@agiflowai/one-mcp 0.2.4 → 0.2.6
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 +129 -0
- package/dist/cli.cjs +95 -25
- package/dist/cli.mjs +95 -25
- package/dist/{http-CzQfsUEI.mjs → http-D9BDXhHn.mjs} +813 -64
- package/dist/{http-3v8zyDO3.cjs → http-xSfxBa8A.cjs} +825 -66
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +182 -18
- package/dist/index.d.mts +182 -18
- package/dist/index.mjs +1 -1
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -192,6 +192,135 @@ filesystem:
|
|
|
192
192
|
read_file, list_directory, search_files
|
|
193
193
|
```
|
|
194
194
|
|
|
195
|
+
### Skills
|
|
196
|
+
|
|
197
|
+
Skills are reusable prompt templates that provide specialized capabilities to AI agents. They are markdown files with YAML frontmatter that get loaded and made available through the `describe_tools` output.
|
|
198
|
+
|
|
199
|
+
#### Configuration
|
|
200
|
+
|
|
201
|
+
Enable skills by adding a `skills` section to your config:
|
|
202
|
+
|
|
203
|
+
```yaml
|
|
204
|
+
mcpServers:
|
|
205
|
+
# ... your MCP servers
|
|
206
|
+
|
|
207
|
+
skills:
|
|
208
|
+
paths:
|
|
209
|
+
- ".claude/skills" # Relative to config file
|
|
210
|
+
- "/absolute/path/to/skills" # Absolute paths also supported
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
#### Skill File Structure
|
|
214
|
+
|
|
215
|
+
Skills can be organized in two ways:
|
|
216
|
+
|
|
217
|
+
**Flat structure:**
|
|
218
|
+
```
|
|
219
|
+
.claude/skills/
|
|
220
|
+
├── pdf/
|
|
221
|
+
│ └── SKILL.md
|
|
222
|
+
└── data-analysis/
|
|
223
|
+
└── SKILL.md
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Skill file format (`SKILL.md`):**
|
|
227
|
+
```markdown
|
|
228
|
+
---
|
|
229
|
+
name: pdf
|
|
230
|
+
description: Create and manipulate PDF documents
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
# PDF Skill
|
|
234
|
+
|
|
235
|
+
This skill helps you work with PDF files...
|
|
236
|
+
|
|
237
|
+
## Usage
|
|
238
|
+
...
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
#### Required Frontmatter
|
|
242
|
+
|
|
243
|
+
Each `SKILL.md` must have:
|
|
244
|
+
- `name`: Unique identifier for the skill
|
|
245
|
+
- `description`: Brief description shown to AI agents
|
|
246
|
+
|
|
247
|
+
#### How Skills Work
|
|
248
|
+
|
|
249
|
+
1. Skills are discovered from configured paths at startup
|
|
250
|
+
2. Available skills are listed in the `describe_tools` output
|
|
251
|
+
3. AI agents can invoke skills by name (e.g., `skill: "pdf"`)
|
|
252
|
+
4. The skill's content expands as a prompt providing specialized instructions
|
|
253
|
+
|
|
254
|
+
#### Precedence
|
|
255
|
+
|
|
256
|
+
When multiple paths are configured, skills from earlier paths take precedence over skills with the same name from later paths.
|
|
257
|
+
|
|
258
|
+
### Prompt-Based Skills
|
|
259
|
+
|
|
260
|
+
You can also convert MCP server prompts into skills. This allows you to expose prompts from MCP servers as executable skills that AI agents can invoke.
|
|
261
|
+
|
|
262
|
+
#### Configuration
|
|
263
|
+
|
|
264
|
+
Add a `prompts` section under a server's `config`:
|
|
265
|
+
|
|
266
|
+
```yaml
|
|
267
|
+
mcpServers:
|
|
268
|
+
my-server:
|
|
269
|
+
command: npx
|
|
270
|
+
args:
|
|
271
|
+
- -y
|
|
272
|
+
- "@mycompany/mcp-server"
|
|
273
|
+
config:
|
|
274
|
+
instruction: "My MCP server"
|
|
275
|
+
prompts:
|
|
276
|
+
code-review:
|
|
277
|
+
skill:
|
|
278
|
+
name: code-reviewer
|
|
279
|
+
description: "Review code for best practices and potential issues"
|
|
280
|
+
folder: "./prompts/code-review" # Optional: resource folder
|
|
281
|
+
documentation:
|
|
282
|
+
skill:
|
|
283
|
+
name: doc-generator
|
|
284
|
+
description: "Generate documentation from code"
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
#### How Prompt-Based Skills Work
|
|
288
|
+
|
|
289
|
+
1. **Configuration**: Define which prompts should be exposed as skills in the server config
|
|
290
|
+
2. **Discovery**: Prompt-based skills appear alongside file-based skills in `describe_tools`
|
|
291
|
+
3. **Invocation**: When an AI agent requests a prompt-based skill, one-mcp:
|
|
292
|
+
- Fetches the prompt content from the MCP server
|
|
293
|
+
- Returns the prompt messages as skill instructions
|
|
294
|
+
4. **Execution**: The AI agent follows the skill instructions
|
|
295
|
+
|
|
296
|
+
#### Skill Configuration Fields
|
|
297
|
+
|
|
298
|
+
| Field | Required | Description |
|
|
299
|
+
|-------|----------|-------------|
|
|
300
|
+
| `name` | Yes | Unique skill identifier shown to AI agents |
|
|
301
|
+
| `description` | Yes | Brief description of what the skill does |
|
|
302
|
+
| `folder` | No | Optional folder path for skill resources |
|
|
303
|
+
|
|
304
|
+
#### Example Use Case
|
|
305
|
+
|
|
306
|
+
Convert a complex prompt from an MCP server into a reusable skill:
|
|
307
|
+
|
|
308
|
+
```yaml
|
|
309
|
+
mcpServers:
|
|
310
|
+
architect-mcp:
|
|
311
|
+
command: npx
|
|
312
|
+
args: ["-y", "@agiflowai/architect-mcp", "mcp-serve"]
|
|
313
|
+
config:
|
|
314
|
+
instruction: "Architecture and design patterns"
|
|
315
|
+
prompts:
|
|
316
|
+
design-review:
|
|
317
|
+
skill:
|
|
318
|
+
name: design-reviewer
|
|
319
|
+
description: "Review code architecture and suggest improvements"
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
When the AI agent invokes `design-reviewer`, it receives the full prompt content from `architect-mcp`'s `design-review` prompt, enabling sophisticated code review capabilities.
|
|
323
|
+
|
|
195
324
|
---
|
|
196
325
|
|
|
197
326
|
## MCP Tools
|
package/dist/cli.cjs
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const require_http = require('./http-
|
|
2
|
+
const require_http = require('./http-xSfxBa8A.cjs');
|
|
3
3
|
let node_fs_promises = require("node:fs/promises");
|
|
4
4
|
let node_path = require("node:path");
|
|
5
|
+
let liquidjs = require("liquidjs");
|
|
5
6
|
let commander = require("commander");
|
|
6
7
|
let __agiflowai_aicode_utils = require("@agiflowai/aicode-utils");
|
|
7
|
-
let liquidjs = require("liquidjs");
|
|
8
8
|
|
|
9
9
|
//#region src/types/index.ts
|
|
10
10
|
/**
|
|
11
|
-
* Transport mode
|
|
11
|
+
* Transport mode constants
|
|
12
12
|
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}({});
|
|
13
|
+
const TRANSPORT_MODE = {
|
|
14
|
+
STDIO: "stdio",
|
|
15
|
+
HTTP: "http",
|
|
16
|
+
SSE: "sse"
|
|
17
|
+
};
|
|
19
18
|
|
|
20
19
|
//#endregion
|
|
21
20
|
//#region src/commands/mcp-serve.ts
|
|
@@ -40,7 +39,16 @@ let TransportMode = /* @__PURE__ */ function(TransportMode$1) {
|
|
|
40
39
|
* - Not cleaning up resources on shutdown
|
|
41
40
|
*/
|
|
42
41
|
/**
|
|
42
|
+
* Type guard to validate transport type
|
|
43
|
+
* @param type - The transport type string to validate
|
|
44
|
+
* @returns True if the type is a valid transport type
|
|
45
|
+
*/
|
|
46
|
+
function isValidTransportType(type) {
|
|
47
|
+
return type === "stdio" || type === "http" || type === "sse";
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
43
50
|
* Start MCP server with given transport handler
|
|
51
|
+
* @param handler - The transport handler to start
|
|
44
52
|
*/
|
|
45
53
|
async function startServer(handler) {
|
|
46
54
|
await handler.start();
|
|
@@ -60,30 +68,30 @@ async function startServer(handler) {
|
|
|
60
68
|
/**
|
|
61
69
|
* MCP Serve command
|
|
62
70
|
*/
|
|
63
|
-
const mcpServeCommand = new commander.Command("mcp-serve").description("Start MCP server with specified transport").option("-t, --type <type>", "Transport type: stdio, http, or sse", "stdio").option("-p, --port <port>", "Port to listen on (http/sse only)", (val) => parseInt(val, 10), 3e3).option("--host <host>", "Host to bind to (http/sse only)", "localhost").option("-c, --config <path>", "Path to MCP server configuration file").option("--no-cache", "
|
|
71
|
+
const mcpServeCommand = new commander.Command("mcp-serve").description("Start MCP server with specified transport").option("-t, --type <type>", "Transport type: stdio, http, or sse", "stdio").option("-p, --port <port>", "Port to listen on (http/sse only)", (val) => parseInt(val, 10), 3e3).option("--host <host>", "Host to bind to (http/sse only)", "localhost").option("-c, --config <path>", "Path to MCP server configuration file").option("--no-cache", "Disable configuration caching, always reload from config file").action(async (options) => {
|
|
72
|
+
const transportType = options.type.toLowerCase();
|
|
73
|
+
if (!isValidTransportType(transportType)) {
|
|
74
|
+
console.error(`Unknown transport type: '${transportType}'. Valid options: stdio, http, sse`);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
64
77
|
try {
|
|
65
|
-
const transportType = options.type.toLowerCase();
|
|
66
78
|
const serverOptions = {
|
|
67
|
-
configFilePath: options.config || require_http.findConfigFile(),
|
|
79
|
+
configFilePath: options.config || require_http.findConfigFile() || void 0,
|
|
68
80
|
noCache: options.cache === false
|
|
69
81
|
};
|
|
70
82
|
if (transportType === "stdio") await startServer(new require_http.StdioTransportHandler(await require_http.createServer(serverOptions)));
|
|
71
83
|
else if (transportType === "http") await startServer(new require_http.HttpTransportHandler(await require_http.createServer(serverOptions), {
|
|
72
|
-
mode:
|
|
84
|
+
mode: TRANSPORT_MODE.HTTP,
|
|
73
85
|
port: options.port || Number(process.env.MCP_PORT) || 3e3,
|
|
74
86
|
host: options.host || process.env.MCP_HOST || "localhost"
|
|
75
87
|
}));
|
|
76
88
|
else if (transportType === "sse") await startServer(new require_http.SseTransportHandler(await require_http.createServer(serverOptions), {
|
|
77
|
-
mode:
|
|
89
|
+
mode: TRANSPORT_MODE.SSE,
|
|
78
90
|
port: options.port || Number(process.env.MCP_PORT) || 3e3,
|
|
79
91
|
host: options.host || process.env.MCP_HOST || "localhost"
|
|
80
92
|
}));
|
|
81
|
-
else {
|
|
82
|
-
console.error(`Unknown transport type: ${transportType}. Use: stdio, http, or sse`);
|
|
83
|
-
process.exit(1);
|
|
84
|
-
}
|
|
85
93
|
} catch (error) {
|
|
86
|
-
console.error(
|
|
94
|
+
console.error(`Failed to start MCP server with transport '${transportType}' on ${options.host}:${options.port}:`, error);
|
|
87
95
|
process.exit(1);
|
|
88
96
|
}
|
|
89
97
|
});
|
|
@@ -213,7 +221,11 @@ const describeToolsCommand = new commander.Command("describe-tools").description
|
|
|
213
221
|
console.error("No MCP servers connected");
|
|
214
222
|
process.exit(1);
|
|
215
223
|
}
|
|
224
|
+
const cwd = process.env.PROJECT_PATH || process.cwd();
|
|
225
|
+
const skillPaths = config.skills?.paths || [];
|
|
226
|
+
const skillService = skillPaths.length > 0 ? new require_http.SkillService(cwd, skillPaths) : void 0;
|
|
216
227
|
const foundTools = [];
|
|
228
|
+
const foundSkills = [];
|
|
217
229
|
const notFoundTools = [...toolNames];
|
|
218
230
|
for (const client of clients) {
|
|
219
231
|
if (options.server && client.serverName !== options.server) continue;
|
|
@@ -236,8 +248,30 @@ const describeToolsCommand = new commander.Command("describe-tools").description
|
|
|
236
248
|
if (!options.json) console.error(`Failed to list tools from ${client.serverName}:`, error);
|
|
237
249
|
}
|
|
238
250
|
}
|
|
251
|
+
if (skillService && notFoundTools.length > 0) {
|
|
252
|
+
const skillsToCheck = [...notFoundTools];
|
|
253
|
+
for (const toolName of skillsToCheck) {
|
|
254
|
+
const skillName = toolName.startsWith("skill__") ? toolName.slice(7) : toolName;
|
|
255
|
+
const skill = await skillService.getSkill(skillName);
|
|
256
|
+
if (skill) {
|
|
257
|
+
foundSkills.push({
|
|
258
|
+
name: skill.name,
|
|
259
|
+
location: skill.basePath,
|
|
260
|
+
instructions: skill.content
|
|
261
|
+
});
|
|
262
|
+
const idx = notFoundTools.indexOf(toolName);
|
|
263
|
+
if (idx > -1) notFoundTools.splice(idx, 1);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const nextSteps = [];
|
|
268
|
+
if (foundTools.length > 0) nextSteps.push("For MCP tools: Use the use_tool function with toolName and toolArgs based on the inputSchema above.");
|
|
269
|
+
if (foundSkills.length > 0) nextSteps.push(`For skill, just follow skill's description to continue.`);
|
|
239
270
|
if (options.json) {
|
|
240
|
-
const result = {
|
|
271
|
+
const result = {};
|
|
272
|
+
if (foundTools.length > 0) result.tools = foundTools;
|
|
273
|
+
if (foundSkills.length > 0) result.skills = foundSkills;
|
|
274
|
+
if (nextSteps.length > 0) result.nextSteps = nextSteps;
|
|
241
275
|
if (notFoundTools.length > 0) result.notFound = notFoundTools;
|
|
242
276
|
console.log(JSON.stringify(result, null, 2));
|
|
243
277
|
} else {
|
|
@@ -252,9 +286,23 @@ const describeToolsCommand = new commander.Command("describe-tools").description
|
|
|
252
286
|
console.log("");
|
|
253
287
|
}
|
|
254
288
|
}
|
|
255
|
-
if (
|
|
256
|
-
|
|
257
|
-
|
|
289
|
+
if (foundSkills.length > 0) {
|
|
290
|
+
console.log("\nFound skills:\n");
|
|
291
|
+
for (const skill of foundSkills) {
|
|
292
|
+
console.log(`Skill: ${skill.name}`);
|
|
293
|
+
console.log(`Location: ${skill.location}`);
|
|
294
|
+
console.log(`Instructions:\n${skill.instructions}`);
|
|
295
|
+
console.log("");
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (nextSteps.length > 0) {
|
|
299
|
+
console.log("\nNext steps:");
|
|
300
|
+
for (const step of nextSteps) console.log(` • ${step}`);
|
|
301
|
+
console.log("");
|
|
302
|
+
}
|
|
303
|
+
if (notFoundTools.length > 0) console.error(`\nTools/skills not found: ${notFoundTools.join(", ")}`);
|
|
304
|
+
if (foundTools.length === 0 && foundSkills.length === 0) {
|
|
305
|
+
console.error("No tools or skills found");
|
|
258
306
|
process.exit(1);
|
|
259
307
|
}
|
|
260
308
|
}
|
|
@@ -355,7 +403,29 @@ const useToolCommand = new commander.Command("use-tool").description("Execute an
|
|
|
355
403
|
if (!options.json) console.error(`Failed to list tools from ${client$1.serverName}:`, error);
|
|
356
404
|
}
|
|
357
405
|
if (matchingServers.length === 0) {
|
|
358
|
-
|
|
406
|
+
const cwd = process.env.PROJECT_PATH || process.cwd();
|
|
407
|
+
const skillPaths = config.skills?.paths || [];
|
|
408
|
+
if (skillPaths.length > 0) try {
|
|
409
|
+
const skillService = new require_http.SkillService(cwd, skillPaths);
|
|
410
|
+
const skillName = toolName.startsWith("skill__") ? toolName.slice(7) : toolName;
|
|
411
|
+
const skill = await skillService.getSkill(skillName);
|
|
412
|
+
if (skill) {
|
|
413
|
+
const result = { content: [{
|
|
414
|
+
type: "text",
|
|
415
|
+
text: skill.content
|
|
416
|
+
}] };
|
|
417
|
+
if (options.json) console.log(JSON.stringify(result, null, 2));
|
|
418
|
+
else {
|
|
419
|
+
console.log("\nSkill content:");
|
|
420
|
+
console.log(skill.content);
|
|
421
|
+
}
|
|
422
|
+
await clientManager.disconnectAll();
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
} catch (error) {
|
|
426
|
+
if (!options.json) console.error(`Failed to lookup skill "${toolName}":`, error);
|
|
427
|
+
}
|
|
428
|
+
console.error(`Tool or skill "${toolName}" not found on any connected server or configured skill paths`);
|
|
359
429
|
await clientManager.disconnectAll();
|
|
360
430
|
process.exit(1);
|
|
361
431
|
}
|
|
@@ -478,7 +548,7 @@ const initCommand = new commander.Command("init").description("Initialize MCP co
|
|
|
478
548
|
|
|
479
549
|
//#endregion
|
|
480
550
|
//#region package.json
|
|
481
|
-
var version = "0.2.
|
|
551
|
+
var version = "0.2.5";
|
|
482
552
|
|
|
483
553
|
//#endregion
|
|
484
554
|
//#region src/cli.ts
|
package/dist/cli.mjs
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as findConfigFile, i as createServer, n as SseTransportHandler, o as
|
|
2
|
+
import { a as findConfigFile, c as ConfigFetcherService, i as createServer, n as SseTransportHandler, o as SkillService, r as StdioTransportHandler, s as McpClientManagerService, t as HttpTransportHandler } from "./http-D9BDXhHn.mjs";
|
|
3
3
|
import { writeFile } from "node:fs/promises";
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
|
+
import { Liquid } from "liquidjs";
|
|
5
6
|
import { Command } from "commander";
|
|
6
7
|
import { log } from "@agiflowai/aicode-utils";
|
|
7
|
-
import { Liquid } from "liquidjs";
|
|
8
8
|
|
|
9
9
|
//#region src/types/index.ts
|
|
10
10
|
/**
|
|
11
|
-
* Transport mode
|
|
11
|
+
* Transport mode constants
|
|
12
12
|
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}({});
|
|
13
|
+
const TRANSPORT_MODE = {
|
|
14
|
+
STDIO: "stdio",
|
|
15
|
+
HTTP: "http",
|
|
16
|
+
SSE: "sse"
|
|
17
|
+
};
|
|
19
18
|
|
|
20
19
|
//#endregion
|
|
21
20
|
//#region src/commands/mcp-serve.ts
|
|
@@ -40,7 +39,16 @@ let TransportMode = /* @__PURE__ */ function(TransportMode$1) {
|
|
|
40
39
|
* - Not cleaning up resources on shutdown
|
|
41
40
|
*/
|
|
42
41
|
/**
|
|
42
|
+
* Type guard to validate transport type
|
|
43
|
+
* @param type - The transport type string to validate
|
|
44
|
+
* @returns True if the type is a valid transport type
|
|
45
|
+
*/
|
|
46
|
+
function isValidTransportType(type) {
|
|
47
|
+
return type === "stdio" || type === "http" || type === "sse";
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
43
50
|
* Start MCP server with given transport handler
|
|
51
|
+
* @param handler - The transport handler to start
|
|
44
52
|
*/
|
|
45
53
|
async function startServer(handler) {
|
|
46
54
|
await handler.start();
|
|
@@ -60,30 +68,30 @@ async function startServer(handler) {
|
|
|
60
68
|
/**
|
|
61
69
|
* MCP Serve command
|
|
62
70
|
*/
|
|
63
|
-
const mcpServeCommand = new Command("mcp-serve").description("Start MCP server with specified transport").option("-t, --type <type>", "Transport type: stdio, http, or sse", "stdio").option("-p, --port <port>", "Port to listen on (http/sse only)", (val) => parseInt(val, 10), 3e3).option("--host <host>", "Host to bind to (http/sse only)", "localhost").option("-c, --config <path>", "Path to MCP server configuration file").option("--no-cache", "
|
|
71
|
+
const mcpServeCommand = new Command("mcp-serve").description("Start MCP server with specified transport").option("-t, --type <type>", "Transport type: stdio, http, or sse", "stdio").option("-p, --port <port>", "Port to listen on (http/sse only)", (val) => parseInt(val, 10), 3e3).option("--host <host>", "Host to bind to (http/sse only)", "localhost").option("-c, --config <path>", "Path to MCP server configuration file").option("--no-cache", "Disable configuration caching, always reload from config file").action(async (options) => {
|
|
72
|
+
const transportType = options.type.toLowerCase();
|
|
73
|
+
if (!isValidTransportType(transportType)) {
|
|
74
|
+
console.error(`Unknown transport type: '${transportType}'. Valid options: stdio, http, sse`);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
64
77
|
try {
|
|
65
|
-
const transportType = options.type.toLowerCase();
|
|
66
78
|
const serverOptions = {
|
|
67
|
-
configFilePath: options.config || findConfigFile(),
|
|
79
|
+
configFilePath: options.config || findConfigFile() || void 0,
|
|
68
80
|
noCache: options.cache === false
|
|
69
81
|
};
|
|
70
82
|
if (transportType === "stdio") await startServer(new StdioTransportHandler(await createServer(serverOptions)));
|
|
71
83
|
else if (transportType === "http") await startServer(new HttpTransportHandler(await createServer(serverOptions), {
|
|
72
|
-
mode:
|
|
84
|
+
mode: TRANSPORT_MODE.HTTP,
|
|
73
85
|
port: options.port || Number(process.env.MCP_PORT) || 3e3,
|
|
74
86
|
host: options.host || process.env.MCP_HOST || "localhost"
|
|
75
87
|
}));
|
|
76
88
|
else if (transportType === "sse") await startServer(new SseTransportHandler(await createServer(serverOptions), {
|
|
77
|
-
mode:
|
|
89
|
+
mode: TRANSPORT_MODE.SSE,
|
|
78
90
|
port: options.port || Number(process.env.MCP_PORT) || 3e3,
|
|
79
91
|
host: options.host || process.env.MCP_HOST || "localhost"
|
|
80
92
|
}));
|
|
81
|
-
else {
|
|
82
|
-
console.error(`Unknown transport type: ${transportType}. Use: stdio, http, or sse`);
|
|
83
|
-
process.exit(1);
|
|
84
|
-
}
|
|
85
93
|
} catch (error) {
|
|
86
|
-
console.error(
|
|
94
|
+
console.error(`Failed to start MCP server with transport '${transportType}' on ${options.host}:${options.port}:`, error);
|
|
87
95
|
process.exit(1);
|
|
88
96
|
}
|
|
89
97
|
});
|
|
@@ -213,7 +221,11 @@ const describeToolsCommand = new Command("describe-tools").description("Describe
|
|
|
213
221
|
console.error("No MCP servers connected");
|
|
214
222
|
process.exit(1);
|
|
215
223
|
}
|
|
224
|
+
const cwd = process.env.PROJECT_PATH || process.cwd();
|
|
225
|
+
const skillPaths = config.skills?.paths || [];
|
|
226
|
+
const skillService = skillPaths.length > 0 ? new SkillService(cwd, skillPaths) : void 0;
|
|
216
227
|
const foundTools = [];
|
|
228
|
+
const foundSkills = [];
|
|
217
229
|
const notFoundTools = [...toolNames];
|
|
218
230
|
for (const client of clients) {
|
|
219
231
|
if (options.server && client.serverName !== options.server) continue;
|
|
@@ -236,8 +248,30 @@ const describeToolsCommand = new Command("describe-tools").description("Describe
|
|
|
236
248
|
if (!options.json) console.error(`Failed to list tools from ${client.serverName}:`, error);
|
|
237
249
|
}
|
|
238
250
|
}
|
|
251
|
+
if (skillService && notFoundTools.length > 0) {
|
|
252
|
+
const skillsToCheck = [...notFoundTools];
|
|
253
|
+
for (const toolName of skillsToCheck) {
|
|
254
|
+
const skillName = toolName.startsWith("skill__") ? toolName.slice(7) : toolName;
|
|
255
|
+
const skill = await skillService.getSkill(skillName);
|
|
256
|
+
if (skill) {
|
|
257
|
+
foundSkills.push({
|
|
258
|
+
name: skill.name,
|
|
259
|
+
location: skill.basePath,
|
|
260
|
+
instructions: skill.content
|
|
261
|
+
});
|
|
262
|
+
const idx = notFoundTools.indexOf(toolName);
|
|
263
|
+
if (idx > -1) notFoundTools.splice(idx, 1);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const nextSteps = [];
|
|
268
|
+
if (foundTools.length > 0) nextSteps.push("For MCP tools: Use the use_tool function with toolName and toolArgs based on the inputSchema above.");
|
|
269
|
+
if (foundSkills.length > 0) nextSteps.push(`For skill, just follow skill's description to continue.`);
|
|
239
270
|
if (options.json) {
|
|
240
|
-
const result = {
|
|
271
|
+
const result = {};
|
|
272
|
+
if (foundTools.length > 0) result.tools = foundTools;
|
|
273
|
+
if (foundSkills.length > 0) result.skills = foundSkills;
|
|
274
|
+
if (nextSteps.length > 0) result.nextSteps = nextSteps;
|
|
241
275
|
if (notFoundTools.length > 0) result.notFound = notFoundTools;
|
|
242
276
|
console.log(JSON.stringify(result, null, 2));
|
|
243
277
|
} else {
|
|
@@ -252,9 +286,23 @@ const describeToolsCommand = new Command("describe-tools").description("Describe
|
|
|
252
286
|
console.log("");
|
|
253
287
|
}
|
|
254
288
|
}
|
|
255
|
-
if (
|
|
256
|
-
|
|
257
|
-
|
|
289
|
+
if (foundSkills.length > 0) {
|
|
290
|
+
console.log("\nFound skills:\n");
|
|
291
|
+
for (const skill of foundSkills) {
|
|
292
|
+
console.log(`Skill: ${skill.name}`);
|
|
293
|
+
console.log(`Location: ${skill.location}`);
|
|
294
|
+
console.log(`Instructions:\n${skill.instructions}`);
|
|
295
|
+
console.log("");
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (nextSteps.length > 0) {
|
|
299
|
+
console.log("\nNext steps:");
|
|
300
|
+
for (const step of nextSteps) console.log(` • ${step}`);
|
|
301
|
+
console.log("");
|
|
302
|
+
}
|
|
303
|
+
if (notFoundTools.length > 0) console.error(`\nTools/skills not found: ${notFoundTools.join(", ")}`);
|
|
304
|
+
if (foundTools.length === 0 && foundSkills.length === 0) {
|
|
305
|
+
console.error("No tools or skills found");
|
|
258
306
|
process.exit(1);
|
|
259
307
|
}
|
|
260
308
|
}
|
|
@@ -355,7 +403,29 @@ const useToolCommand = new Command("use-tool").description("Execute an MCP tool
|
|
|
355
403
|
if (!options.json) console.error(`Failed to list tools from ${client$1.serverName}:`, error);
|
|
356
404
|
}
|
|
357
405
|
if (matchingServers.length === 0) {
|
|
358
|
-
|
|
406
|
+
const cwd = process.env.PROJECT_PATH || process.cwd();
|
|
407
|
+
const skillPaths = config.skills?.paths || [];
|
|
408
|
+
if (skillPaths.length > 0) try {
|
|
409
|
+
const skillService = new SkillService(cwd, skillPaths);
|
|
410
|
+
const skillName = toolName.startsWith("skill__") ? toolName.slice(7) : toolName;
|
|
411
|
+
const skill = await skillService.getSkill(skillName);
|
|
412
|
+
if (skill) {
|
|
413
|
+
const result = { content: [{
|
|
414
|
+
type: "text",
|
|
415
|
+
text: skill.content
|
|
416
|
+
}] };
|
|
417
|
+
if (options.json) console.log(JSON.stringify(result, null, 2));
|
|
418
|
+
else {
|
|
419
|
+
console.log("\nSkill content:");
|
|
420
|
+
console.log(skill.content);
|
|
421
|
+
}
|
|
422
|
+
await clientManager.disconnectAll();
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
} catch (error) {
|
|
426
|
+
if (!options.json) console.error(`Failed to lookup skill "${toolName}":`, error);
|
|
427
|
+
}
|
|
428
|
+
console.error(`Tool or skill "${toolName}" not found on any connected server or configured skill paths`);
|
|
359
429
|
await clientManager.disconnectAll();
|
|
360
430
|
process.exit(1);
|
|
361
431
|
}
|
|
@@ -478,7 +548,7 @@ const initCommand = new Command("init").description("Initialize MCP configuratio
|
|
|
478
548
|
|
|
479
549
|
//#endregion
|
|
480
550
|
//#region package.json
|
|
481
|
-
var version = "0.2.
|
|
551
|
+
var version = "0.2.5";
|
|
482
552
|
|
|
483
553
|
//#endregion
|
|
484
554
|
//#region src/cli.ts
|