mcp-multi-bridge 2.3.1 → 2.4.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 +82 -0
- package/bin.js +68 -1
- package/lib/higress.js +32 -1
- package/lib/preset.js +125 -0
- package/package.json +34 -34
package/README.md
CHANGED
|
@@ -42,6 +42,40 @@ npm i -g mcp-multi-bridge mcp-multi-login
|
|
|
42
42
|
>
|
|
43
43
|
> 配置目录与 `config.json` 结构不变,无需重新登录。
|
|
44
44
|
|
|
45
|
+
### 首次使用:配好 mcp.json 即可,不用先跑命令
|
|
46
|
+
|
|
47
|
+
配置不存在时,bridge 启动会按预设自动生成,无需先手动执行登录命令:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
"ebs-plus": {
|
|
51
|
+
"command": "mcp-multi-bridge",
|
|
52
|
+
"args": ["--name", "ebs-plus"]
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
启动后按以下顺序找预设:
|
|
57
|
+
|
|
58
|
+
| 顺序 | 来源 | 说明 |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| 1 | `--preset <名>` | 显式指定,优先级最高 |
|
|
61
|
+
| 2 | `--name <名>` 同名匹配 | `--name ebs-plus` → `presets/ebs-plus.json` |
|
|
62
|
+
| 3 | 都没有 | 不生成,按原行为提示运行登录命令 |
|
|
63
|
+
|
|
64
|
+
预设文件来自 `mcp-multi-login` 包(`presets/`),所以**两个包都要安装**。
|
|
65
|
+
预设不在默认位置时用 `MCP_BRIDGE_PRESETS=<目录>` 指定。
|
|
66
|
+
|
|
67
|
+
三条边界:
|
|
68
|
+
|
|
69
|
+
- **已存在的 `config.json` 一律不覆盖**,手改过的内容不会被冲掉
|
|
70
|
+
- 只生成配置,不写 token——首次调用业务工具时仍需登录一次
|
|
71
|
+
- 生成过程只在 stderr 打印一行,不会污染 stdout 的 JSON-RPC 通道
|
|
72
|
+
|
|
73
|
+
用 `MCP_MULTI_HOME` 指定目录时 `--name` 为空,此时只能靠 `--preset` 指定:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
MCP_MULTI_HOME=~/.my-mcp mcp-multi-bridge --preset ebs-plus
|
|
77
|
+
```
|
|
78
|
+
|
|
45
79
|
## 多后端与工具列表
|
|
46
80
|
|
|
47
81
|
`config.json` 里的每个组织都带一个 `path`,指向它在 Higress 上的 MCP 路由。
|
|
@@ -300,6 +334,54 @@ bridge 侧**不维护任何业务词对照表**。
|
|
|
300
334
|
两种做法的取舍:拆 server 简单但要维护多套配置和凭证;分层只维护一套,
|
|
301
335
|
代价是每次找工具多一跳。系统数量不多时,拆 server 更省事。
|
|
302
336
|
|
|
337
|
+
### 网关侧认证(key-auth)
|
|
338
|
+
|
|
339
|
+
桥接默认只发 `Content-Type`,不带任何认证头——业务登录 token 是作为**工具参数**
|
|
340
|
+
传给后端的,不参与网关认证。所以当网关对某个端点开了 Key 认证时,
|
|
341
|
+
必须让桥接额外带一个头,否则该端点会直接 401(表现为只剩本地的 `login` 工具)。
|
|
342
|
+
|
|
343
|
+
三个来源,后者覆盖前者:
|
|
344
|
+
|
|
345
|
+
| 来源 | 作用范围 | 适合 |
|
|
346
|
+
| --- | --- | --- |
|
|
347
|
+
| `MCP_BRIDGE_HEADERS`(环境变量,JSON) | 本实例所有组织 | 一套凭证走全部环境 |
|
|
348
|
+
| `config.json` 顶层 `headers` | 本实例所有组织 | 同上,但想写进配置文件 |
|
|
349
|
+
| `orgs[].headers` | 单个组织 | 每个环境用不同凭证 |
|
|
350
|
+
|
|
351
|
+
最省事的是写在客户端条目的 `env` 里:
|
|
352
|
+
|
|
353
|
+
```json
|
|
354
|
+
{
|
|
355
|
+
"mcpServers": {
|
|
356
|
+
"mes": {
|
|
357
|
+
"command": "mcp-multi-bridge",
|
|
358
|
+
"args": ["--name", "mes"],
|
|
359
|
+
"env": {
|
|
360
|
+
"MCP_BRIDGE_HEADERS": "{\"Authorization\":\"Bearer <网关消费者凭证>\"}"
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
要给不同环境配不同消费者,就写进 `config.json` 的组织里(优先级更高):
|
|
368
|
+
|
|
369
|
+
```json
|
|
370
|
+
{
|
|
371
|
+
"orgs": [
|
|
372
|
+
{ "key": "test", "path": "/mcp-servers/mes-mcp-server" },
|
|
373
|
+
{ "key": "prod", "path": "/mcp-servers/tc-mes-mcp-server",
|
|
374
|
+
"headers": { "Authorization": "Bearer <prod 的凭证>" } }
|
|
375
|
+
]
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
三个来源都没配时,请求头与旧版完全一致,不影响未开认证的网关。
|
|
380
|
+
|
|
381
|
+
> 凭证是明文,别提交进仓库;`MCP_BRIDGE_HEADERS` 不是合法 JSON 时会被忽略并打一行提示,
|
|
382
|
+
> 不会让进程退出——但那个端点会因此 401,排查时先看这条提示。
|
|
383
|
+
|
|
384
|
+
|
|
303
385
|
## 检查安装的版本
|
|
304
386
|
|
|
305
387
|
```bash
|
package/bin.js
CHANGED
|
@@ -55,6 +55,7 @@ import { getOrgAuth, getCurrentOrgKey, listLoggedInOrgs } from './lib/token.js';
|
|
|
55
55
|
import { rpc, extractPayload } from './lib/higress.js';
|
|
56
56
|
import { settings, DEFAULT_SETTINGS } from './lib/settings.js';
|
|
57
57
|
import { buildIndex, searchTools, summarize } from './lib/toolindex.js';
|
|
58
|
+
import { ensureConfig, listPresets, resolvePresetsDir } from './lib/preset.js';
|
|
58
59
|
|
|
59
60
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
60
61
|
const require = createRequire(import.meta.url);
|
|
@@ -163,6 +164,59 @@ function pathAllowed(p, allow) {
|
|
|
163
164
|
});
|
|
164
165
|
}
|
|
165
166
|
|
|
167
|
+
/**
|
|
168
|
+
* 取 --flag 后面的值;没有该参数时返回空字符串
|
|
169
|
+
*/
|
|
170
|
+
function argOf(argv, flag) {
|
|
171
|
+
const i = argv.indexOf(flag);
|
|
172
|
+
return i >= 0 ? String(argv[i + 1] || '').trim() : '';
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* 首次启动时按预设生成 config.json
|
|
177
|
+
*
|
|
178
|
+
* 只写 stderr:stdout 是 JSON-RPC 通道,写一个字都会破坏 MCP 握手。
|
|
179
|
+
* 任何失败都只提示、不退出——服务还能以「仅 login 工具」的形态起来,
|
|
180
|
+
* 比直接崩掉更容易让用户看到原因。
|
|
181
|
+
*/
|
|
182
|
+
function tryInitFromPreset(argv) {
|
|
183
|
+
if (!CONFIG_FILE) return;
|
|
184
|
+
|
|
185
|
+
const preset = argOf(argv, '--preset');
|
|
186
|
+
let r;
|
|
187
|
+
try {
|
|
188
|
+
r = ensureConfig({ configFile: CONFIG_FILE, name: CONFIG_NAME, preset });
|
|
189
|
+
} catch (e) {
|
|
190
|
+
console.error(`[bridge] 自动初始化配置失败(不影响启动):${e.message}`);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (r.created) {
|
|
195
|
+
console.error(`[bridge] 已按预设「${r.preset}」初始化配置: ${r.file}`);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (r.reason === 'exists' || r.reason === 'no_name') return;
|
|
199
|
+
|
|
200
|
+
if (r.reason === 'presets_dir_missing') {
|
|
201
|
+
console.error(
|
|
202
|
+
`[bridge] 未找到预设目录 ${resolvePresetsDir()}\n` +
|
|
203
|
+
' 自动初始化需要 mcp-multi-login 包提供的预设:npm i -g mcp-multi-login'
|
|
204
|
+
);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (r.reason === 'preset_not_found') {
|
|
208
|
+
const avail = listPresets(resolvePresetsDir());
|
|
209
|
+
console.error(
|
|
210
|
+
`[bridge] 预设「${preset || CONFIG_NAME}」不存在,可用:${avail.join('、') || '(无)'}\n` +
|
|
211
|
+
` 也可以手动创建 ${CONFIG_FILE}`
|
|
212
|
+
);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (r.reason === 'invalid_preset') {
|
|
216
|
+
console.error(`[bridge] 预设「${preset || CONFIG_NAME}」内容不合法(缺 baseUrl 或 orgs),已跳过`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
166
220
|
/**
|
|
167
221
|
* 处理 --version / --help / --status
|
|
168
222
|
*
|
|
@@ -239,6 +293,13 @@ async function handleCli(argv) {
|
|
|
239
293
|
以前没配时会静默用 ~/.mes-mcp-login,导致新系统忘配就读到 MES 的数据。
|
|
240
294
|
现在没配直接报错,不再猜。
|
|
241
295
|
|
|
296
|
+
首次配置(自动生成):
|
|
297
|
+
配置不存在时,启动会按预设复制一份,无需先手动运行登录命令:
|
|
298
|
+
--name ebs-plus 套用 mcp-multi-login 包里的 presets/ebs-plus.json
|
|
299
|
+
--preset <名> 显式指定预设,优先于 --name 同名匹配
|
|
300
|
+
MCP_BRIDGE_PRESETS=<目录> 预设目录不在 login 包默认位置时指定
|
|
301
|
+
已存在的 config.json 一律不覆盖;生成后仍需登录一次才有业务凭据。
|
|
302
|
+
|
|
242
303
|
当前配置目录: ${CONFIG_DIR || '(未配置)'}
|
|
243
304
|
配置文件: ${CONFIG_FILE || '(未配置)'}
|
|
244
305
|
登录文件: ${CONFIG_DIR ? CONFIG_DIR + '/token.json' : '(未配置)'}(由 ${L.loginCommand} 写入)
|
|
@@ -301,7 +362,9 @@ async function handleCli(argv) {
|
|
|
301
362
|
return false;
|
|
302
363
|
}
|
|
303
364
|
|
|
304
|
-
|
|
365
|
+
const ARGV = process.argv.slice(2);
|
|
366
|
+
|
|
367
|
+
if (await handleCli(ARGV)) {
|
|
305
368
|
process.exit(0);
|
|
306
369
|
}
|
|
307
370
|
|
|
@@ -313,6 +376,10 @@ if (!CONFIG_DIR) {
|
|
|
313
376
|
process.exit(1);
|
|
314
377
|
}
|
|
315
378
|
|
|
379
|
+
// 配置不存在时按预设生成,省掉「必须先手动跑一次登录命令」这一步。
|
|
380
|
+
// 放在 handleCli 之后:--help / --version 不该有写文件的副作用。
|
|
381
|
+
tryInitFromPreset(ARGV);
|
|
382
|
+
|
|
316
383
|
function textResult(text, isError = false) {
|
|
317
384
|
return {
|
|
318
385
|
content: [{ type: 'text', text }],
|
package/lib/higress.js
CHANGED
|
@@ -12,13 +12,44 @@ import { orgUrl } from './config.js';
|
|
|
12
12
|
// 自增 id,避免同毫秒并发撞号
|
|
13
13
|
let rpcSeq = 0;
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* 附加到网关请求上的头
|
|
17
|
+
*
|
|
18
|
+
* 用于网关侧的消费者认证(如 key-auth 的 Authorization)。三个来源按优先级合并,
|
|
19
|
+
* 后者覆盖前者:
|
|
20
|
+
* 1. 环境变量 MCP_BRIDGE_HEADERS —— 客户端 mcp.json 的 env 里配,JSON 字符串
|
|
21
|
+
* 2. config.json 顶层 headers —— 对本实例所有组织生效
|
|
22
|
+
* 3. orgs[].headers —— 只对该组织生效,用于不同环境不同凭证
|
|
23
|
+
*
|
|
24
|
+
* 都没配时返回空对象,请求头与旧版完全一致(不改变既有行为)。
|
|
25
|
+
* 为什么不放在工具参数里:网关的 key-auth 只认请求头,参数是给后端业务用的。
|
|
26
|
+
*/
|
|
27
|
+
export function bridgeHeaders(cfg, org) {
|
|
28
|
+
let fromEnv = {};
|
|
29
|
+
const raw = process.env.MCP_BRIDGE_HEADERS;
|
|
30
|
+
if (raw) {
|
|
31
|
+
try {
|
|
32
|
+
const v = JSON.parse(raw);
|
|
33
|
+
if (v && typeof v === 'object' && !Array.isArray(v)) fromEnv = v;
|
|
34
|
+
else console.error('[bridge] MCP_BRIDGE_HEADERS 必须是 JSON 对象,已忽略');
|
|
35
|
+
} catch (e) {
|
|
36
|
+
console.error('[bridge] MCP_BRIDGE_HEADERS 不是合法 JSON,已忽略');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
...fromEnv,
|
|
41
|
+
...((cfg && cfg.headers) || {}),
|
|
42
|
+
...((org && org.headers) || {})
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
15
46
|
/**
|
|
16
47
|
* 发一个 JSON-RPC 请求到网关
|
|
17
48
|
*/
|
|
18
49
|
export async function rpc(cfg, org, method, params) {
|
|
19
50
|
const res = await fetch(orgUrl(cfg, org), {
|
|
20
51
|
method: 'POST',
|
|
21
|
-
headers: { 'Content-Type': 'application/json' },
|
|
52
|
+
headers: { 'Content-Type': 'application/json', ...bridgeHeaders(cfg, org) },
|
|
22
53
|
body: JSON.stringify({ jsonrpc: '2.0', id: ++rpcSeq, method, params })
|
|
23
54
|
});
|
|
24
55
|
const text = await res.text();
|
package/lib/preset.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* preset.js —— 首次启动时按预设生成 config.json
|
|
3
|
+
*
|
|
4
|
+
* 背景:config.json 的唯一所有者是 `mcp-multi-login`(presets/ 在它那边),
|
|
5
|
+
* bridge 只读不写。于是「先配 mcp.json、客户端拉起 bridge」这条路径上没人写配置,
|
|
6
|
+
* 第一次连上只能退化成一个只有 login 工具的服务,用户必须先手动跑一次登录命令。
|
|
7
|
+
*
|
|
8
|
+
* 本模块把这一步收进 bridge:启动时若配置不存在,按预设复制一份。
|
|
9
|
+
*
|
|
10
|
+
* 四条约束:
|
|
11
|
+
* 1. 只在 config.json **不存在**时写,已存在一律不动(不覆盖用户改过的内容)
|
|
12
|
+
* 2. 不猜目录:仍要求显式 --name 或 MCP_MULTI_HOME(静默默认目录曾导致登错环境)
|
|
13
|
+
* 3. preset 文件仍由 login 包提供,本包不复制一份,避免两边漂移
|
|
14
|
+
* 4. 任何失败都不抛出,只返回 reason —— 初始化失败不该让服务起不来
|
|
15
|
+
*/
|
|
16
|
+
import fs from 'node:fs';
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
import { fileURLToPath } from 'node:url';
|
|
19
|
+
|
|
20
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
21
|
+
/** 本包位于 <node_modules>/mcp-multi-bridge/lib,往上两层是 node_modules */
|
|
22
|
+
const NODE_MODULES = path.resolve(HERE, '..', '..');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* preset 目录查找顺序
|
|
26
|
+
*
|
|
27
|
+
* 1. 环境变量 MCP_BRIDGE_PRESETS —— 自定义目录,或本机没装 login 包时指过去
|
|
28
|
+
* 2. 同级安装的 mcp-multi-login/presets —— 全局安装时两个包是兄弟目录
|
|
29
|
+
*/
|
|
30
|
+
export function resolvePresetsDir() {
|
|
31
|
+
const env = (process.env.MCP_BRIDGE_PRESETS || '').trim();
|
|
32
|
+
if (env) return env;
|
|
33
|
+
return path.join(NODE_MODULES, 'mcp-multi-login', 'presets');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** 列出可用的预设名,目录不存在时返回空数组 */
|
|
37
|
+
export function listPresets(dir) {
|
|
38
|
+
try {
|
|
39
|
+
return fs
|
|
40
|
+
.readdirSync(dir)
|
|
41
|
+
.filter((f) => f.endsWith('.json'))
|
|
42
|
+
.map((f) => f.replace(/\.json$/, ''))
|
|
43
|
+
.sort();
|
|
44
|
+
} catch (e) {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 读取并校验一个预设
|
|
51
|
+
*
|
|
52
|
+
* @returns {object|null} 结构不合格时返回 null(宁可不生成,也不写一份坏配置)
|
|
53
|
+
*/
|
|
54
|
+
export function readPreset(dir, name) {
|
|
55
|
+
if (!name) return null;
|
|
56
|
+
try {
|
|
57
|
+
const file = path.join(dir, `${name}.json`);
|
|
58
|
+
if (!fs.existsSync(file)) return null;
|
|
59
|
+
const cfg = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
60
|
+
if (!cfg || typeof cfg !== 'object') return null;
|
|
61
|
+
if (!Array.isArray(cfg.orgs) || !cfg.orgs.length) return null;
|
|
62
|
+
// baseUrl 与 orgs[].path 是后续一切请求的基础,缺了等于不能用
|
|
63
|
+
if (typeof cfg.baseUrl !== 'string' || !cfg.baseUrl.trim()) return null;
|
|
64
|
+
if (!cfg.orgs.every((o) => o && typeof o.key === 'string' && o.key && typeof o.path === 'string' && o.path)) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return cfg;
|
|
68
|
+
} catch (e) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 配置不存在时按预设生成
|
|
75
|
+
*
|
|
76
|
+
* @param {object} opts
|
|
77
|
+
* @param {string} opts.configFile 目标文件(CONFIG_FILE)
|
|
78
|
+
* @param {string} [opts.name] --name 传入的系统名;用 MCP_MULTI_HOME 时为空
|
|
79
|
+
* @param {string} [opts.preset] --preset 显式指定,优先级高于 name
|
|
80
|
+
* @param {string} [opts.presetsDir] 覆盖预设目录(测试用)
|
|
81
|
+
* @returns {{created:boolean, file?:string, preset?:string, reason?:string}}
|
|
82
|
+
* reason 取值:exists / no_name / presets_dir_missing / preset_not_found / invalid_preset
|
|
83
|
+
*/
|
|
84
|
+
export function ensureConfig(opts = {}) {
|
|
85
|
+
const { configFile, name, preset, presetsDir } = opts;
|
|
86
|
+
|
|
87
|
+
if (!configFile) return { created: false, reason: 'no_config_file' };
|
|
88
|
+
if (fs.existsSync(configFile)) return { created: false, reason: 'exists' };
|
|
89
|
+
|
|
90
|
+
// --preset 优先;否则用 --name 同名匹配(presets 的文件名就等于系统名)
|
|
91
|
+
const target = (preset || name || '').trim();
|
|
92
|
+
if (!target) return { created: false, reason: 'no_name' };
|
|
93
|
+
|
|
94
|
+
const dir = presetsDir || resolvePresetsDir();
|
|
95
|
+
if (!fs.existsSync(dir)) return { created: false, reason: 'presets_dir_missing' };
|
|
96
|
+
|
|
97
|
+
const cfg = readPreset(dir, target);
|
|
98
|
+
if (!cfg) {
|
|
99
|
+
// 区分「文件没有」和「文件损坏」,两者的排查方向完全不同
|
|
100
|
+
const file = path.join(dir, `${target}.json`);
|
|
101
|
+
return {
|
|
102
|
+
created: false,
|
|
103
|
+
reason: fs.existsSync(file) ? 'invalid_preset' : 'preset_not_found'
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const targetDir = path.dirname(configFile);
|
|
108
|
+
fs.mkdirSync(targetDir, { recursive: true, mode: 0o700 });
|
|
109
|
+
|
|
110
|
+
// 原子写:客户端可能同时拉起多个实例,直接写会让另一个读到半个 JSON
|
|
111
|
+
const tmp = `${configFile}.tmp-${process.pid}`;
|
|
112
|
+
try {
|
|
113
|
+
fs.writeFileSync(tmp, JSON.stringify(cfg, null, 4), { encoding: 'utf8', mode: 0o600 });
|
|
114
|
+
fs.renameSync(tmp, configFile);
|
|
115
|
+
} catch (e) {
|
|
116
|
+
try {
|
|
117
|
+
fs.unlinkSync(tmp);
|
|
118
|
+
} catch (ignored) {
|
|
119
|
+
// 清理临时文件失败不掩盖原始错误
|
|
120
|
+
}
|
|
121
|
+
throw e;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return { created: true, file: configFile, preset: target };
|
|
125
|
+
}
|
package/package.json
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "mcp-multi-bridge",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "多后端 MCP 桥接:把网关后多个后端、多个租户的工具集合并成一个 MCP 服务,凭据由登录 CLI 提供",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"bin": {
|
|
7
|
-
"mcp-multi-bridge": "bin.js"
|
|
8
|
-
},
|
|
9
|
-
"files": [
|
|
10
|
-
"bin.js",
|
|
11
|
-
"lib/",
|
|
12
|
-
"README.md"
|
|
13
|
-
],
|
|
14
|
-
"engines": {
|
|
15
|
-
"node": ">=18"
|
|
16
|
-
},
|
|
17
|
-
"scripts": {
|
|
18
|
-
"start": "node bin.js",
|
|
19
|
-
"pack:check": "npm pack --dry-run",
|
|
20
|
-
"test": "node test/toolindex.test.mjs"
|
|
21
|
-
},
|
|
22
|
-
"keywords": [
|
|
23
|
-
"mcp",
|
|
24
|
-
"model-context-protocol",
|
|
25
|
-
"bridge",
|
|
26
|
-
"multi-tenant",
|
|
27
|
-
"multi-backend",
|
|
28
|
-
"mes"
|
|
29
|
-
],
|
|
30
|
-
"license": "MIT",
|
|
31
|
-
"dependencies": {
|
|
32
|
-
"@modelcontextprotocol/sdk": "^1.20.2"
|
|
33
|
-
}
|
|
34
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "mcp-multi-bridge",
|
|
3
|
+
"version": "2.4.0",
|
|
4
|
+
"description": "多后端 MCP 桥接:把网关后多个后端、多个租户的工具集合并成一个 MCP 服务,凭据由登录 CLI 提供",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mcp-multi-bridge": "bin.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin.js",
|
|
11
|
+
"lib/",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"start": "node bin.js",
|
|
19
|
+
"pack:check": "npm pack --dry-run",
|
|
20
|
+
"test": "node test/toolindex.test.mjs && node test/headers.test.mjs && node test/preset.test.mjs"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"mcp",
|
|
24
|
+
"model-context-protocol",
|
|
25
|
+
"bridge",
|
|
26
|
+
"multi-tenant",
|
|
27
|
+
"multi-backend",
|
|
28
|
+
"mes"
|
|
29
|
+
],
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@modelcontextprotocol/sdk": "^1.20.2"
|
|
33
|
+
}
|
|
34
|
+
}
|