opencode-lazy-loader 1.0.0 → 1.0.1
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/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/skill-loader.d.ts +27 -0
- package/dist/skill-loader.d.ts.map +1 -0
- package/dist/skill-loader.js +197 -0
- package/dist/skill-loader.js.map +1 -0
- package/dist/skill-mcp-manager.d.ts +26 -0
- package/dist/skill-mcp-manager.d.ts.map +1 -0
- package/dist/skill-mcp-manager.js +284 -0
- package/dist/skill-mcp-manager.js.map +1 -0
- package/dist/tools/skill-mcp.d.ts +13 -0
- package/dist/tools/skill-mcp.d.ts.map +1 -0
- package/dist/tools/skill-mcp.js +162 -0
- package/dist/tools/skill-mcp.js.map +1 -0
- package/dist/tools/skill.d.ts +13 -0
- package/dist/tools/skill.d.ts.map +1 -0
- package/dist/tools/skill.js +160 -0
- package/dist/tools/skill.js.map +1 -0
- package/dist/types.d.ts +70 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/env-vars.d.ts +15 -0
- package/dist/utils/env-vars.d.ts.map +1 -0
- package/dist/utils/env-vars.js +59 -0
- package/dist/utils/env-vars.js.map +1 -0
- package/dist/utils/frontmatter.d.ts +10 -0
- package/dist/utils/frontmatter.d.ts.map +1 -0
- package/dist/utils/frontmatter.js +44 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/package.json +5 -4
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Plugin } from '@opencode-ai/plugin';
|
|
2
|
+
/**
|
|
3
|
+
* OpenCode Embedded Skill MCP Plugin
|
|
4
|
+
*
|
|
5
|
+
* Provides skill-embedded MCP support for OpenCode without requiring oh-my-opencode.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Discovers skills from .opencode/skill/ (project) and ~/.config/opencode/skill/ (user)
|
|
9
|
+
* - Parses MCP configurations from YAML frontmatter or mcp.json files
|
|
10
|
+
* - Provides 'skill' tool to load skill instructions and discover MCP capabilities
|
|
11
|
+
* - Provides 'skill_mcp' tool to invoke MCP operations (tools, resources, prompts)
|
|
12
|
+
* - Manages MCP client connections with pooling, lazy initialization, and cleanup
|
|
13
|
+
*/
|
|
14
|
+
export declare const OpenCodeEmbeddedSkillMcp: Plugin;
|
|
15
|
+
export default OpenCodeEmbeddedSkillMcp;
|
|
16
|
+
export type { LoadedSkill, McpServerConfig, SkillScope } from './types.js';
|
|
17
|
+
export { discoverSkills } from './skill-loader.js';
|
|
18
|
+
export { createSkillMcpManager } from './skill-mcp-manager.js';
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAOjD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAwCtC,CAAA;AAGD,eAAe,wBAAwB,CAAA;AAGvC,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createSkillMcpManager } from './skill-mcp-manager.js';
|
|
2
|
+
import { discoverSkills } from './skill-loader.js';
|
|
3
|
+
import { createSkillTool } from './tools/skill.js';
|
|
4
|
+
import { createSkillMcpTool } from './tools/skill-mcp.js';
|
|
5
|
+
/**
|
|
6
|
+
* OpenCode Embedded Skill MCP Plugin
|
|
7
|
+
*
|
|
8
|
+
* Provides skill-embedded MCP support for OpenCode without requiring oh-my-opencode.
|
|
9
|
+
*
|
|
10
|
+
* Features:
|
|
11
|
+
* - Discovers skills from .opencode/skill/ (project) and ~/.config/opencode/skill/ (user)
|
|
12
|
+
* - Parses MCP configurations from YAML frontmatter or mcp.json files
|
|
13
|
+
* - Provides 'skill' tool to load skill instructions and discover MCP capabilities
|
|
14
|
+
* - Provides 'skill_mcp' tool to invoke MCP operations (tools, resources, prompts)
|
|
15
|
+
* - Manages MCP client connections with pooling, lazy initialization, and cleanup
|
|
16
|
+
*/
|
|
17
|
+
export const OpenCodeEmbeddedSkillMcp = async ({ client }) => {
|
|
18
|
+
const manager = createSkillMcpManager();
|
|
19
|
+
let loadedSkills = [];
|
|
20
|
+
let currentSessionID = null;
|
|
21
|
+
// Discover skills on initialization
|
|
22
|
+
try {
|
|
23
|
+
loadedSkills = await discoverSkills();
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
loadedSkills = [];
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
// Handle session lifecycle events
|
|
30
|
+
event: async ({ event }) => {
|
|
31
|
+
if (event.type === 'session.created') {
|
|
32
|
+
currentSessionID = event.properties.info.id;
|
|
33
|
+
}
|
|
34
|
+
if (event.type === 'session.deleted' && currentSessionID) {
|
|
35
|
+
// Cleanup MCP connections for the deleted session
|
|
36
|
+
await manager.disconnectSession(currentSessionID);
|
|
37
|
+
currentSessionID = null;
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
// Register tools
|
|
41
|
+
tool: {
|
|
42
|
+
skill: createSkillTool({
|
|
43
|
+
skills: loadedSkills,
|
|
44
|
+
mcpManager: manager,
|
|
45
|
+
getSessionID: () => currentSessionID || 'unknown'
|
|
46
|
+
}),
|
|
47
|
+
skill_mcp: createSkillMcpTool({
|
|
48
|
+
manager,
|
|
49
|
+
getLoadedSkills: () => loadedSkills,
|
|
50
|
+
getSessionID: () => currentSessionID || 'unknown'
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
// Default export for plugin loading
|
|
56
|
+
export default OpenCodeEmbeddedSkillMcp;
|
|
57
|
+
export { discoverSkills } from './skill-loader.js';
|
|
58
|
+
export { createSkillMcpManager } from './skill-mcp-manager.js';
|
|
59
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAGzD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAW,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;IACnE,MAAM,OAAO,GAAG,qBAAqB,EAAE,CAAA;IACvC,IAAI,YAAY,GAAkB,EAAE,CAAA;IACpC,IAAI,gBAAgB,GAAkB,IAAI,CAAA;IAE1C,oCAAoC;IACpC,IAAI,CAAC;QACH,YAAY,GAAG,MAAM,cAAc,EAAE,CAAA;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,YAAY,GAAG,EAAE,CAAA;IACnB,CAAC;IAED,OAAO;QACL,kCAAkC;QAClC,KAAK,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;YACzB,IAAI,KAAK,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;gBACrC,gBAAgB,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAA;YAC7C,CAAC;YAED,IAAI,KAAK,CAAC,IAAI,KAAK,iBAAiB,IAAI,gBAAgB,EAAE,CAAC;gBACzD,kDAAkD;gBAClD,MAAM,OAAO,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,CAAA;gBACjD,gBAAgB,GAAG,IAAI,CAAA;YACzB,CAAC;QACH,CAAC;QAED,iBAAiB;QACjB,IAAI,EAAE;YACJ,KAAK,EAAE,eAAe,CAAC;gBACrB,MAAM,EAAE,YAAY;gBACpB,UAAU,EAAE,OAAO;gBACnB,YAAY,EAAE,GAAG,EAAE,CAAC,gBAAgB,IAAI,SAAS;aAClD,CAAC;YACF,SAAS,EAAE,kBAAkB,CAAC;gBAC5B,OAAO;gBACP,eAAe,EAAE,GAAG,EAAE,CAAC,YAAY;gBACnC,YAAY,EAAE,GAAG,EAAE,CAAC,gBAAgB,IAAI,SAAS;aAClD,CAAC;SACH;KACF,CAAA;AACH,CAAC,CAAA;AAED,oCAAoC;AACpC,eAAe,wBAAwB,CAAA;AAIvC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { LoadedSkill, McpServerConfig, SkillScope } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Load MCP config from mcp.json file in skill directory
|
|
4
|
+
*/
|
|
5
|
+
export declare function loadMcpJsonFromDir(skillDir: string): Promise<Record<string, McpServerConfig> | undefined>;
|
|
6
|
+
/**
|
|
7
|
+
* Load a skill from a markdown file path
|
|
8
|
+
*/
|
|
9
|
+
export declare function loadSkillFromPath(skillPath: string, resolvedPath: string, defaultName: string, scope: SkillScope): Promise<LoadedSkill | null>;
|
|
10
|
+
/**
|
|
11
|
+
* Load all skills from a directory
|
|
12
|
+
*/
|
|
13
|
+
export declare function loadSkillsFromDir(skillsDir: string, scope: SkillScope): Promise<LoadedSkill[]>;
|
|
14
|
+
/**
|
|
15
|
+
* Discover skills from opencode global directory (~/.config/opencode/skill/)
|
|
16
|
+
*/
|
|
17
|
+
export declare function discoverOpencodeGlobalSkills(): Promise<LoadedSkill[]>;
|
|
18
|
+
/**
|
|
19
|
+
* Discover skills from opencode project directory (.opencode/skill/)
|
|
20
|
+
*/
|
|
21
|
+
export declare function discoverOpencodeProjectSkills(): Promise<LoadedSkill[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Discover all skills from both opencode locations
|
|
24
|
+
* Priority: project > global
|
|
25
|
+
*/
|
|
26
|
+
export declare function discoverSkills(): Promise<LoadedSkill[]>;
|
|
27
|
+
//# sourceMappingURL=skill-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-loader.d.ts","sourceRoot":"","sources":["../src/skill-loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,UAAU,EAAe,MAAM,YAAY,CAAA;AAsBvF;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC,CA+BtD;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAsD7B;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC,WAAW,EAAE,CAAC,CAyDxB;AAED;;GAEG;AACH,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAG3E;AAED;;GAEG;AACH,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAG5E;AAED;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAoB7D"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import { join, basename } from 'path';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import { parseFrontmatter, parseSkillMcpConfigFromFrontmatter } from './utils/frontmatter.js';
|
|
5
|
+
/**
|
|
6
|
+
* Check if a file is a markdown file
|
|
7
|
+
*/
|
|
8
|
+
function isMarkdownFile(entry) {
|
|
9
|
+
return entry.name.endsWith('.md');
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Resolve symlink to its target path
|
|
13
|
+
*/
|
|
14
|
+
async function resolveSymlinkAsync(entryPath) {
|
|
15
|
+
try {
|
|
16
|
+
const realPath = await fs.realpath(entryPath);
|
|
17
|
+
return realPath;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return entryPath;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Load MCP config from mcp.json file in skill directory
|
|
25
|
+
*/
|
|
26
|
+
export async function loadMcpJsonFromDir(skillDir) {
|
|
27
|
+
const mcpJsonPath = join(skillDir, 'mcp.json');
|
|
28
|
+
try {
|
|
29
|
+
const content = await fs.readFile(mcpJsonPath, 'utf-8');
|
|
30
|
+
const parsed = JSON.parse(content);
|
|
31
|
+
// Support { mcpServers: { ... } } format
|
|
32
|
+
if (parsed && typeof parsed === 'object' && 'mcpServers' in parsed && parsed.mcpServers) {
|
|
33
|
+
return parsed.mcpServers;
|
|
34
|
+
}
|
|
35
|
+
// Support { mcp: { ... } } format (OpenCode config style)
|
|
36
|
+
if (parsed && typeof parsed === 'object' && 'mcp' in parsed && parsed.mcp) {
|
|
37
|
+
return parsed.mcp;
|
|
38
|
+
}
|
|
39
|
+
// Support direct { serverName: { command: ... } } format
|
|
40
|
+
if (parsed && typeof parsed === 'object' && !('mcpServers' in parsed) && !('mcp' in parsed)) {
|
|
41
|
+
const hasCommandField = Object.values(parsed).some((v) => v && typeof v === 'object' && 'command' in v);
|
|
42
|
+
if (hasCommandField) {
|
|
43
|
+
return parsed;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Load a skill from a markdown file path
|
|
54
|
+
*/
|
|
55
|
+
export async function loadSkillFromPath(skillPath, resolvedPath, defaultName, scope) {
|
|
56
|
+
try {
|
|
57
|
+
const content = await fs.readFile(skillPath, 'utf-8');
|
|
58
|
+
const { data } = parseFrontmatter(content);
|
|
59
|
+
// Load MCP config from frontmatter or mcp.json
|
|
60
|
+
const frontmatterMcp = parseSkillMcpConfigFromFrontmatter(content);
|
|
61
|
+
const mcpJsonMcp = await loadMcpJsonFromDir(resolvedPath);
|
|
62
|
+
const mcpConfig = mcpJsonMcp || frontmatterMcp; // mcp.json takes priority
|
|
63
|
+
const skillName = data.name || defaultName;
|
|
64
|
+
const originalDescription = data.description || '';
|
|
65
|
+
const formattedDescription = `(${scope} - Skill) ${originalDescription}`;
|
|
66
|
+
// Create lazy content loader
|
|
67
|
+
const lazyContent = {
|
|
68
|
+
loaded: false,
|
|
69
|
+
content: undefined,
|
|
70
|
+
load: async () => {
|
|
71
|
+
if (!lazyContent.loaded) {
|
|
72
|
+
const fileContent = await fs.readFile(skillPath, 'utf-8');
|
|
73
|
+
const { body } = parseFrontmatter(fileContent);
|
|
74
|
+
lazyContent.content = `<skill-instruction>
|
|
75
|
+
Base directory for this skill: ${resolvedPath}/
|
|
76
|
+
File references (@path) in this skill are relative to this directory.
|
|
77
|
+
|
|
78
|
+
${body.trim()}
|
|
79
|
+
</skill-instruction>
|
|
80
|
+
|
|
81
|
+
<user-request>
|
|
82
|
+
$ARGUMENTS
|
|
83
|
+
</user-request>`;
|
|
84
|
+
lazyContent.loaded = true;
|
|
85
|
+
}
|
|
86
|
+
return lazyContent.content;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
return {
|
|
90
|
+
name: skillName,
|
|
91
|
+
path: skillPath,
|
|
92
|
+
resolvedPath,
|
|
93
|
+
definition: {
|
|
94
|
+
name: skillName,
|
|
95
|
+
description: formattedDescription,
|
|
96
|
+
template: ''
|
|
97
|
+
},
|
|
98
|
+
scope,
|
|
99
|
+
mcpConfig,
|
|
100
|
+
lazyContent
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Load all skills from a directory
|
|
109
|
+
*/
|
|
110
|
+
export async function loadSkillsFromDir(skillsDir, scope) {
|
|
111
|
+
const entries = await fs.readdir(skillsDir, { withFileTypes: true }).catch(() => []);
|
|
112
|
+
const skills = [];
|
|
113
|
+
for (const entry of entries) {
|
|
114
|
+
// Skip hidden files
|
|
115
|
+
if (entry.name.startsWith('.')) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const entryPath = join(skillsDir, entry.name);
|
|
119
|
+
// Handle directories (skill folders)
|
|
120
|
+
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
121
|
+
const resolvedPath = await resolveSymlinkAsync(entryPath);
|
|
122
|
+
const dirName = entry.name;
|
|
123
|
+
// Try SKILL.md first
|
|
124
|
+
const skillMdPath = join(resolvedPath, 'SKILL.md');
|
|
125
|
+
try {
|
|
126
|
+
await fs.access(skillMdPath);
|
|
127
|
+
const skill = await loadSkillFromPath(skillMdPath, resolvedPath, dirName, scope);
|
|
128
|
+
if (skill) {
|
|
129
|
+
skills.push(skill);
|
|
130
|
+
}
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// SKILL.md not found, try {dirname}.md
|
|
135
|
+
}
|
|
136
|
+
// Try {dirname}.md
|
|
137
|
+
const namedSkillMdPath = join(resolvedPath, `${dirName}.md`);
|
|
138
|
+
try {
|
|
139
|
+
await fs.access(namedSkillMdPath);
|
|
140
|
+
const skill = await loadSkillFromPath(namedSkillMdPath, resolvedPath, dirName, scope);
|
|
141
|
+
if (skill) {
|
|
142
|
+
skills.push(skill);
|
|
143
|
+
}
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
// Named skill file not found
|
|
148
|
+
}
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
// Handle standalone markdown files
|
|
152
|
+
if (isMarkdownFile(entry)) {
|
|
153
|
+
const skillName = basename(entry.name, '.md');
|
|
154
|
+
const skill = await loadSkillFromPath(entryPath, skillsDir, skillName, scope);
|
|
155
|
+
if (skill) {
|
|
156
|
+
skills.push(skill);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return skills;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Discover skills from opencode global directory (~/.config/opencode/skill/)
|
|
164
|
+
*/
|
|
165
|
+
export async function discoverOpencodeGlobalSkills() {
|
|
166
|
+
const opencodeSkillsDir = join(homedir(), '.config', 'opencode', 'skill');
|
|
167
|
+
return loadSkillsFromDir(opencodeSkillsDir, 'opencode');
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Discover skills from opencode project directory (.opencode/skill/)
|
|
171
|
+
*/
|
|
172
|
+
export async function discoverOpencodeProjectSkills() {
|
|
173
|
+
const opencodeProjectDir = join(process.cwd(), '.opencode', 'skill');
|
|
174
|
+
return loadSkillsFromDir(opencodeProjectDir, 'opencode-project');
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Discover all skills from both opencode locations
|
|
178
|
+
* Priority: project > global
|
|
179
|
+
*/
|
|
180
|
+
export async function discoverSkills() {
|
|
181
|
+
const [projectSkills, globalSkills] = await Promise.all([
|
|
182
|
+
discoverOpencodeProjectSkills(),
|
|
183
|
+
discoverOpencodeGlobalSkills()
|
|
184
|
+
]);
|
|
185
|
+
// Project skills take priority - dedupe by name
|
|
186
|
+
const skillMap = new Map();
|
|
187
|
+
// Add global skills first
|
|
188
|
+
for (const skill of globalSkills) {
|
|
189
|
+
skillMap.set(skill.name, skill);
|
|
190
|
+
}
|
|
191
|
+
// Project skills override global
|
|
192
|
+
for (const skill of projectSkills) {
|
|
193
|
+
skillMap.set(skill.name, skill);
|
|
194
|
+
}
|
|
195
|
+
return Array.from(skillMap.values());
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=skill-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-loader.js","sourceRoot":"","sources":["../src/skill-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAA;AACnC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAA;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAA;AAE5B,OAAO,EAAE,gBAAgB,EAAE,kCAAkC,EAAE,MAAM,wBAAwB,CAAA;AAE7F;;GAEG;AACH,SAAS,cAAc,CAAC,KAAuB;IAC7C,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AACnC,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,mBAAmB,CAAC,SAAiB;IAClD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;QAC7C,OAAO,QAAQ,CAAA;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,QAAgB;IAEhB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;IAE9C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QACvD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAA4B,CAAA;QAE7D,yCAAyC;QACzC,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,YAAY,IAAI,MAAM,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACxF,OAAO,MAAM,CAAC,UAA6C,CAAA;QAC7D,CAAC;QAED,0DAA0D;QAC1D,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,IAAI,MAAM,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;YAC1E,OAAO,MAAM,CAAC,GAAsC,CAAA;QACtD,CAAC;QAED,yDAAyD;QACzD,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,YAAY,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC,EAAE,CAAC;YAC5F,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAChD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,SAAS,IAAK,CAA6B,CACjF,CAAA;YACD,IAAI,eAAe,EAAE,CAAC;gBACpB,OAAO,MAAoD,CAAA;YAC7D,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,SAAiB,EACjB,YAAoB,EACpB,WAAmB,EACnB,KAAiB;IAEjB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;QACrD,MAAM,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAA;QAE1C,+CAA+C;QAC/C,MAAM,cAAc,GAAG,kCAAkC,CAAC,OAAO,CAAC,CAAA;QAClE,MAAM,UAAU,GAAG,MAAM,kBAAkB,CAAC,YAAY,CAAC,CAAA;QACzD,MAAM,SAAS,GAAG,UAAU,IAAI,cAAc,CAAA,CAAC,0BAA0B;QAEzE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,IAAI,WAAW,CAAA;QAC1C,MAAM,mBAAmB,GAAG,IAAI,CAAC,WAAW,IAAI,EAAE,CAAA;QAClD,MAAM,oBAAoB,GAAG,IAAI,KAAK,aAAa,mBAAmB,EAAE,CAAA;QAExE,6BAA6B;QAC7B,MAAM,WAAW,GAAgB;YAC/B,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,SAAS;YAClB,IAAI,EAAE,KAAK,IAAI,EAAE;gBACf,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;oBACxB,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;oBACzD,MAAM,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAA;oBAC9C,WAAW,CAAC,OAAO,GAAG;iCACC,YAAY;;;EAG3C,IAAI,CAAC,IAAI,EAAE;;;;;gBAKG,CAAA;oBACN,WAAW,CAAC,MAAM,GAAG,IAAI,CAAA;gBAC3B,CAAC;gBACD,OAAO,WAAW,CAAC,OAAQ,CAAA;YAC7B,CAAC;SACF,CAAA;QAED,OAAO;YACL,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,SAAS;YACf,YAAY;YACZ,UAAU,EAAE;gBACV,IAAI,EAAE,SAAS;gBACf,WAAW,EAAE,oBAAoB;gBACjC,QAAQ,EAAE,EAAE;aACb;YACD,KAAK;YACL,SAAS;YACT,WAAW;SACZ,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,SAAiB,EACjB,KAAiB;IAEjB,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAA;IACpF,MAAM,MAAM,GAAkB,EAAE,CAAA;IAEhC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,oBAAoB;QACpB,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/B,SAAQ;QACV,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;QAE7C,qCAAqC;QACrC,IAAI,KAAK,CAAC,WAAW,EAAE,IAAI,KAAK,CAAC,cAAc,EAAE,EAAE,CAAC;YAClD,MAAM,YAAY,GAAG,MAAM,mBAAmB,CAAC,SAAS,CAAC,CAAA;YACzD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAA;YAE1B,qBAAqB;YACrB,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,CAAA;YAClD,IAAI,CAAC;gBACH,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;gBAC5B,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,CAAC,CAAA;gBAChF,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;gBACpB,CAAC;gBACD,SAAQ;YACV,CAAC;YAAC,MAAM,CAAC;gBACP,uCAAuC;YACzC,CAAC;YAED,mBAAmB;YACnB,MAAM,gBAAgB,GAAG,IAAI,CAAC,YAAY,EAAE,GAAG,OAAO,KAAK,CAAC,CAAA;YAC5D,IAAI,CAAC;gBACH,MAAM,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAA;gBACjC,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC,gBAAgB,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,CAAC,CAAA;gBACrF,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;gBACpB,CAAC;gBACD,SAAQ;YACV,CAAC;YAAC,MAAM,CAAC;gBACP,6BAA6B;YAC/B,CAAC;YAED,SAAQ;QACV,CAAC;QAED,mCAAmC;QACnC,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;YAC7C,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,CAAA;YAC7E,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACpB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B;IAChD,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;IACzE,OAAO,iBAAiB,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAA;AACzD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,6BAA6B;IACjD,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,CAAA;IACpE,OAAO,iBAAiB,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,CAAA;AAClE,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,CAAC,aAAa,EAAE,YAAY,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACtD,6BAA6B,EAAE;QAC/B,4BAA4B,EAAE;KAC/B,CAAC,CAAA;IAEF,gDAAgD;IAChD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAuB,CAAA;IAE/C,0BAA0B;IAC1B,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;QACjC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACjC,CAAC;IAED,iCAAiC;IACjC,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;QAClC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACjC,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;AACtC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import type { McpClientInfo, McpContext, McpServerConfig } from './types.js';
|
|
3
|
+
export interface SkillMcpManager {
|
|
4
|
+
getOrCreateClient(info: McpClientInfo, config: McpServerConfig): Promise<Client>;
|
|
5
|
+
disconnectSession(sessionID: string): Promise<void>;
|
|
6
|
+
disconnectAll(): Promise<void>;
|
|
7
|
+
listTools(info: McpClientInfo, context: McpContext): Promise<unknown[]>;
|
|
8
|
+
listResources(info: McpClientInfo, context: McpContext): Promise<unknown[]>;
|
|
9
|
+
listPrompts(info: McpClientInfo, context: McpContext): Promise<unknown[]>;
|
|
10
|
+
callTool(info: McpClientInfo, context: McpContext, name: string, args: Record<string, unknown>): Promise<unknown>;
|
|
11
|
+
readResource(info: McpClientInfo, context: McpContext, uri: string): Promise<unknown>;
|
|
12
|
+
getPrompt(info: McpClientInfo, context: McpContext, name: string, args: Record<string, string>): Promise<unknown>;
|
|
13
|
+
getConnectedServers(): string[];
|
|
14
|
+
isConnected(info: McpClientInfo): boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Create a SkillMcpManager instance
|
|
18
|
+
*
|
|
19
|
+
* Features:
|
|
20
|
+
* - Connection pooling keyed by session/skill/server
|
|
21
|
+
* - Lazy connection creation
|
|
22
|
+
* - Idle cleanup after 5 minutes
|
|
23
|
+
* - Session/process cleanup
|
|
24
|
+
*/
|
|
25
|
+
export declare function createSkillMcpManager(): SkillMcpManager;
|
|
26
|
+
//# sourceMappingURL=skill-mcp-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-mcp-manager.d.ts","sourceRoot":"","sources":["../src/skill-mcp-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAA;AAElE,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAU5E,MAAM,WAAW,eAAe;IAC9B,iBAAiB,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAChF,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnD,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9B,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;IACvE,aAAa,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;IAC3E,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;IACzE,QAAQ,CACN,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,UAAU,EACnB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,OAAO,CAAC,CAAA;IACnB,YAAY,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACrF,SAAS,CACP,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,UAAU,EACnB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,OAAO,CAAC,OAAO,CAAC,CAAA;IACnB,mBAAmB,IAAI,MAAM,EAAE,CAAA;IAC/B,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAA;CAC1C;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,CA0UvD"}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
3
|
+
import { expandEnvVarsInObject, createCleanMcpEnvironment } from './utils/env-vars.js';
|
|
4
|
+
/**
|
|
5
|
+
* Create a SkillMcpManager instance
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Connection pooling keyed by session/skill/server
|
|
9
|
+
* - Lazy connection creation
|
|
10
|
+
* - Idle cleanup after 5 minutes
|
|
11
|
+
* - Session/process cleanup
|
|
12
|
+
*/
|
|
13
|
+
export function createSkillMcpManager() {
|
|
14
|
+
const clients = new Map();
|
|
15
|
+
const pendingConnections = new Map();
|
|
16
|
+
let cleanupRegistered = false;
|
|
17
|
+
let cleanupInterval = null;
|
|
18
|
+
const IDLE_TIMEOUT = 5 * 60 * 1000; // 5 minutes
|
|
19
|
+
const getClientKey = (info) => {
|
|
20
|
+
return `${info.sessionID}:${info.skillName}:${info.serverName}`;
|
|
21
|
+
};
|
|
22
|
+
const registerProcessCleanup = () => {
|
|
23
|
+
if (cleanupRegistered) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
cleanupRegistered = true;
|
|
27
|
+
const cleanup = async () => {
|
|
28
|
+
for (const [, managed] of clients) {
|
|
29
|
+
try {
|
|
30
|
+
await managed.client.close();
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Ignore cleanup errors
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
await managed.transport.close();
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Ignore cleanup errors
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
clients.clear();
|
|
43
|
+
pendingConnections.clear();
|
|
44
|
+
};
|
|
45
|
+
process.on('SIGINT', async () => {
|
|
46
|
+
await cleanup();
|
|
47
|
+
process.exit(0);
|
|
48
|
+
});
|
|
49
|
+
process.on('SIGTERM', async () => {
|
|
50
|
+
await cleanup();
|
|
51
|
+
process.exit(0);
|
|
52
|
+
});
|
|
53
|
+
if (process.platform === 'win32') {
|
|
54
|
+
process.on('SIGBREAK', async () => {
|
|
55
|
+
await cleanup();
|
|
56
|
+
process.exit(0);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const createClient = async (info, config) => {
|
|
61
|
+
const key = getClientKey(info);
|
|
62
|
+
if (!config.command) {
|
|
63
|
+
throw new Error(`MCP server "${info.serverName}" is missing required 'command' field.\n\n` +
|
|
64
|
+
`The MCP configuration in skill "${info.skillName}" must specify a command to execute.\n\n` +
|
|
65
|
+
`Example:\n` +
|
|
66
|
+
` mcp:\n` +
|
|
67
|
+
` ${info.serverName}:\n` +
|
|
68
|
+
` command: ["npx", "-y", "@some/mcp-server"]`);
|
|
69
|
+
}
|
|
70
|
+
const commandValue = config.command;
|
|
71
|
+
const commandParts = Array.isArray(commandValue)
|
|
72
|
+
? commandValue.map(String)
|
|
73
|
+
: [String(commandValue)];
|
|
74
|
+
const command = commandParts[0];
|
|
75
|
+
const args = commandParts.slice(1);
|
|
76
|
+
const mergedEnv = createCleanMcpEnvironment(config.environment);
|
|
77
|
+
registerProcessCleanup();
|
|
78
|
+
const transport = new StdioClientTransport({
|
|
79
|
+
command,
|
|
80
|
+
args,
|
|
81
|
+
env: mergedEnv,
|
|
82
|
+
stderr: 'ignore'
|
|
83
|
+
});
|
|
84
|
+
const client = new Client({ name: `skill-mcp-${info.skillName}-${info.serverName}`, version: '1.0.0' }, { capabilities: {} });
|
|
85
|
+
try {
|
|
86
|
+
await client.connect(transport);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
try {
|
|
90
|
+
await transport.close();
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Ignore cleanup errors
|
|
94
|
+
}
|
|
95
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
96
|
+
throw new Error(`Failed to connect to MCP server "${info.serverName}".\n\n` +
|
|
97
|
+
`Command: ${command} ${args.join(' ')}\n` +
|
|
98
|
+
`Reason: ${errorMessage}\n\n` +
|
|
99
|
+
`Hints:\n` +
|
|
100
|
+
` - Ensure the command is installed and available in PATH\n` +
|
|
101
|
+
` - Check if the MCP server package exists\n` +
|
|
102
|
+
` - Verify the args are correct for this server`);
|
|
103
|
+
}
|
|
104
|
+
clients.set(key, {
|
|
105
|
+
client,
|
|
106
|
+
transport,
|
|
107
|
+
skillName: info.skillName,
|
|
108
|
+
lastUsedAt: Date.now()
|
|
109
|
+
});
|
|
110
|
+
startCleanupTimer();
|
|
111
|
+
return client;
|
|
112
|
+
};
|
|
113
|
+
const getOrCreateClient = async (info, config) => {
|
|
114
|
+
const key = getClientKey(info);
|
|
115
|
+
const existing = clients.get(key);
|
|
116
|
+
if (existing) {
|
|
117
|
+
existing.lastUsedAt = Date.now();
|
|
118
|
+
return existing.client;
|
|
119
|
+
}
|
|
120
|
+
const pending = pendingConnections.get(key);
|
|
121
|
+
if (pending) {
|
|
122
|
+
return pending;
|
|
123
|
+
}
|
|
124
|
+
const expandedConfig = expandEnvVarsInObject(config);
|
|
125
|
+
const connectionPromise = createClient(info, expandedConfig);
|
|
126
|
+
pendingConnections.set(key, connectionPromise);
|
|
127
|
+
try {
|
|
128
|
+
const client = await connectionPromise;
|
|
129
|
+
return client;
|
|
130
|
+
}
|
|
131
|
+
finally {
|
|
132
|
+
pendingConnections.delete(key);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const disconnectSession = async (sessionID) => {
|
|
136
|
+
for (const [key, managed] of clients.entries()) {
|
|
137
|
+
if (key.startsWith(`${sessionID}:`)) {
|
|
138
|
+
clients.delete(key);
|
|
139
|
+
try {
|
|
140
|
+
await managed.client.close();
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// Ignore cleanup errors
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
await managed.transport.close();
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
// Ignore cleanup errors
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
const disconnectAll = async () => {
|
|
155
|
+
stopCleanupTimer();
|
|
156
|
+
const allClients = Array.from(clients.values());
|
|
157
|
+
clients.clear();
|
|
158
|
+
for (const managed of allClients) {
|
|
159
|
+
try {
|
|
160
|
+
await managed.client.close();
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
// Ignore cleanup errors
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
await managed.transport.close();
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// Ignore cleanup errors
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
const startCleanupTimer = () => {
|
|
174
|
+
if (cleanupInterval) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
cleanupInterval = setInterval(() => {
|
|
178
|
+
cleanupIdleClients();
|
|
179
|
+
}, 60000);
|
|
180
|
+
cleanupInterval.unref();
|
|
181
|
+
};
|
|
182
|
+
const stopCleanupTimer = () => {
|
|
183
|
+
if (cleanupInterval) {
|
|
184
|
+
clearInterval(cleanupInterval);
|
|
185
|
+
cleanupInterval = null;
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
const cleanupIdleClients = async () => {
|
|
189
|
+
const now = Date.now();
|
|
190
|
+
for (const [key, managed] of clients) {
|
|
191
|
+
if (now - managed.lastUsedAt > IDLE_TIMEOUT) {
|
|
192
|
+
clients.delete(key);
|
|
193
|
+
try {
|
|
194
|
+
await managed.client.close();
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// Ignore cleanup errors
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
await managed.transport.close();
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
// Ignore cleanup errors
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
const getOrCreateClientWithRetry = async (info, config) => {
|
|
209
|
+
try {
|
|
210
|
+
return await getOrCreateClient(info, config);
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
const key = getClientKey(info);
|
|
214
|
+
const existing = clients.get(key);
|
|
215
|
+
if (existing) {
|
|
216
|
+
clients.delete(key);
|
|
217
|
+
try {
|
|
218
|
+
await existing.client.close();
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
// Ignore
|
|
222
|
+
}
|
|
223
|
+
try {
|
|
224
|
+
await existing.transport.close();
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
// Ignore
|
|
228
|
+
}
|
|
229
|
+
return await getOrCreateClient(info, config);
|
|
230
|
+
}
|
|
231
|
+
throw error;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
const listTools = async (info, context) => {
|
|
235
|
+
const client = await getOrCreateClientWithRetry(info, context.config);
|
|
236
|
+
const result = await client.listTools();
|
|
237
|
+
return result.tools;
|
|
238
|
+
};
|
|
239
|
+
const listResources = async (info, context) => {
|
|
240
|
+
const client = await getOrCreateClientWithRetry(info, context.config);
|
|
241
|
+
const result = await client.listResources();
|
|
242
|
+
return result.resources;
|
|
243
|
+
};
|
|
244
|
+
const listPrompts = async (info, context) => {
|
|
245
|
+
const client = await getOrCreateClientWithRetry(info, context.config);
|
|
246
|
+
const result = await client.listPrompts();
|
|
247
|
+
return result.prompts;
|
|
248
|
+
};
|
|
249
|
+
const callTool = async (info, context, name, args) => {
|
|
250
|
+
const client = await getOrCreateClientWithRetry(info, context.config);
|
|
251
|
+
const result = await client.callTool({ name, arguments: args });
|
|
252
|
+
return result.content;
|
|
253
|
+
};
|
|
254
|
+
const readResource = async (info, context, uri) => {
|
|
255
|
+
const client = await getOrCreateClientWithRetry(info, context.config);
|
|
256
|
+
const result = await client.readResource({ uri });
|
|
257
|
+
return result.contents;
|
|
258
|
+
};
|
|
259
|
+
const getPrompt = async (info, context, name, args) => {
|
|
260
|
+
const client = await getOrCreateClientWithRetry(info, context.config);
|
|
261
|
+
const result = await client.getPrompt({ name, arguments: args });
|
|
262
|
+
return result.messages;
|
|
263
|
+
};
|
|
264
|
+
const getConnectedServers = () => {
|
|
265
|
+
return Array.from(clients.keys());
|
|
266
|
+
};
|
|
267
|
+
const isConnected = (info) => {
|
|
268
|
+
return clients.has(getClientKey(info));
|
|
269
|
+
};
|
|
270
|
+
return {
|
|
271
|
+
getOrCreateClient,
|
|
272
|
+
disconnectSession,
|
|
273
|
+
disconnectAll,
|
|
274
|
+
listTools,
|
|
275
|
+
listResources,
|
|
276
|
+
listPrompts,
|
|
277
|
+
callTool,
|
|
278
|
+
readResource,
|
|
279
|
+
getPrompt,
|
|
280
|
+
getConnectedServers,
|
|
281
|
+
isConnected
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
//# sourceMappingURL=skill-mcp-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-mcp-manager.js","sourceRoot":"","sources":["../src/skill-mcp-manager.ts"],"names":[],"mappings":"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"}
|