aixx-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -0
- package/index.js +329 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# @ AIXX MCP Server
|
|
2
|
+
|
|
3
|
+
> **Google for AI — One line. Every AI model.**
|
|
4
|
+
> A zero-dependency MCP server that lets any MCP-compatible client (WorkBuddy, Claude Desktop, Cursor, etc.) call **dozens of LLMs + image/video generation** through a single AIXX key.
|
|
5
|
+
|
|
6
|
+
## What it does
|
|
7
|
+
|
|
8
|
+
- 🔑 **One key, every model** — Claude, GPT, Gemini, DeepSeek, Qwen, GLM, Moonshot, MiniMax and more (38+ text models, live list).
|
|
9
|
+
- 🖼️ **Image generation** — GPT-Image-2, Nano Banana Pro, Seedream, Midjourney, ...
|
|
10
|
+
- 🎬 **Video generation** — MiniMax H3, Veo 3.1, Kling, Seedance, ... (async + task polling).
|
|
11
|
+
- 🔌 **OpenAI-compatible** — talks to `https://baodan.run/v1`.
|
|
12
|
+
- 🪶 **Zero dependencies** — single file, Node 18+ only.
|
|
13
|
+
|
|
14
|
+
## Get a key
|
|
15
|
+
|
|
16
|
+
Register at **https://baodan.run/console/** — new accounts get **¥5 free credit**. After login, generate your `sk-` key on the **令牌 (Tokens)** page.
|
|
17
|
+
|
|
18
|
+
Your key looks like `sk-` + 48 hex chars.
|
|
19
|
+
|
|
20
|
+
## Configure
|
|
21
|
+
|
|
22
|
+
Set your key via the `AIXX_API_KEY` environment variable (recommended), or pass `apiKey` per call.
|
|
23
|
+
|
|
24
|
+
### WorkBuddy
|
|
25
|
+
|
|
26
|
+
Add to `~/.workbuddy/mcp.json`:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"mcpServers": {
|
|
31
|
+
"aixx": {
|
|
32
|
+
"command": "npx",
|
|
33
|
+
"args": ["-y", "aixx-mcp"],
|
|
34
|
+
"env": {
|
|
35
|
+
"AIXX_API_KEY": "sk-your-key-here"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Claude Desktop / Cursor
|
|
43
|
+
|
|
44
|
+
Same block under `mcpServers` in your client's MCP config.
|
|
45
|
+
|
|
46
|
+
## Tools
|
|
47
|
+
|
|
48
|
+
| Tool | Description |
|
|
49
|
+
|------|-------------|
|
|
50
|
+
| `aixx_list_models` | List live text models (cached 5 min). |
|
|
51
|
+
| `aixx_chat` | Chat completion. Supports streaming internally, returns full text. |
|
|
52
|
+
| `aixx_image` | Generate an image (sync ≤90s, then falls back to task). |
|
|
53
|
+
| `aixx_video` | Submit a video generation task (async). |
|
|
54
|
+
| `aixx_task` | Poll an image/video task for status/result URL. |
|
|
55
|
+
|
|
56
|
+
### Tip: reasoning models
|
|
57
|
+
|
|
58
|
+
Models like `deepseek-v4-pro` spend tokens on reasoning. Give `max_tokens` enough headroom (≥500) or the visible answer may be empty.
|
|
59
|
+
|
|
60
|
+
## Billing
|
|
61
|
+
|
|
62
|
+
- Text: token-based credit.
|
|
63
|
+
- Images: from ¥0.06/image.
|
|
64
|
+
- Video: per-second (e.g. MiniMax 480p ¥0.048/s); rate limit 5 req/min/key.
|
|
65
|
+
- `402` means insufficient credit — top up at https://baodan.run/console/topup.
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
MIT
|
package/index.js
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* AIXX MCP Server (zero-dependency, stdio)
|
|
4
|
+
* Base: https://baodan.run/v1 (OpenAI-compatible)
|
|
5
|
+
*
|
|
6
|
+
* Tools:
|
|
7
|
+
* aixx_list_models - 列出在架文本模型(实时拉 /v1/models,带缓存)
|
|
8
|
+
* aixx_chat - 对话补全(POST /v1/chat/completions)
|
|
9
|
+
* aixx_image - 出图(POST /v1/media/image,AIXX扩展)
|
|
10
|
+
* aixx_video - 出视频(POST /v1/media/video,AIXX扩展,异步)
|
|
11
|
+
* aixx_task - 轮询媒体任务(GET /v1/media/task/{id})
|
|
12
|
+
*
|
|
13
|
+
* 鉴权: 优先用工具参数 apiKey,其次环境变量 AIXX_API_KEY。
|
|
14
|
+
* Key 格式: sk- + 48位hex。
|
|
15
|
+
*/
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
const BASE_URL = process.env.AIXX_BASE_URL || 'https://baodan.run/v1';
|
|
19
|
+
const ENV_KEY = process.env.AIXX_API_KEY || '';
|
|
20
|
+
|
|
21
|
+
let modelCache = null;
|
|
22
|
+
let modelCacheAt = 0;
|
|
23
|
+
const MODEL_TTL_MS = 5 * 60 * 1000;
|
|
24
|
+
|
|
25
|
+
// ---------- stdio JSON-RPC (NDJSON) ----------
|
|
26
|
+
let buf = '';
|
|
27
|
+
process.stdin.setEncoding('utf8');
|
|
28
|
+
process.stdin.on('data', (chunk) => {
|
|
29
|
+
buf += chunk;
|
|
30
|
+
let idx;
|
|
31
|
+
while ((idx = buf.indexOf('\n')) >= 0) {
|
|
32
|
+
const line = buf.slice(0, idx).trim();
|
|
33
|
+
buf = buf.slice(idx + 1);
|
|
34
|
+
if (line) {
|
|
35
|
+
try { handle(JSON.parse(line)); } catch (e) { /* ignore malformed */ }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
function send(obj) {
|
|
41
|
+
process.stdout.write(JSON.stringify(obj) + '\n');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function reply(id, result) {
|
|
45
|
+
send({ jsonrpc: '2.0', id, result });
|
|
46
|
+
}
|
|
47
|
+
function replyError(id, code, message, data) {
|
|
48
|
+
send({ jsonrpc: '2.0', id, error: { code, message, data } });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ---------- tool definitions ----------
|
|
52
|
+
const TOOLS = [
|
|
53
|
+
{
|
|
54
|
+
name: 'aixx_list_models',
|
|
55
|
+
description: '列出 AIXX 当前在架的文本大模型(实时从 /v1/models 拉取,5分钟缓存)。返回模型 id、厂牌、支持的端点类型。图像/视频模型为固定清单,见各自工具说明。',
|
|
56
|
+
inputSchema: {
|
|
57
|
+
type: 'object',
|
|
58
|
+
properties: {
|
|
59
|
+
apiKey: { type: 'string', description: 'AIXX API Key (sk-开头)。不传则用环境变量 AIXX_API_KEY。' },
|
|
60
|
+
force_refresh: { type: 'boolean', description: 'true 时跳过缓存强制重新拉取。', default: false }
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'aixx_chat',
|
|
66
|
+
description: '调用 AIXX 对话补全(OpenAI 兼容)。支持全部在架文本模型(Claude/GPT/Gemini/DeepSeek/Qwen/GLM 等),支持 SSE 流式但本工具返回完整文本。注意:推理模型(如 deepseek-v4-pro)会消耗 token 用于思考,max_tokens 要给足。',
|
|
67
|
+
inputSchema: {
|
|
68
|
+
type: 'object',
|
|
69
|
+
required: ['messages'],
|
|
70
|
+
properties: {
|
|
71
|
+
model: { type: 'string', description: '模型 id,如 claude-sonnet-4-6、deepseek-v4-pro、gpt-5.5。用 aixx_list_models 查在架列表。' },
|
|
72
|
+
messages: {
|
|
73
|
+
type: 'array',
|
|
74
|
+
description: '对话消息数组,每条 {role: user|assistant|system, content: string}',
|
|
75
|
+
items: {
|
|
76
|
+
type: 'object',
|
|
77
|
+
required: ['role', 'content'],
|
|
78
|
+
properties: {
|
|
79
|
+
role: { type: 'string' },
|
|
80
|
+
content: { type: 'string' }
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
max_tokens: { type: 'integer', description: '最大生成 token 数。推理模型建议 >=500。', default: 1024 },
|
|
85
|
+
temperature: { type: 'number', description: '采样温度 0-2。' },
|
|
86
|
+
apiKey: { type: 'string', description: 'AIXX API Key,不传则用环境变量。' }
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'aixx_image',
|
|
92
|
+
description: 'AIXX 出图(扩展端点 /v1/media/image)。模型: gpt-image-2(-lite)、nano-banana-pro、seedream、midjourney 等;不传 model 自动挑最便宜可用。同步等 <=90s 直接出图,超时返回 task_id 可用 aixx_task 轮询。',
|
|
93
|
+
inputSchema: {
|
|
94
|
+
type: 'object',
|
|
95
|
+
required: ['prompt'],
|
|
96
|
+
properties: {
|
|
97
|
+
prompt: { type: 'string', description: '图像描述。' },
|
|
98
|
+
model: { type: 'string', description: '出图模型 id,可省略=自动选最便宜。' },
|
|
99
|
+
size: { type: 'string', description: '比例字符串: 9:16 / 1:1 / 16:9 等,不是像素。', default: '1:1' },
|
|
100
|
+
apiKey: { type: 'string' }
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'aixx_video',
|
|
106
|
+
description: 'AIXX 出视频(扩展端点 /v1/media/video,异步)。模型: minimax-h3、veo-3.1、kling、seedance 等。提交后立即返回 task_id,用 aixx_task 轮询 status/progress/result_url。失败自动退款。限速 5次/分钟/Key。',
|
|
107
|
+
inputSchema: {
|
|
108
|
+
type: 'object',
|
|
109
|
+
required: ['prompt'],
|
|
110
|
+
properties: {
|
|
111
|
+
prompt: { type: 'string', description: '视频描述。' },
|
|
112
|
+
model: { type: 'string', description: '视频模型 id,如 minimax-h3。', default: 'minimax-h3' },
|
|
113
|
+
duration: { type: 'integer', description: '时长 5-15 秒。', default: 5, minimum: 5, maximum: 15 },
|
|
114
|
+
resolution: { type: 'string', description: '480p 或 720p。', default: '480p', enum: ['480p', '720p'] },
|
|
115
|
+
apiKey: { type: 'string' }
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: 'aixx_task',
|
|
121
|
+
description: '轮询 AIXX 媒体任务(GET /v1/media/task/{task_id})。返回 status / progress / result_url。用于出图(超时时)和出视频。',
|
|
122
|
+
inputSchema: {
|
|
123
|
+
type: 'object',
|
|
124
|
+
required: ['task_id'],
|
|
125
|
+
properties: {
|
|
126
|
+
task_id: { type: 'string', description: 'aixx_image/aixx_video 返回的 task_id。' },
|
|
127
|
+
apiKey: { type: 'string' }
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
// ---------- handler ----------
|
|
134
|
+
async function handle(msg) {
|
|
135
|
+
const { id, method, params } = msg;
|
|
136
|
+
try {
|
|
137
|
+
if (method === 'initialize') {
|
|
138
|
+
return reply(id, {
|
|
139
|
+
protocolVersion: '2024-11-05',
|
|
140
|
+
capabilities: { tools: {} },
|
|
141
|
+
serverInfo: { name: 'aixx-mcp', version: '1.0.0' }
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (method === 'notifications/initialized') return; // no response
|
|
145
|
+
if (method === 'ping') return reply(id, {});
|
|
146
|
+
if (method === 'tools/list') return reply(id, { tools: TOOLS });
|
|
147
|
+
if (method === 'tools/call') return await callTool(id, params);
|
|
148
|
+
return replyError(id, -32601, `Method not found: ${method}`);
|
|
149
|
+
} catch (e) {
|
|
150
|
+
return replyError(id, -32603, e && e.message ? e.message : String(e));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async function callTool(id, params) {
|
|
155
|
+
const name = params && params.name;
|
|
156
|
+
const args = (params && params.arguments) || {};
|
|
157
|
+
const key = args.apiKey || ENV_KEY;
|
|
158
|
+
if (!key) {
|
|
159
|
+
return toolResult(id, '缺少 AIXX API Key。请在连接器环境变量设置 AIXX_API_KEY,或在调用时传 apiKey 参数。注册并领取 Key: https://baodan.run/console/ (新用户送 ¥5,登录后在「令牌」页生成 sk- key)。', true);
|
|
160
|
+
}
|
|
161
|
+
if (!/^sk-[0-9a-fA-F]{48}$/.test(key)) {
|
|
162
|
+
return toolResult(id, 'API Key 格式不对:应为 sk- + 48位纯hex(不要含连字符等符号)。', true);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
if (name === 'aixx_list_models') return await listModels(id, key, !!args.force_refresh);
|
|
167
|
+
if (name === 'aixx_chat') return await chat(id, key, args);
|
|
168
|
+
if (name === 'aixx_image') return await image(id, key, args);
|
|
169
|
+
if (name === 'aixx_video') return await video(id, key, args);
|
|
170
|
+
if (name === 'aixx_task') return await task(id, key, args);
|
|
171
|
+
return toolResult(id, `未知工具: ${name}`, true);
|
|
172
|
+
} catch (e) {
|
|
173
|
+
return toolResult(id, `调用 AIXX 失败: ${e.message}`, true);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ---------- API wrappers ----------
|
|
178
|
+
async function httpJson(url, opts, timeoutMs = 90000) {
|
|
179
|
+
const ctrl = new AbortController();
|
|
180
|
+
const t = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
181
|
+
try {
|
|
182
|
+
const res = await fetch(url, { ...opts, signal: ctrl.signal });
|
|
183
|
+
const text = await res.text();
|
|
184
|
+
let json;
|
|
185
|
+
try { json = JSON.parse(text); } catch { json = { raw: text }; }
|
|
186
|
+
if (!res.ok) {
|
|
187
|
+
const msg = (json && json.error && json.error.message) || text || `HTTP ${res.status}`;
|
|
188
|
+
const err = new Error(`[${res.status}] ${msg}`);
|
|
189
|
+
err.status = res.status; err.body = json;
|
|
190
|
+
throw err;
|
|
191
|
+
}
|
|
192
|
+
return json;
|
|
193
|
+
} finally {
|
|
194
|
+
clearTimeout(t);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function authHeaders(key, extra) {
|
|
199
|
+
return { 'Authorization': `Bearer ${key}`, 'Content-Type': 'application/json', ...(extra || {}) };
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async function listModels(id, key, force) {
|
|
203
|
+
if (!force && modelCache && Date.now() - modelCacheAt < MODEL_TTL_MS) {
|
|
204
|
+
return toolResult(id, `(缓存) AIXX 在架文本模型共 ${modelCache.length} 个:\n` + formatModels(modelCache));
|
|
205
|
+
}
|
|
206
|
+
const json = await httpJson(`${BASE_URL}/models`, { headers: authHeaders(key) }, 30000);
|
|
207
|
+
const data = json.data || [];
|
|
208
|
+
modelCache = data; modelCacheAt = Date.now();
|
|
209
|
+
return toolResult(id, `AIXX 在架文本模型共 ${data.length} 个:\n` + formatModels(data));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function formatModels(data) {
|
|
213
|
+
const byVendor = {};
|
|
214
|
+
for (const m of data) {
|
|
215
|
+
const v = m.owned_by || 'unknown';
|
|
216
|
+
(byVendor[v] = byVendor[v] || []).push(m.id);
|
|
217
|
+
}
|
|
218
|
+
const lines = [];
|
|
219
|
+
for (const [v, ids] of Object.entries(byVendor)) {
|
|
220
|
+
lines.push(`[${v}] (${ids.length})`);
|
|
221
|
+
for (const x of ids) lines.push(` - ${x}`);
|
|
222
|
+
}
|
|
223
|
+
return lines.join('\n');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async function chat(id, key, args) {
|
|
227
|
+
if (!Array.isArray(args.messages) || !args.messages.length) {
|
|
228
|
+
return toolResult(id, 'messages 不能为空。', true);
|
|
229
|
+
}
|
|
230
|
+
const body = {
|
|
231
|
+
model: args.model || 'claude-haiku-4-5',
|
|
232
|
+
messages: args.messages,
|
|
233
|
+
max_tokens: args.max_tokens || 1024
|
|
234
|
+
};
|
|
235
|
+
if (typeof args.temperature === 'number') body.temperature = args.temperature;
|
|
236
|
+
|
|
237
|
+
const json = await httpJson(`${BASE_URL}/chat/completions`, {
|
|
238
|
+
method: 'POST',
|
|
239
|
+
headers: authHeaders(key),
|
|
240
|
+
body: JSON.stringify(body)
|
|
241
|
+
}, 180000);
|
|
242
|
+
|
|
243
|
+
const choice = (json.choices && json.choices[0]) || {};
|
|
244
|
+
const content = (choice.message && choice.message.content) || '';
|
|
245
|
+
const reasoning = (choice.message && choice.message.reasoning_content) || '';
|
|
246
|
+
const usage = json.usage || {};
|
|
247
|
+
|
|
248
|
+
let out = '';
|
|
249
|
+
if (content) out += content;
|
|
250
|
+
if (reasoning) out += (out ? '\n\n' : '') + `[思考过程]\n${reasoning}`;
|
|
251
|
+
if (!out) {
|
|
252
|
+
out = '(模型未返回正文内容。如果用的是推理模型如 deepseek-v4-pro,可能 max_tokens 被思考占满,请调大 max_tokens 后重试。)';
|
|
253
|
+
}
|
|
254
|
+
out += `\n\n— 模型: ${json.model || body.model} | tokens: ${usage.total_tokens != null ? usage.total_tokens : 'n/a'}(prompt ${usage.prompt_tokens != null ? usage.prompt_tokens : '?'}/completion ${usage.completion_tokens != null ? usage.completion_tokens : '?'})`;
|
|
255
|
+
return toolResult(id, out, !content && !!reasoning);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async function image(id, key, args) {
|
|
259
|
+
const body = {
|
|
260
|
+
user_compute_key: key,
|
|
261
|
+
prompt: args.prompt,
|
|
262
|
+
size: args.size || '1:1'
|
|
263
|
+
};
|
|
264
|
+
if (args.model) body.model = args.model;
|
|
265
|
+
|
|
266
|
+
const json = await httpJson(`${BASE_URL}/media/image`, {
|
|
267
|
+
method: 'POST',
|
|
268
|
+
headers: authHeaders(key),
|
|
269
|
+
body: JSON.stringify(body)
|
|
270
|
+
}, 95000);
|
|
271
|
+
|
|
272
|
+
if (json.task_id) {
|
|
273
|
+
return toolResult(id, `出图超过 90s,已转为后台任务。\ntask_id: ${json.task_id}\n请用 aixx_task 轮询结果。`);
|
|
274
|
+
}
|
|
275
|
+
const urls = [];
|
|
276
|
+
if (Array.isArray(json.data)) for (const d of json.data) if (d.url) urls.push(d.url);
|
|
277
|
+
if (json.url) urls.push(json.url);
|
|
278
|
+
if (json.result_url) urls.push(json.result_url);
|
|
279
|
+
if (urls.length) {
|
|
280
|
+
return toolResult(id, `出图完成(${body.model || '自动选模'} / ${body.size}):\n` + urls.join('\n'));
|
|
281
|
+
}
|
|
282
|
+
return toolResult(id, '出图返回:\n' + JSON.stringify(json, null, 2));
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async function video(id, key, args) {
|
|
286
|
+
const body = {
|
|
287
|
+
user_compute_key: key,
|
|
288
|
+
prompt: args.prompt,
|
|
289
|
+
model: args.model || 'minimax-h3',
|
|
290
|
+
duration: args.duration || 5,
|
|
291
|
+
resolution: args.resolution || '480p'
|
|
292
|
+
};
|
|
293
|
+
const json = await httpJson(`${BASE_URL}/media/video`, {
|
|
294
|
+
method: 'POST',
|
|
295
|
+
headers: authHeaders(key),
|
|
296
|
+
body: JSON.stringify(body)
|
|
297
|
+
}, 60000);
|
|
298
|
+
const tid = json.task_id || json.id;
|
|
299
|
+
if (!tid) return toolResult(id, '视频提交返回:\n' + JSON.stringify(json, null, 2));
|
|
300
|
+
return toolResult(id, `视频任务已提交(${body.model} / ${body.duration}s / ${body.resolution})。\ntask_id: ${tid}\n状态: ${json.status || 'submitted'}\n用 aixx_task 轮询进度,失败自动退款。限速 5次/分钟/Key。`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
async function task(id, key, args) {
|
|
304
|
+
const json = await httpJson(
|
|
305
|
+
`${BASE_URL}/media/task/${encodeURIComponent(args.task_id)}?user_compute_key=${encodeURIComponent(key)}`,
|
|
306
|
+
{ headers: authHeaders(key) },
|
|
307
|
+
30000
|
|
308
|
+
);
|
|
309
|
+
const lines = [
|
|
310
|
+
`task_id: ${args.task_id}`,
|
|
311
|
+
`status: ${json.status ?? 'unknown'}`,
|
|
312
|
+
];
|
|
313
|
+
if (json.progress != null) lines.push(`progress: ${json.progress}`);
|
|
314
|
+
if (json.result_url) lines.push(`result_url: ${json.result_url}`);
|
|
315
|
+
if (json.url) lines.push(`url: ${json.url}`);
|
|
316
|
+
if (json.error) lines.push(`error: ${json.error}`);
|
|
317
|
+
if (!json.result_url && !json.url && !json.error) {
|
|
318
|
+
lines.push('raw: ' + JSON.stringify(json));
|
|
319
|
+
}
|
|
320
|
+
return toolResult(id, lines.join('\n'));
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// ---------- MCP result helper ----------
|
|
324
|
+
function toolResult(id, text, isError) {
|
|
325
|
+
reply(id, {
|
|
326
|
+
content: [{ type: 'text', text: String(text) }],
|
|
327
|
+
isError: !!isError
|
|
328
|
+
});
|
|
329
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "aixx-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "AIXX MCP server — one key to every AI model. Call Claude/GPT/Gemini/DeepSeek + image/video generation from any MCP-compatible client. OpenAI-compatible.",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"aixx-mcp": "index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"index.js",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"aixx",
|
|
16
|
+
"mcp",
|
|
17
|
+
"model-context-protocol",
|
|
18
|
+
"openai-compatible",
|
|
19
|
+
"llm",
|
|
20
|
+
"ai",
|
|
21
|
+
"image-generation",
|
|
22
|
+
"video-generation",
|
|
23
|
+
"claude",
|
|
24
|
+
"gpt",
|
|
25
|
+
"gemini",
|
|
26
|
+
"deepseek"
|
|
27
|
+
],
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=18"
|
|
30
|
+
},
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"author": {
|
|
33
|
+
"name": "AIXX",
|
|
34
|
+
"url": "https://baodan.run/aixx/"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://baodan.run/aixx/",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://gitee.com/kk0803/token-hub.git"
|
|
40
|
+
}
|
|
41
|
+
}
|