@zhin.js/mcp-feature 1.0.2 → 1.0.4
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 +3 -0
- package/lib/definition.d.ts +5 -0
- package/lib/mcp-index.js +6 -2
- package/lib/provider.js +13 -0
- package/package.json +3 -3
- package/src/definition.ts +6 -0
- package/src/mcp-index.ts +6 -2
- package/src/provider.ts +15 -1
package/README.md
CHANGED
|
@@ -34,6 +34,9 @@ export default defineMcp({
|
|
|
34
34
|
|
|
35
35
|
`create()` 在 projection prepare 中执行,只能构造 inert client;网络连接必须放在 `start()`。具体 stdio/HTTP transport 和 MCP SDK 由 Plugin Resource 或可选 adapter 提供,本包没有相关第三方依赖。
|
|
36
36
|
|
|
37
|
+
单文件插件可用 `setup({ addMcp })` 注册 `defineMcp(...)`。它仍走相同的连接 handoff、
|
|
38
|
+
owner 继承和 generation 回收。
|
|
39
|
+
|
|
37
40
|
## 生命周期
|
|
38
41
|
|
|
39
42
|
```text
|
package/lib/definition.d.ts
CHANGED
|
@@ -16,6 +16,11 @@ export interface McpDefinition<TConfig = unknown> {
|
|
|
16
16
|
readonly description?: string;
|
|
17
17
|
create(context: CapabilityContext<TConfig>): McpClientInstance | Promise<McpClientInstance>;
|
|
18
18
|
}
|
|
19
|
+
declare module '@zhin.js/plugin-runtime' {
|
|
20
|
+
interface PluginSetupContext<TConfig> {
|
|
21
|
+
addMcp(localName: string, definition: McpDefinition<TConfig>): void;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
19
24
|
export declare function defineMcp<TConfig = unknown>(definition: Omit<McpDefinition<TConfig>, '$feature'>): Readonly<McpDefinition<TConfig>>;
|
|
20
25
|
export declare function parseMcpDefinition(value: unknown): McpDefinition;
|
|
21
26
|
export declare function assertMcpClient(value: unknown, source: string): asserts value is McpClientInstance;
|
package/lib/mcp-index.js
CHANGED
|
@@ -37,11 +37,12 @@ export class McpIndex {
|
|
|
37
37
|
const started = [];
|
|
38
38
|
try {
|
|
39
39
|
for (const record of this.#order) {
|
|
40
|
-
if (record.started
|
|
40
|
+
if (record.started)
|
|
41
41
|
continue;
|
|
42
42
|
started.push(record);
|
|
43
43
|
await record.client.start?.();
|
|
44
44
|
record.started = true;
|
|
45
|
+
record.stopped = false;
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
catch (error) {
|
|
@@ -90,8 +91,11 @@ async function stopRecords(records, primary) {
|
|
|
90
91
|
if (record.stopped)
|
|
91
92
|
continue;
|
|
92
93
|
stack.add(async () => {
|
|
93
|
-
|
|
94
|
+
// 先 await stop 成功再标记 stopped:stop 失败时保持未标记,
|
|
95
|
+
// 下次 stop()(或代际 resume 后的再次 quiesce)可重试,不会永久泄漏。
|
|
94
96
|
await record.client.stop?.();
|
|
97
|
+
record.started = false;
|
|
98
|
+
record.stopped = true;
|
|
95
99
|
});
|
|
96
100
|
}
|
|
97
101
|
try {
|
package/lib/provider.js
CHANGED
|
@@ -7,6 +7,7 @@ const mcpFeature = defineFeatureProvider({
|
|
|
7
7
|
protocol: 1,
|
|
8
8
|
id: mcpFeatureId,
|
|
9
9
|
authoring: {
|
|
10
|
+
setupMethod: 'addMcp',
|
|
10
11
|
conventions: [typeScriptModules({
|
|
11
12
|
id: 'mcp-ts',
|
|
12
13
|
directory: 'mcp',
|
|
@@ -17,16 +18,28 @@ const mcpFeature = defineFeatureProvider({
|
|
|
17
18
|
runtime: {
|
|
18
19
|
async project(slots, context) {
|
|
19
20
|
const index = await McpIndex.create(slots, context.snapshot);
|
|
21
|
+
let previousIndex;
|
|
20
22
|
return {
|
|
21
23
|
value: index,
|
|
22
24
|
dispose: () => index.stop(),
|
|
23
25
|
handoff: {
|
|
26
|
+
// 先停旧代连接再激活新代:独占端口型 server 热重载不会新旧并存。
|
|
27
|
+
quiescePrevious(previous) {
|
|
28
|
+
previousIndex = previousMcpIndex(previous);
|
|
29
|
+
return previousIndex?.stop();
|
|
30
|
+
},
|
|
24
31
|
activateNext: () => index.start(),
|
|
25
32
|
deactivateNext: () => index.stop(),
|
|
33
|
+
resumePrevious() {
|
|
34
|
+
return previousIndex?.start();
|
|
35
|
+
},
|
|
26
36
|
},
|
|
27
37
|
};
|
|
28
38
|
},
|
|
29
39
|
},
|
|
30
40
|
});
|
|
41
|
+
function previousMcpIndex(snapshot) {
|
|
42
|
+
return snapshot.projections.get(mcpFeatureId);
|
|
43
|
+
}
|
|
31
44
|
export { mcpFeature };
|
|
32
45
|
export default mcpFeature;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/mcp-feature",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Convention-based MCP client Feature for Zhin Plugin Runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"src"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@zhin.js/feature-kit": "1.0.
|
|
21
|
-
"@zhin.js/plugin-runtime": "1.1.
|
|
20
|
+
"@zhin.js/feature-kit": "1.0.4",
|
|
21
|
+
"@zhin.js/plugin-runtime": "1.1.1"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^26.1.0",
|
package/src/definition.ts
CHANGED
|
@@ -21,6 +21,12 @@ export interface McpDefinition<TConfig = unknown> {
|
|
|
21
21
|
create(context: CapabilityContext<TConfig>): McpClientInstance | Promise<McpClientInstance>;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
declare module '@zhin.js/plugin-runtime' {
|
|
25
|
+
interface PluginSetupContext<TConfig> {
|
|
26
|
+
addMcp(localName: string, definition: McpDefinition<TConfig>): void;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
24
30
|
export function defineMcp<TConfig = unknown>(
|
|
25
31
|
definition: Omit<McpDefinition<TConfig>, '$feature'>,
|
|
26
32
|
): Readonly<McpDefinition<TConfig>> {
|
package/src/mcp-index.ts
CHANGED
|
@@ -78,10 +78,11 @@ export class McpIndex {
|
|
|
78
78
|
const started: McpRecord[] = [];
|
|
79
79
|
try {
|
|
80
80
|
for (const record of this.#order) {
|
|
81
|
-
if (record.started
|
|
81
|
+
if (record.started) continue;
|
|
82
82
|
started.push(record);
|
|
83
83
|
await record.client.start?.();
|
|
84
84
|
record.started = true;
|
|
85
|
+
record.stopped = false;
|
|
85
86
|
}
|
|
86
87
|
} catch (error) {
|
|
87
88
|
await stopRecords(started, error);
|
|
@@ -137,8 +138,11 @@ async function stopRecords(records: readonly McpRecord[], primary?: unknown): Pr
|
|
|
137
138
|
for (const record of records) {
|
|
138
139
|
if (record.stopped) continue;
|
|
139
140
|
stack.add(async () => {
|
|
140
|
-
|
|
141
|
+
// 先 await stop 成功再标记 stopped:stop 失败时保持未标记,
|
|
142
|
+
// 下次 stop()(或代际 resume 后的再次 quiesce)可重试,不会永久泄漏。
|
|
141
143
|
await record.client.stop?.();
|
|
144
|
+
record.started = false;
|
|
145
|
+
record.stopped = true;
|
|
142
146
|
});
|
|
143
147
|
}
|
|
144
148
|
try {
|
package/src/provider.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { featureId } from '@zhin.js/plugin-runtime';
|
|
1
|
+
import { featureId, type RuntimeSnapshot } from '@zhin.js/plugin-runtime';
|
|
2
2
|
import { defineFeatureProvider, typeScriptModules } from '@zhin.js/feature-kit';
|
|
3
3
|
import { parseMcpDefinition } from './definition.js';
|
|
4
4
|
import { McpIndex } from './mcp-index.js';
|
|
@@ -9,6 +9,7 @@ const mcpFeature = defineFeatureProvider({
|
|
|
9
9
|
protocol: 1,
|
|
10
10
|
id: mcpFeatureId,
|
|
11
11
|
authoring: {
|
|
12
|
+
setupMethod: 'addMcp',
|
|
12
13
|
conventions: [typeScriptModules({
|
|
13
14
|
id: 'mcp-ts',
|
|
14
15
|
directory: 'mcp',
|
|
@@ -19,17 +20,30 @@ const mcpFeature = defineFeatureProvider({
|
|
|
19
20
|
runtime: {
|
|
20
21
|
async project(slots, context) {
|
|
21
22
|
const index = await McpIndex.create(slots, context.snapshot);
|
|
23
|
+
let previousIndex: McpIndex | undefined;
|
|
22
24
|
return {
|
|
23
25
|
value: index,
|
|
24
26
|
dispose: () => index.stop(),
|
|
25
27
|
handoff: {
|
|
28
|
+
// 先停旧代连接再激活新代:独占端口型 server 热重载不会新旧并存。
|
|
29
|
+
quiescePrevious(previous) {
|
|
30
|
+
previousIndex = previousMcpIndex(previous);
|
|
31
|
+
return previousIndex?.stop();
|
|
32
|
+
},
|
|
26
33
|
activateNext: () => index.start(),
|
|
27
34
|
deactivateNext: () => index.stop(),
|
|
35
|
+
resumePrevious() {
|
|
36
|
+
return previousIndex?.start();
|
|
37
|
+
},
|
|
28
38
|
},
|
|
29
39
|
};
|
|
30
40
|
},
|
|
31
41
|
},
|
|
32
42
|
});
|
|
33
43
|
|
|
44
|
+
function previousMcpIndex(snapshot: RuntimeSnapshot): McpIndex | undefined {
|
|
45
|
+
return snapshot.projections.get(mcpFeatureId) as McpIndex | undefined;
|
|
46
|
+
}
|
|
47
|
+
|
|
34
48
|
export { mcpFeature };
|
|
35
49
|
export default mcpFeature;
|