@moxxy/plugin-mcp 0.26.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/LICENSE +21 -0
- package/dist/admin/config-io.d.ts +46 -0
- package/dist/admin/config-io.d.ts.map +1 -0
- package/dist/admin/config-io.js +108 -0
- package/dist/admin/config-io.js.map +1 -0
- package/dist/admin/config-schema.d.ts +65 -0
- package/dist/admin/config-schema.d.ts.map +1 -0
- package/dist/admin/config-schema.js +36 -0
- package/dist/admin/config-schema.js.map +1 -0
- package/dist/admin/index.d.ts +21 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +189 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/runtime.d.ts +25 -0
- package/dist/admin/runtime.d.ts.map +1 -0
- package/dist/admin/runtime.js +196 -0
- package/dist/admin/runtime.js.map +1 -0
- package/dist/admin/schema.d.ts +37 -0
- package/dist/admin/schema.d.ts.map +1 -0
- package/dist/admin/schema.js +97 -0
- package/dist/admin/schema.js.map +1 -0
- package/dist/admin/secrets.d.ts +24 -0
- package/dist/admin/secrets.d.ts.map +1 -0
- package/dist/admin/secrets.js +35 -0
- package/dist/admin/secrets.js.map +1 -0
- package/dist/admin/skill.d.ts +18 -0
- package/dist/admin/skill.d.ts.map +1 -0
- package/dist/admin/skill.js +70 -0
- package/dist/admin/skill.js.map +1 -0
- package/dist/admin/tools/add.d.ts +19 -0
- package/dist/admin/tools/add.d.ts.map +1 -0
- package/dist/admin/tools/add.js +97 -0
- package/dist/admin/tools/add.js.map +1 -0
- package/dist/admin/tools/list.d.ts +3 -0
- package/dist/admin/tools/list.d.ts.map +1 -0
- package/dist/admin/tools/list.js +16 -0
- package/dist/admin/tools/list.js.map +1 -0
- package/dist/admin/tools/remove.d.ts +6 -0
- package/dist/admin/tools/remove.d.ts.map +1 -0
- package/dist/admin/tools/remove.js +41 -0
- package/dist/admin/tools/remove.js.map +1 -0
- package/dist/admin/tools/test.d.ts +8 -0
- package/dist/admin/tools/test.d.ts.map +1 -0
- package/dist/admin/tools/test.js +73 -0
- package/dist/admin/tools/test.js.map +1 -0
- package/dist/admin/types.d.ts +107 -0
- package/dist/admin/types.d.ts.map +1 -0
- package/dist/admin/types.js +2 -0
- package/dist/admin/types.js.map +1 -0
- package/dist/admin.d.ts +7 -0
- package/dist/admin.d.ts.map +1 -0
- package/dist/admin.js +7 -0
- package/dist/admin.js.map +1 -0
- package/dist/client.d.ts +10 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +73 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -0
- package/dist/timeout.d.ts +23 -0
- package/dist/timeout.d.ts.map +1 -0
- package/dist/timeout.js +35 -0
- package/dist/timeout.js.map +1 -0
- package/dist/types.d.ts +59 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/wrap.d.ts +23 -0
- package/dist/wrap.d.ts.map +1 -0
- package/dist/wrap.js +193 -0
- package/dist/wrap.js.map +1 -0
- package/package.json +63 -0
- package/src/admin/config-io.test.ts +188 -0
- package/src/admin/config-io.ts +112 -0
- package/src/admin/config-schema.ts +39 -0
- package/src/admin/index.ts +225 -0
- package/src/admin/runtime.test.ts +470 -0
- package/src/admin/runtime.ts +244 -0
- package/src/admin/schema.test.ts +70 -0
- package/src/admin/schema.ts +110 -0
- package/src/admin/secrets.test.ts +60 -0
- package/src/admin/secrets.ts +55 -0
- package/src/admin/skill.test.ts +143 -0
- package/src/admin/skill.ts +83 -0
- package/src/admin/tools/add.test.ts +193 -0
- package/src/admin/tools/add.ts +118 -0
- package/src/admin/tools/list.ts +19 -0
- package/src/admin/tools/remove.test.ts +74 -0
- package/src/admin/tools/remove.ts +46 -0
- package/src/admin/tools/test.test.ts +123 -0
- package/src/admin/tools/test.ts +84 -0
- package/src/admin/types.ts +112 -0
- package/src/admin.ts +25 -0
- package/src/client.ts +120 -0
- package/src/discovery.test.ts +45 -0
- package/src/index.test.ts +95 -0
- package/src/index.ts +101 -0
- package/src/timeout.ts +37 -0
- package/src/types.ts +57 -0
- package/src/wrap.test.ts +261 -0
- package/src/wrap.ts +236 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { defineTool, MoxxyError } from '@moxxy/sdk';
|
|
2
|
+
import { mcpConfigPath, mutateMcpConfig, readMcpConfig } from '../config-io.js';
|
|
3
|
+
import { addServerInput, validateAddServerInput } from '../schema.js';
|
|
4
|
+
export function buildAddServerTool(deps) {
|
|
5
|
+
const { registry, attachServer, detachServer, writeMcpUsageSkill } = deps;
|
|
6
|
+
return defineTool({
|
|
7
|
+
name: 'mcp_add_server',
|
|
8
|
+
description: 'Register a new MCP server in ~/.moxxy/mcp.json. Pick "stdio" for local commands ' +
|
|
9
|
+
'(npm/uv packages, scripts); pick "http" or "sse" for remote HTTP servers. The new ' +
|
|
10
|
+
'server\'s tools become available after the next moxxy restart. Call mcp_test_server ' +
|
|
11
|
+
'first if you want to verify connectivity before persisting. NEVER pass API keys or ' +
|
|
12
|
+
'tokens in plaintext: store the secret in the vault first (vault_set), then reference ' +
|
|
13
|
+
'it as "${vault:NAME}" in the env/header value — the placeholder is what gets ' +
|
|
14
|
+
'persisted, and it is resolved only at connect time.',
|
|
15
|
+
inputSchema: addServerInput,
|
|
16
|
+
permission: { action: 'prompt' },
|
|
17
|
+
handler: async (input) => {
|
|
18
|
+
const server = validateAddServerInput(input);
|
|
19
|
+
const cfg = await readMcpConfig();
|
|
20
|
+
if (cfg.servers.some((s) => s.name === server.name)) {
|
|
21
|
+
throw new MoxxyError({
|
|
22
|
+
code: 'CONFIG_INVALID',
|
|
23
|
+
message: `mcp_add_server: an MCP server named "${server.name}" already exists. ` +
|
|
24
|
+
`Use mcp_remove_server first, or pick a different name.`,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
// Hot-attach: connect + register tools BEFORE persisting. If
|
|
28
|
+
// attach fails (bad URL, missing command, schema mismatch),
|
|
29
|
+
// we never write a broken entry to disk.
|
|
30
|
+
const { toolNames, descriptors } = await attachServer(server);
|
|
31
|
+
// Cache descriptors so next boot can register lazy stubs
|
|
32
|
+
// without paying the connection cost up-front.
|
|
33
|
+
const stored = { ...server, cachedTools: descriptors };
|
|
34
|
+
// Persist under the shared config mutex, re-reading the latest
|
|
35
|
+
// catalog so a concurrent add/remove can't clobber the file. The
|
|
36
|
+
// duplicate check is repeated against the fresh read to catch a race
|
|
37
|
+
// where two adds for the same name both passed the initial check.
|
|
38
|
+
try {
|
|
39
|
+
await mutateMcpConfig((current) => {
|
|
40
|
+
if (current.servers.some((s) => s.name === server.name)) {
|
|
41
|
+
throw new MoxxyError({
|
|
42
|
+
code: 'CONFIG_INVALID',
|
|
43
|
+
message: `mcp_add_server: an MCP server named "${server.name}" already exists. ` +
|
|
44
|
+
`Use mcp_remove_server first, or pick a different name.`,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return { next: { servers: [...current.servers, stored] }, result: undefined };
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
// attachServer already registered the live tools + opened a client, but
|
|
52
|
+
// persistence failed (e.g. a concurrent add for the same name won the
|
|
53
|
+
// race, or the file write threw). Roll the live registry back so we
|
|
54
|
+
// don't strand callable tools with no config entry + a leaked client.
|
|
55
|
+
await detachServer(server.name).catch(() => undefined);
|
|
56
|
+
throw err;
|
|
57
|
+
}
|
|
58
|
+
// Auto-create the usage skill so /skills surfaces the new
|
|
59
|
+
// server alongside hand-authored skills. Best-effort — if
|
|
60
|
+
// skill writing fails, the MCP attach still succeeded.
|
|
61
|
+
let skillResult = null;
|
|
62
|
+
if (input.autoSkill !== false) {
|
|
63
|
+
try {
|
|
64
|
+
skillResult = await writeMcpUsageSkill(server, descriptors);
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
skillResult = null;
|
|
68
|
+
// surface but don't fail the whole tool call
|
|
69
|
+
return {
|
|
70
|
+
ok: true,
|
|
71
|
+
name: server.name,
|
|
72
|
+
path: mcpConfigPath(),
|
|
73
|
+
attached: registry !== null,
|
|
74
|
+
tools: toolNames,
|
|
75
|
+
skill: null,
|
|
76
|
+
skillError: err instanceof Error ? err.message : String(err),
|
|
77
|
+
note: 'Server attached + persisted; skill creation failed (see skillError).',
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
ok: true,
|
|
83
|
+
name: server.name,
|
|
84
|
+
path: mcpConfigPath(),
|
|
85
|
+
attached: registry !== null,
|
|
86
|
+
tools: toolNames,
|
|
87
|
+
skill: skillResult,
|
|
88
|
+
note: registry
|
|
89
|
+
? `Live in this session — ${toolNames.length} tool${toolNames.length === 1 ? '' : 's'} now callable.` +
|
|
90
|
+
(skillResult ? ` Usage skill written to ${skillResult.path}.` : '') +
|
|
91
|
+
' Persisted; survives restart.'
|
|
92
|
+
: 'Saved to config. Restart moxxy to load the tools (no live registry was wired into the admin plugin).',
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=add.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../../src/admin/tools/add.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/admin/tools/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAGzD,wBAAgB,oBAAoB,IAAI,OAAO,CAe9C"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineTool, z } from '@moxxy/sdk';
|
|
2
|
+
import { readMcpConfig } from '../config-io.js';
|
|
3
|
+
export function buildListServersTool() {
|
|
4
|
+
return defineTool({
|
|
5
|
+
name: 'mcp_list_servers',
|
|
6
|
+
description: 'List every MCP server currently registered in ~/.moxxy/mcp.json. Returns name + transport kind + connection details (command/url) for each.',
|
|
7
|
+
inputSchema: z.object({}),
|
|
8
|
+
handler: async () => {
|
|
9
|
+
const cfg = await readMcpConfig();
|
|
10
|
+
return cfg.servers.map((s) => s.kind === undefined || s.kind === 'stdio'
|
|
11
|
+
? { name: s.name, kind: 'stdio', command: s.command }
|
|
12
|
+
: { name: s.name, kind: s.kind, url: s.url });
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/admin/tools/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,CAAC,EAAgB,MAAM,YAAY,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,UAAU,oBAAoB;IAClC,OAAO,UAAU,CAAC;QAChB,IAAI,EAAE,kBAAkB;QACxB,WAAW,EACT,6IAA6I;QAC/I,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,MAAM,GAAG,GAAG,MAAM,aAAa,EAAE,CAAC;YAClC,OAAO,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAC3B,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO;gBACxC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,OAAgB,EAAE,OAAO,EAAG,CAAyB,CAAC,OAAO,EAAE;gBACvF,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,EAAG,CAAqB,CAAC,GAAG,EAAE,CACpE,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove.d.ts","sourceRoot":"","sources":["../../../src/admin/tools/remove.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAIzD,MAAM,WAAW,oBAAoB;IACnC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9C;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAqCzE"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { defineTool, z } from '@moxxy/sdk';
|
|
2
|
+
import { mutateMcpConfig } from '../config-io.js';
|
|
3
|
+
import { serverNameSchema } from '../schema.js';
|
|
4
|
+
export function buildRemoveServerTool(deps) {
|
|
5
|
+
const { detachServer } = deps;
|
|
6
|
+
return defineTool({
|
|
7
|
+
name: 'mcp_remove_server',
|
|
8
|
+
description: 'Remove an MCP server from ~/.moxxy/mcp.json and detach its tools from the live session. ' +
|
|
9
|
+
'The tools become uncallable immediately and the entry is gone on next restart.',
|
|
10
|
+
inputSchema: z.object({ name: serverNameSchema }),
|
|
11
|
+
permission: { action: 'prompt' },
|
|
12
|
+
handler: async ({ name }) => {
|
|
13
|
+
// Read-modify-write under the shared config mutex so a concurrent
|
|
14
|
+
// add/remove can't clobber the file.
|
|
15
|
+
const persisted = await mutateMcpConfig((cfg) => {
|
|
16
|
+
const filtered = cfg.servers.filter((s) => s.name !== name);
|
|
17
|
+
if (filtered.length === cfg.servers.length) {
|
|
18
|
+
// Nothing matched — return the same reference to skip the write.
|
|
19
|
+
return { next: cfg, result: false };
|
|
20
|
+
}
|
|
21
|
+
return { next: { servers: filtered }, result: true };
|
|
22
|
+
});
|
|
23
|
+
// Runtime detach runs OUTSIDE the config mutex (the live tool registry
|
|
24
|
+
// isn't guarded by it), so a concurrent same-name add could interleave
|
|
25
|
+
// between this persist and detach. Detach is best-effort and loosely
|
|
26
|
+
// coupled to the config — the entry is authoritative, the runtime map
|
|
27
|
+
// self-heals on the next attach/restart.
|
|
28
|
+
const detached = await detachServer(name);
|
|
29
|
+
if (!persisted && !detached) {
|
|
30
|
+
return { removed: false, name, note: `No MCP server named "${name}" was registered.` };
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
removed: true,
|
|
34
|
+
name,
|
|
35
|
+
persistedChange: persisted,
|
|
36
|
+
detachedFromSession: detached,
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=remove.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove.js","sourceRoot":"","sources":["../../../src/admin/tools/remove.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,CAAC,EAAgB,MAAM,YAAY,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAMhD,MAAM,UAAU,qBAAqB,CAAC,IAA0B;IAC9D,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IAC9B,OAAO,UAAU,CAAC;QAChB,IAAI,EAAE,mBAAmB;QACzB,WAAW,EACT,0FAA0F;YAC1F,gFAAgF;QAClF,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;QACjD,UAAU,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAChC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;YAC1B,kEAAkE;YAClE,qCAAqC;YACrC,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,CAAC,GAAG,EAAE,EAAE;gBAC9C,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;gBAC5D,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;oBAC3C,iEAAiE;oBACjE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;gBACtC,CAAC;gBACD,OAAO,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YACvD,CAAC,CAAC,CAAC;YACH,uEAAuE;YACvE,uEAAuE;YACvE,qEAAqE;YACrE,sEAAsE;YACtE,yCAAyC;YACzC,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;YAC1C,IAAI,CAAC,SAAS,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC5B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,wBAAwB,IAAI,mBAAmB,EAAE,CAAC;YACzF,CAAC;YACD,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,IAAI;gBACJ,eAAe,EAAE,SAAS;gBAC1B,mBAAmB,EAAE,QAAQ;aAC9B,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ToolDef } from '@moxxy/sdk';
|
|
2
|
+
import { type McpSecretResolver } from '../secrets.js';
|
|
3
|
+
export interface TestServerToolDeps {
|
|
4
|
+
/** Resolves `${vault:NAME}` placeholders in env/header values at connect time. */
|
|
5
|
+
readonly secretResolver?: McpSecretResolver | null;
|
|
6
|
+
}
|
|
7
|
+
export declare function buildTestServerTool(deps?: TestServerToolDeps): ToolDef;
|
|
8
|
+
//# sourceMappingURL=test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../../src/admin/tools/test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAKtD,OAAO,EAAwB,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAE7E,MAAM,WAAW,kBAAkB;IACjC,kFAAkF;IAClF,QAAQ,CAAC,cAAc,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;CACpD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAuE1E"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { defineTool } from '@moxxy/sdk';
|
|
2
|
+
import { defaultClientFactory } from '../../client.js';
|
|
3
|
+
import { MCP_CONNECT_TIMEOUT_MS, withTimeout } from '../../timeout.js';
|
|
4
|
+
import { wrapMcpServerTools } from '../../wrap.js';
|
|
5
|
+
import { addServerInput, validateAddServerInput } from '../schema.js';
|
|
6
|
+
import { resolveServerSecrets } from '../secrets.js';
|
|
7
|
+
export function buildTestServerTool(deps = {}) {
|
|
8
|
+
return defineTool({
|
|
9
|
+
name: 'mcp_test_server',
|
|
10
|
+
description: 'Connect to an MCP server WITHOUT saving it to config. Returns the list of tools the ' +
|
|
11
|
+
'server exposes if the connection succeeds, or a connection-error message. Useful for ' +
|
|
12
|
+
'sanity-checking before calling mcp_add_server. Credentials (env/header values) must be ' +
|
|
13
|
+
'vault references, never plaintext: store the secret first via vault_set, then pass ' +
|
|
14
|
+
'"${vault:NAME}" — it is resolved at connect time.',
|
|
15
|
+
inputSchema: addServerInput,
|
|
16
|
+
// Mirrors mcp_add_server: a stdio server is an arbitrary local
|
|
17
|
+
// executable we spawn, so gate behind a prompt rather than running
|
|
18
|
+
// unknown commands silently.
|
|
19
|
+
permission: { action: 'prompt' },
|
|
20
|
+
// Honest capability surface modeled on the Bash tool: for kind="stdio"
|
|
21
|
+
// this spawns a child process the user named (subprocess + broad fs,
|
|
22
|
+
// since the command can touch anything it likes); for http/sse it
|
|
23
|
+
// makes an outbound connection to an arbitrary URL (net: any). Advisory
|
|
24
|
+
// until @moxxy/plugin-security is enabled, then enforced at call time.
|
|
25
|
+
isolation: {
|
|
26
|
+
required: 'inproc',
|
|
27
|
+
capabilities: {
|
|
28
|
+
subprocess: true,
|
|
29
|
+
fs: { read: ['$cwd/**', '/tmp/**'], write: ['$cwd/**', '/tmp/**'] },
|
|
30
|
+
net: { mode: 'any' },
|
|
31
|
+
env: ['PATH', 'HOME', 'USER', 'SHELL', 'LANG', 'LC_ALL', 'TERM'],
|
|
32
|
+
timeMs: 600_000,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
handler: async (input) => {
|
|
36
|
+
const server = validateAddServerInput(input);
|
|
37
|
+
let client = null;
|
|
38
|
+
try {
|
|
39
|
+
// Bound the connect + listTools handshake so a wedged / unreachable
|
|
40
|
+
// server surfaces as a readable connection error instead of hanging
|
|
41
|
+
// this tool call forever (defaultClientFactory + listTools take no
|
|
42
|
+
// AbortSignal). On timeout the inner `connect` may still resolve a
|
|
43
|
+
// client after we've rejected; the finally{} below closes whatever
|
|
44
|
+
// `client` we captured, so a late-opening handle isn't leaked.
|
|
45
|
+
client = await withTimeout(defaultClientFactory(await resolveServerSecrets(server, deps.secretResolver ?? null)), MCP_CONNECT_TIMEOUT_MS, `MCP connect "${server.name}"`);
|
|
46
|
+
const wrapped = await withTimeout(wrapMcpServerTools({ server, client }), MCP_CONNECT_TIMEOUT_MS, `MCP listTools "${server.name}"`);
|
|
47
|
+
return {
|
|
48
|
+
ok: true,
|
|
49
|
+
name: server.name,
|
|
50
|
+
tools: wrapped.map((t) => ({ name: t.name, description: t.description })),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
return {
|
|
55
|
+
ok: false,
|
|
56
|
+
name: server.name,
|
|
57
|
+
error: err instanceof Error ? err.message : String(err),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
if (client) {
|
|
62
|
+
try {
|
|
63
|
+
await client.close();
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
/* ignore */
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.js","sourceRoot":"","sources":["../../../src/admin/tools/test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { Skill, ToolDef } from '@moxxy/sdk';
|
|
2
|
+
import type { McpClientLike, McpServerConfig, McpToolDescriptor } from '../types.js';
|
|
3
|
+
import type { McpSecretResolver } from './secrets.js';
|
|
4
|
+
/**
|
|
5
|
+
* Minimal skill-registry shape the admin plugin needs to auto-register
|
|
6
|
+
* a usage skill after `mcp_add_server`. Loose typing to keep this plugin
|
|
7
|
+
* free of an explicit @moxxy/core import.
|
|
8
|
+
*/
|
|
9
|
+
export interface AdminSkillRegistryLike {
|
|
10
|
+
register(skill: Skill): void;
|
|
11
|
+
byName(name: string): Skill | undefined;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Live runtime: live MCP clients keyed by server name plus the set of
|
|
15
|
+
* tool names each one registered into the session. Lets us close +
|
|
16
|
+
* unregister on `mcp_remove_server` and on shutdown without
|
|
17
|
+
* rediscovering anything. Module-scoped so the admin plugin and the
|
|
18
|
+
* shutdown hook share the same state; each Session that loads the
|
|
19
|
+
* plugin gets its own map via the closure in `buildMcpAdminPlugin`.
|
|
20
|
+
*/
|
|
21
|
+
export interface McpRuntimeHandle {
|
|
22
|
+
readonly client: McpClientLike;
|
|
23
|
+
readonly toolNames: ReadonlyArray<string>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Tool-registry surface the admin plugin uses to hot-attach / detach
|
|
27
|
+
* MCP tools. Matches the `ToolRegistry` in @moxxy/core but typed loosely
|
|
28
|
+
* so we don't add an internal-dep on core from this plugin.
|
|
29
|
+
*/
|
|
30
|
+
export interface AdminToolRegistryLike {
|
|
31
|
+
has(name: string): boolean;
|
|
32
|
+
register(tool: ToolDef): void;
|
|
33
|
+
unregister(name: string): void;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* On-disk catalog entry: connection config PLUS a cache of the tool
|
|
37
|
+
* descriptors the server last advertised, plus an enable/disable flag.
|
|
38
|
+
*
|
|
39
|
+
* Defined as an intersection (not `extends`) so the McpServerConfig
|
|
40
|
+
* discriminated union is preserved — `extends` would collapse it.
|
|
41
|
+
*/
|
|
42
|
+
export type McpStoredServer = McpServerConfig & {
|
|
43
|
+
readonly cachedTools?: ReadonlyArray<McpToolDescriptor>;
|
|
44
|
+
/** When true, the boot loader skips this entry — no lazy stubs are
|
|
45
|
+
* registered and tools stay invisible. Lets the user keep the
|
|
46
|
+
* connection config for later without paying for tool registration. */
|
|
47
|
+
readonly disabled?: boolean;
|
|
48
|
+
};
|
|
49
|
+
export interface McpStoredConfig {
|
|
50
|
+
readonly servers: ReadonlyArray<McpStoredServer>;
|
|
51
|
+
}
|
|
52
|
+
export interface BuildMcpAdminPluginOptions {
|
|
53
|
+
/**
|
|
54
|
+
* Live tool registry. When provided, `mcp_add_server` connects + wraps
|
|
55
|
+
* the server immediately and registers its tools into this registry —
|
|
56
|
+
* no restart needed. `mcp_remove_server` closes the client and
|
|
57
|
+
* unregisters. Pass `null` for pure-config behavior (write-only).
|
|
58
|
+
*/
|
|
59
|
+
readonly toolRegistry: AdminToolRegistryLike | null;
|
|
60
|
+
/**
|
|
61
|
+
* Skill registry + skills dir. When provided, `mcp_add_server`
|
|
62
|
+
* auto-writes a deterministic usage skill (server-name + tool catalog)
|
|
63
|
+
* to disk and registers it so `/skills` and the system-prompt index
|
|
64
|
+
* surface the MCP server alongside hand-authored skills. The skill is
|
|
65
|
+
* generated from descriptors directly — no model call. Pass `null` to
|
|
66
|
+
* disable auto-skill creation.
|
|
67
|
+
*/
|
|
68
|
+
readonly skillRegistry?: AdminSkillRegistryLike | null;
|
|
69
|
+
readonly userSkillsDir?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Resolves `${vault:NAME}` placeholders in server env/header values at
|
|
72
|
+
* CONNECT time (every connect path: hot-attach, lazy attach, cache
|
|
73
|
+
* refresh, mcp_test_server). Wired from setup with the vault's
|
|
74
|
+
* `resolveString`; literal values pass through unchanged. The persisted
|
|
75
|
+
* catalog always keeps the placeholder form, never the plaintext.
|
|
76
|
+
*/
|
|
77
|
+
readonly secretResolver?: McpSecretResolver | null;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Runtime control surface exposed alongside the admin Plugin. The TUI's
|
|
81
|
+
* /mcp slash command and the CLI's `moxxy mcp` subcommand use this to
|
|
82
|
+
* detach a server's live tools when disabling, or re-attach when
|
|
83
|
+
* enabling, without going through the model.
|
|
84
|
+
*/
|
|
85
|
+
export interface McpAdminApi {
|
|
86
|
+
/** Refresh + lazy-attach a server (used after enabling). */
|
|
87
|
+
enableAndAttach(name: string): Promise<{
|
|
88
|
+
toolNames: ReadonlyArray<string>;
|
|
89
|
+
} | null>;
|
|
90
|
+
/** Detach a server's live tools and close its client. */
|
|
91
|
+
detach(name: string): Promise<boolean>;
|
|
92
|
+
/**
|
|
93
|
+
* One-shot snapshot of every server configured in ~/.moxxy/mcp.json,
|
|
94
|
+
* joined with the runtime attach state. `enabled` reflects the persisted
|
|
95
|
+
* config (`disabled !== true`); `connected` is true when the server's
|
|
96
|
+
* tools are attached to the session (whether eagerly or via a lazy stub
|
|
97
|
+
* — both states make tools callable from a user's perspective). Used
|
|
98
|
+
* by the TUI status bar to show "mcp 2/3" style summaries.
|
|
99
|
+
*/
|
|
100
|
+
listServers(): Promise<ReadonlyArray<McpServerStatus>>;
|
|
101
|
+
}
|
|
102
|
+
export interface McpServerStatus {
|
|
103
|
+
readonly name: string;
|
|
104
|
+
readonly enabled: boolean;
|
|
105
|
+
readonly connected: boolean;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/admin/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;CACzC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC3C;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,eAAe,GAAG;IAC9C,QAAQ,CAAC,WAAW,CAAC,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;IACxD;;4EAEwE;IACxE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;CAClD;AAED,MAAM,WAAW,0BAA0B;IACzC;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACpD;;;;;;;OAOG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACvD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;CACpD;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,4DAA4D;IAC5D,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IACpF,yDAAyD;IACzD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC;;;;;;;OAOG;IACH,WAAW,IAAI,OAAO,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC;CACxD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/admin/types.ts"],"names":[],"mappings":""}
|
package/dist/admin.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backward-compatibility façade. The real implementation lives in
|
|
3
|
+
* `./admin/` as cohesive sub-modules; this file just re-exports the
|
|
4
|
+
* symbols that consumers (and the package's own `src/index.ts`) import.
|
|
5
|
+
*/
|
|
6
|
+
export { buildMcpAdminPlugin, buildMcpAdminPluginWithApi, mcpAdminPlugin, mcpConfigPath, readMcpConfig, removeServerFromConfig, setServerDisabled, writeMcpConfig, resolveServerSecrets, type McpSecretResolver, type AdminSkillRegistryLike, type AdminToolRegistryLike, type BuildMcpAdminPluginOptions, type McpAdminApi, type McpRuntimeHandle, type McpServerStatus, type McpStoredConfig, type McpStoredServer, } from './admin/index.js';
|
|
7
|
+
//# sourceMappingURL=admin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../src/admin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,mBAAmB,EACnB,0BAA0B,EAC1B,cAAc,EACd,aAAa,EACb,aAAa,EACb,sBAAsB,EACtB,iBAAiB,EACjB,cAAc,EACd,oBAAoB,EACpB,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,0BAA0B,EAC/B,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC"}
|
package/dist/admin.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backward-compatibility façade. The real implementation lives in
|
|
3
|
+
* `./admin/` as cohesive sub-modules; this file just re-exports the
|
|
4
|
+
* symbols that consumers (and the package's own `src/index.ts`) import.
|
|
5
|
+
*/
|
|
6
|
+
export { buildMcpAdminPlugin, buildMcpAdminPluginWithApi, mcpAdminPlugin, mcpConfigPath, readMcpConfig, removeServerFromConfig, setServerDisabled, writeMcpConfig, resolveServerSecrets, } from './admin/index.js';
|
|
7
|
+
//# sourceMappingURL=admin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin.js","sourceRoot":"","sources":["../src/admin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,mBAAmB,EACnB,0BAA0B,EAC1B,cAAc,EACd,aAAa,EACb,aAAa,EACb,sBAAsB,EACtB,iBAAiB,EACjB,cAAc,EACd,oBAAoB,GAUrB,MAAM,kBAAkB,CAAC"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default MCP client factory + transport setup. Lives in its own module so
|
|
3
|
+
* both `index.ts` (the public surface) and `admin.ts` (the runtime
|
|
4
|
+
* admin/hot-attach tools) can pull `defaultClientFactory` without the two
|
|
5
|
+
* referencing each other — which is what would otherwise create the
|
|
6
|
+
* `admin.ts → index.ts → admin.ts` import cycle.
|
|
7
|
+
*/
|
|
8
|
+
import type { McpClientLike, McpPluginOptions, McpServerConfig } from './types.js';
|
|
9
|
+
export declare function defaultClientFactory(server: McpServerConfig, options?: McpPluginOptions): Promise<McpClientLike>;
|
|
10
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAEV,aAAa,EAEb,gBAAgB,EAChB,eAAe,EAEhB,MAAM,YAAY,CAAC;AAEpB,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,eAAe,EACvB,OAAO,GAAE,gBAAkC,GAC1C,OAAO,CAAC,aAAa,CAAC,CAgCxB"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default MCP client factory + transport setup. Lives in its own module so
|
|
3
|
+
* both `index.ts` (the public surface) and `admin.ts` (the runtime
|
|
4
|
+
* admin/hot-attach tools) can pull `defaultClientFactory` without the two
|
|
5
|
+
* referencing each other — which is what would otherwise create the
|
|
6
|
+
* `admin.ts → index.ts → admin.ts` import cycle.
|
|
7
|
+
*/
|
|
8
|
+
export async function defaultClientFactory(server, options = { servers: [] }) {
|
|
9
|
+
const { Client } = (await import('@modelcontextprotocol/sdk/client/index.js'));
|
|
10
|
+
// Type the SDK boundary ONCE here; the rest of the factory works against the
|
|
11
|
+
// typed `McpClientUntyped` so a signature change in the SDK surfaces as a
|
|
12
|
+
// compile error rather than being papered over by per-call casts.
|
|
13
|
+
const client = new Client({ name: options.clientName ?? 'moxxy', version: options.clientVersion ?? '0.0.0' }, { capabilities: {} });
|
|
14
|
+
const transport = await createTransport(server);
|
|
15
|
+
await client.connect(transport);
|
|
16
|
+
return {
|
|
17
|
+
async listTools() {
|
|
18
|
+
const result = await client.listTools();
|
|
19
|
+
return { tools: (result.tools ?? []).map(toToolDescriptor) };
|
|
20
|
+
},
|
|
21
|
+
async callTool(args) {
|
|
22
|
+
const result = await client.callTool(args);
|
|
23
|
+
const out = {
|
|
24
|
+
content: result.content?.map(toContentBlock),
|
|
25
|
+
isError: result.isError,
|
|
26
|
+
};
|
|
27
|
+
return out;
|
|
28
|
+
},
|
|
29
|
+
async close() {
|
|
30
|
+
await client.close();
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/** Narrow one SDK tool entry to our internal descriptor at the single boundary. */
|
|
35
|
+
function toToolDescriptor(t) {
|
|
36
|
+
return t;
|
|
37
|
+
}
|
|
38
|
+
/** Narrow one SDK content block to our internal union at the single boundary. */
|
|
39
|
+
function toContentBlock(block) {
|
|
40
|
+
return block;
|
|
41
|
+
}
|
|
42
|
+
async function createTransport(server) {
|
|
43
|
+
const kind = server.kind ?? 'stdio';
|
|
44
|
+
if (kind === 'stdio') {
|
|
45
|
+
const stdioServer = server;
|
|
46
|
+
const { StdioClientTransport } = (await import('@modelcontextprotocol/sdk/client/stdio.js'));
|
|
47
|
+
// Set stderr to 'ignore' so spawned subprocesses (mcp-remote, etc.)
|
|
48
|
+
// don't dump their boot logs into the moxxy TUI. The SDK defaults
|
|
49
|
+
// to 'inherit' which clobbers the chat with proxy-status lines on
|
|
50
|
+
// every boot. Set MOXXY_MCP_STDERR=inherit to opt back in for
|
|
51
|
+
// debugging.
|
|
52
|
+
const stderrMode = process.env.MOXXY_MCP_STDERR === 'inherit' ? 'inherit' : 'ignore';
|
|
53
|
+
return new StdioClientTransport({
|
|
54
|
+
command: stdioServer.command,
|
|
55
|
+
args: stdioServer.args ? [...stdioServer.args] : undefined,
|
|
56
|
+
env: stdioServer.env,
|
|
57
|
+
cwd: stdioServer.cwd,
|
|
58
|
+
stderr: stderrMode,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
const httpish = server;
|
|
62
|
+
if (kind === 'sse') {
|
|
63
|
+
const { SSEClientTransport } = (await import('@modelcontextprotocol/sdk/client/sse.js'));
|
|
64
|
+
return new SSEClientTransport(new URL(httpish.url), {
|
|
65
|
+
requestInit: httpish.headers ? { headers: httpish.headers } : undefined,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const { StreamableHTTPClientTransport } = (await import('@modelcontextprotocol/sdk/client/streamableHttp.js'));
|
|
69
|
+
return new StreamableHTTPClientTransport(new URL(httpish.url), {
|
|
70
|
+
requestInit: httpish.headers ? { headers: httpish.headers } : undefined,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Plugin } from '@moxxy/sdk';
|
|
2
|
+
import type { McpClientLike, McpPluginOptions, McpServerConfig } from './types.js';
|
|
3
|
+
export type { McpClientLike, McpContentBlock, McpPluginOptions, McpServerConfig, McpToolDescriptor, SseServerConfig, StdioServerConfig, StreamableHttpServerConfig, } from './types.js';
|
|
4
|
+
export { wrapMcpServerTools } from './wrap.js';
|
|
5
|
+
export { defaultToolNamePrefix } from './types.js';
|
|
6
|
+
export { defaultClientFactory } from './client.js';
|
|
7
|
+
export { buildMcpAdminPlugin, buildMcpAdminPluginWithApi, mcpAdminPlugin, mcpConfigPath, readMcpConfig, removeServerFromConfig, setServerDisabled, writeMcpConfig, resolveServerSecrets, type McpSecretResolver, type McpAdminApi, type McpServerStatus, type McpStoredConfig, type McpStoredServer, } from './admin.js';
|
|
8
|
+
export interface CreateMcpPluginOptions extends McpPluginOptions {
|
|
9
|
+
/**
|
|
10
|
+
* Inject a custom client factory. Used by tests; production code uses the
|
|
11
|
+
* default factory that imports `@modelcontextprotocol/sdk`.
|
|
12
|
+
*/
|
|
13
|
+
readonly clientFactory?: (server: McpServerConfig, options: McpPluginOptions) => Promise<McpClientLike>;
|
|
14
|
+
}
|
|
15
|
+
export declare function createMcpPlugin(opts: CreateMcpPluginOptions): Promise<Plugin>;
|
|
16
|
+
export { mcpAdminPlugin as default } from './admin.js';
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKnF,YAAY,EACV,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,0BAA0B,GAC3B,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EACL,mBAAmB,EACnB,0BAA0B,EAC1B,cAAc,EACd,aAAa,EACb,aAAa,EACb,sBAAsB,EACtB,iBAAiB,EACjB,cAAc,EACd,oBAAoB,EACpB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;CACzG;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmDnF;AAKD,OAAO,EAAE,cAAc,IAAI,OAAO,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { definePlugin } from '@moxxy/sdk';
|
|
2
|
+
import { defaultClientFactory } from './client.js';
|
|
3
|
+
import { MCP_CONNECT_TIMEOUT_MS, withTimeout } from './timeout.js';
|
|
4
|
+
import { wrapMcpServerTools } from './wrap.js';
|
|
5
|
+
export { wrapMcpServerTools } from './wrap.js';
|
|
6
|
+
export { defaultToolNamePrefix } from './types.js';
|
|
7
|
+
export { defaultClientFactory } from './client.js';
|
|
8
|
+
export { buildMcpAdminPlugin, buildMcpAdminPluginWithApi, mcpAdminPlugin, mcpConfigPath, readMcpConfig, removeServerFromConfig, setServerDisabled, writeMcpConfig, resolveServerSecrets, } from './admin.js';
|
|
9
|
+
export async function createMcpPlugin(opts) {
|
|
10
|
+
const factory = opts.clientFactory ?? defaultClientFactory;
|
|
11
|
+
// Connect + list each server in PARALLEL: serial boot paid the sum of every
|
|
12
|
+
// server's spawn/handshake/listTools round-trip, so N servers serialized N
|
|
13
|
+
// latencies. allSettled bounds boot at the slowest server, not the sum,
|
|
14
|
+
// while still letting us close every successfully-opened client if any leg
|
|
15
|
+
// fails (the onShutdown hook is only wired once we RETURN the plugin).
|
|
16
|
+
const opened = [];
|
|
17
|
+
const results = await Promise.allSettled(opts.servers.map(async (server) => {
|
|
18
|
+
// Bound the connect handshake so a single wedged server spawn surfaces
|
|
19
|
+
// as a rejected leg rather than stalling boot until the transport's own
|
|
20
|
+
// (possibly absent) timeout fires. The leg's client, if it opened before
|
|
21
|
+
// the timeout, is still tracked in `opened` and closed in the failure
|
|
22
|
+
// cleanup below.
|
|
23
|
+
const client = await withTimeout(factory(server, opts), MCP_CONNECT_TIMEOUT_MS, `MCP connect "${server.name}"`);
|
|
24
|
+
// Record the client the instant it opens, before listTools — so even a
|
|
25
|
+
// listTools failure can't leak its child process / socket.
|
|
26
|
+
opened.push(client);
|
|
27
|
+
return withTimeout(wrapMcpServerTools({ server, client, toolNamePrefix: opts.toolNamePrefix }), MCP_CONNECT_TIMEOUT_MS, `MCP listTools "${server.name}"`);
|
|
28
|
+
}));
|
|
29
|
+
const failure = results.find((r) => r.status === 'rejected');
|
|
30
|
+
if (failure) {
|
|
31
|
+
await Promise.allSettled(opened.map((c) => c.close()));
|
|
32
|
+
throw failure.reason;
|
|
33
|
+
}
|
|
34
|
+
// Flatten in server order (map preserves index → deterministic tool order).
|
|
35
|
+
const tools = results.flatMap((r) => r.value);
|
|
36
|
+
const clients = opened;
|
|
37
|
+
return definePlugin({
|
|
38
|
+
name: '@moxxy/plugin-mcp',
|
|
39
|
+
version: '0.0.0',
|
|
40
|
+
tools,
|
|
41
|
+
hooks: {
|
|
42
|
+
onShutdown: async () => {
|
|
43
|
+
await Promise.allSettled(clients.map((c) => c.close()));
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
// Discovery entry: `createPluginLoader` requires a default Plugin export.
|
|
49
|
+
export { mcpAdminPlugin as default } from './admin.js';
|
|
50
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAe,MAAM,YAAY,CAAC;AAEvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAY/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EACL,mBAAmB,EACnB,0BAA0B,EAC1B,cAAc,EACd,aAAa,EACb,aAAa,EACb,sBAAsB,EACtB,iBAAiB,EACjB,cAAc,EACd,oBAAoB,GAMrB,MAAM,YAAY,CAAC;AAUpB,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAA4B;IAChE,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,IAAI,oBAAoB,CAAC;IAC3D,4EAA4E;IAC5E,2EAA2E;IAC3E,wEAAwE;IACxE,2EAA2E;IAC3E,uEAAuE;IACvE,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CACtC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QAChC,uEAAuE;QACvE,wEAAwE;QACxE,yEAAyE;QACzE,sEAAsE;QACtE,iBAAiB;QACjB,MAAM,MAAM,GAAG,MAAM,WAAW,CAC9B,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,EACrB,sBAAsB,EACtB,gBAAgB,MAAM,CAAC,IAAI,GAAG,CAC/B,CAAC;QACF,uEAAuE;QACvE,2DAA2D;QAC3D,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACpB,OAAO,WAAW,CAChB,kBAAkB,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,EAC3E,sBAAsB,EACtB,kBAAkB,MAAM,CAAC,IAAI,GAAG,CACjC,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;IAEF,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC;IAC7D,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACvD,MAAO,OAAiC,CAAC,MAAM,CAAC;IAClD,CAAC;IAED,4EAA4E;IAC5E,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAE,CAA4E,CAAC,KAAK,CAAC,CAAC;IAC1H,MAAM,OAAO,GAAG,MAAM,CAAC;IAEvB,OAAO,YAAY,CAAC;QAClB,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,OAAO;QAChB,KAAK;QACL,KAAK,EAAE;YACL,UAAU,EAAE,KAAK,IAAI,EAAE;gBACrB,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YAC1D,CAAC;SACF;KACF,CAAC,CAAC;AACL,CAAC;AAID,0EAA0E;AAC1E,OAAO,EAAE,cAAc,IAAI,OAAO,EAAE,MAAM,YAAY,CAAC"}
|