@agiflowai/one-mcp 0.2.5 → 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 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,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const require_http = require('./http-Q8LPwwwP.cjs');
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
5
  let liquidjs = require("liquidjs");
@@ -548,7 +548,7 @@ const initCommand = new commander.Command("init").description("Initialize MCP co
548
548
 
549
549
  //#endregion
550
550
  //#region package.json
551
- var version = "0.2.4";
551
+ var version = "0.2.5";
552
552
 
553
553
  //#endregion
554
554
  //#region src/cli.ts
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
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-BKDyW8YB.mjs";
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
5
  import { Liquid } from "liquidjs";
@@ -548,7 +548,7 @@ const initCommand = new Command("init").description("Initialize MCP configuratio
548
548
 
549
549
  //#endregion
550
550
  //#region package.json
551
- var version = "0.2.4";
551
+ var version = "0.2.5";
552
552
 
553
553
  //#endregion
554
554
  //#region src/cli.ts
@@ -1,5 +1,5 @@
1
1
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
- import { CallToolRequestSchema, ListToolsRequestSchema, isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
2
+ import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListToolsRequestSchema, isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
3
3
  import { access, mkdir, readFile, readdir, stat, unlink, writeFile } from "node:fs/promises";
4
4
  import { existsSync } from "node:fs";
5
5
  import yaml from "js-yaml";
@@ -175,10 +175,25 @@ function validateRemoteConfigSource(source) {
175
175
  * Claude Code / Claude Desktop standard MCP config format
176
176
  * This is the format users write in their config files
177
177
  */
178
+ /**
179
+ * Prompt skill configuration schema
180
+ * Converts a prompt to an executable skill
181
+ */
182
+ const PromptSkillConfigSchema = z.object({
183
+ name: z.string(),
184
+ description: z.string(),
185
+ folder: z.string().optional()
186
+ });
187
+ /**
188
+ * Prompt configuration schema
189
+ * Supports converting prompts to skills
190
+ */
191
+ const PromptConfigSchema = z.object({ skill: PromptSkillConfigSchema.optional() });
178
192
  const AdditionalConfigSchema = z.object({
179
193
  instruction: z.string().optional(),
180
194
  toolBlacklist: z.array(z.string()).optional(),
181
- omitToolDescription: z.boolean().optional()
195
+ omitToolDescription: z.boolean().optional(),
196
+ prompts: z.record(z.string(), PromptConfigSchema).optional()
182
197
  }).optional();
183
198
  const ClaudeCodeStdioServerSchema = z.object({
184
199
  command: z.string(),
@@ -245,12 +260,25 @@ const McpSseConfigSchema = z.object({
245
260
  url: z.string().url(),
246
261
  headers: z.record(z.string(), z.string()).optional()
247
262
  });
263
+ /**
264
+ * Internal prompt skill configuration schema
265
+ */
266
+ const InternalPromptSkillConfigSchema = z.object({
267
+ name: z.string(),
268
+ description: z.string(),
269
+ folder: z.string().optional()
270
+ });
271
+ /**
272
+ * Internal prompt configuration schema
273
+ */
274
+ const InternalPromptConfigSchema = z.object({ skill: InternalPromptSkillConfigSchema.optional() });
248
275
  const McpServerConfigSchema = z.discriminatedUnion("transport", [
249
276
  z.object({
250
277
  name: z.string(),
251
278
  instruction: z.string().optional(),
252
279
  toolBlacklist: z.array(z.string()).optional(),
253
280
  omitToolDescription: z.boolean().optional(),
281
+ prompts: z.record(z.string(), InternalPromptConfigSchema).optional(),
254
282
  transport: z.literal("stdio"),
255
283
  config: McpStdioConfigSchema
256
284
  }),
@@ -259,6 +287,7 @@ const McpServerConfigSchema = z.discriminatedUnion("transport", [
259
287
  instruction: z.string().optional(),
260
288
  toolBlacklist: z.array(z.string()).optional(),
261
289
  omitToolDescription: z.boolean().optional(),
290
+ prompts: z.record(z.string(), InternalPromptConfigSchema).optional(),
262
291
  transport: z.literal("http"),
263
292
  config: McpHttpConfigSchema
264
293
  }),
@@ -267,6 +296,7 @@ const McpServerConfigSchema = z.discriminatedUnion("transport", [
267
296
  instruction: z.string().optional(),
268
297
  toolBlacklist: z.array(z.string()).optional(),
269
298
  omitToolDescription: z.boolean().optional(),
299
+ prompts: z.record(z.string(), InternalPromptConfigSchema).optional(),
270
300
  transport: z.literal("sse"),
271
301
  config: McpSseConfigSchema
272
302
  })
@@ -299,6 +329,7 @@ function transformClaudeCodeConfig(claudeConfig) {
299
329
  instruction: stdioConfig.instruction || stdioConfig.config?.instruction,
300
330
  toolBlacklist: stdioConfig.config?.toolBlacklist,
301
331
  omitToolDescription: stdioConfig.config?.omitToolDescription,
332
+ prompts: stdioConfig.config?.prompts,
302
333
  transport: "stdio",
303
334
  config: {
304
335
  command: interpolatedCommand,
@@ -316,6 +347,7 @@ function transformClaudeCodeConfig(claudeConfig) {
316
347
  instruction: httpConfig.instruction || httpConfig.config?.instruction,
317
348
  toolBlacklist: httpConfig.config?.toolBlacklist,
318
349
  omitToolDescription: httpConfig.config?.omitToolDescription,
350
+ prompts: httpConfig.config?.prompts,
319
351
  transport,
320
352
  config: {
321
353
  url: interpolatedUrl,
@@ -776,12 +808,14 @@ var ConfigFetcherService = class {
776
808
  //#region src/services/McpClientManagerService.ts
777
809
  /**
778
810
  * MCP Client wrapper for managing individual server connections
811
+ * This is an internal class used by McpClientManagerService
779
812
  */
780
813
  var McpClient = class {
781
814
  serverName;
782
815
  serverInstruction;
783
816
  toolBlacklist;
784
817
  omitToolDescription;
818
+ prompts;
785
819
  transport;
786
820
  client;
787
821
  childProcess;
@@ -791,6 +825,7 @@ var McpClient = class {
791
825
  this.serverInstruction = config.instruction;
792
826
  this.toolBlacklist = config.toolBlacklist;
793
827
  this.omitToolDescription = config.omitToolDescription;
828
+ this.prompts = config.prompts;
794
829
  this.transport = transport;
795
830
  this.client = client;
796
831
  }
@@ -886,7 +921,8 @@ var McpClientManagerService = class {
886
921
  const mcpClient = new McpClient(serverName, config.transport, client, {
887
922
  instruction: config.instruction,
888
923
  toolBlacklist: config.toolBlacklist,
889
- omitToolDescription: config.omitToolDescription
924
+ omitToolDescription: config.omitToolDescription,
925
+ prompts: config.prompts
890
926
  });
891
927
  try {
892
928
  await Promise.race([this.performConnection(mcpClient, config), new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error(`Connection timeout after ${timeoutMs}ms`)), timeoutMs))]);
@@ -1289,11 +1325,11 @@ function parseToolName(toolName) {
1289
1325
 
1290
1326
  //#endregion
1291
1327
  //#region src/templates/skills-description.liquid?raw
1292
- var skills_description_default = "{% if skills.size > 0 %}\n<skills>\n<instructions>\nWhen users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.\n\nHow to use skills:\n- Invoke skills using this tool with the skill name only (no arguments)\n- When you invoke a skill, you will see <command-message>The \"{name}\" skill is loading</command-message>\n- The skill's prompt will expand and provide detailed instructions on how to complete the task\n- Examples:\n - `skill: \"pdf\"` - invoke the pdf skill\n - `skill: \"xlsx\"` - invoke the xlsx skill\n - `skill: \"ms-office-suite:pdf\"` - invoke using fully qualified name\n\nImportant:\n- Only use skills listed in <available_skills> below\n- Do not invoke a skill that is already running\n- Do not use this tool for built-in CLI commands (like /help, /clear, etc.)\n</instructions>\n\n<available_skills>\n{% for skill in skills -%}\n<skill-item><name>{{ skill.displayName }}</name><description>{{ skill.description }}</description></skill-item>\n{% endfor -%}\n</available_skills>\n</skills>\n{% endif %}\n\n<usage_instructions>\nBefore you use any tools above, you MUST call this tool with a list of tool names to learn how to use them properly before use_tool; this includes:\n- Arguments schema needed to pass to the tool use\n- Description about each tool\n\nThis tool is optimized for batch queries - you can request multiple tools at once for better performance.\n</usage_instructions>\n";
1328
+ var skills_description_default = "{% if skills.size > 0 %}\n<skills>\n<instructions>\nWhen users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.\n\nHow to use skills:\n- Invoke skills using this tool with the skill name only (no arguments)\n- When you invoke a skill, you will see <command-message>The \"{name}\" skill is loading</command-message>\n- The skill's prompt will expand and provide detailed instructions on how to complete the task\n- Examples:\n - `skill: \"pdf\"` - invoke the pdf skill\n - `skill: \"xlsx\"` - invoke the xlsx skill\n - `skill: \"ms-office-suite:pdf\"` - invoke using fully qualified name\n\nImportant:\n- Only use skills listed in <available_skills> below\n- Do not invoke a skill that is already running\n- Do not use this tool for built-in CLI commands (like /help, /clear, etc.)\n</instructions>\n\n<available_skills>\n{% for skill in skills -%}\n<item><name>{{ skill.displayName }}</name><description>{{ skill.description }}</description></item>\n{% endfor -%}\n</available_skills>\n</skills>\n{% endif %}\n";
1293
1329
 
1294
1330
  //#endregion
1295
1331
  //#region src/templates/mcp-servers-description.liquid?raw
1296
- var mcp_servers_description_default = "<mcp_servers>\n{% for server in servers -%}\n<server name=\"{{ server.name }}\">\n{% if server.instruction -%}\n<instruction>{{ server.instruction }}</instruction>\n{% endif -%}\n<tools>\n{% if server.omitToolDescription -%}\n{{ server.toolNames | join: \", \" }}\n{% else -%}\n{% for tool in server.tools -%}\n<tool-item><name>{{ tool.displayName }}</name><description>{{ tool.description | default: \"No description\" }}</description></tool-item>\n{% endfor -%}\n{% endif -%}\n</tools>\n</server>\n{% endfor -%}\n</mcp_servers>\n";
1332
+ var mcp_servers_description_default = "<mcp_servers>\n<instructions>\nBefore you use any tools above, you MUST call this tool with a list of tool names to learn how to use them properly before use_tool; this includes:\n- Arguments schema needed to pass to the tool use\n- Description about each tool\n\nThis tool is optimized for batch queries - you can request multiple tools at once for better performance.\n</instructions>\n\n{% for server in servers -%}\n<server name=\"{{ server.name }}\">\n{% if server.instruction -%}\n<instruction>{{ server.instruction }}</instruction>\n{% endif -%}\n<tools>\n{% if server.omitToolDescription -%}\n{{ server.toolNames | join: \", \" }}\n{% else -%}\n{% for tool in server.tools -%}\n<item><name>{{ tool.displayName }}</name><description>{{ tool.description | default: \"No description\" }}</description></item>\n{% endfor -%}\n{% endif -%}\n</tools>\n</server>\n{% endfor -%}\n</mcp_servers>\n";
1297
1333
 
1298
1334
  //#endregion
1299
1335
  //#region src/tools/DescribeToolsTool.ts
@@ -1333,20 +1369,96 @@ var DescribeToolsTool = class DescribeToolsTool {
1333
1369
  this.skillService = skillService;
1334
1370
  }
1335
1371
  /**
1372
+ * Collects skills derived from prompt configurations across all connected MCP servers.
1373
+ * Prompts with a skill configuration are converted to skill format for display.
1374
+ *
1375
+ * @returns Array of skill template data derived from prompts
1376
+ */
1377
+ collectPromptSkills() {
1378
+ const clients = this.clientManager.getAllClients();
1379
+ const promptSkills = [];
1380
+ for (const client of clients) {
1381
+ if (!client.prompts) continue;
1382
+ for (const promptConfig of Object.values(client.prompts)) if (promptConfig.skill) promptSkills.push({
1383
+ name: promptConfig.skill.name,
1384
+ displayName: promptConfig.skill.name,
1385
+ description: promptConfig.skill.description
1386
+ });
1387
+ }
1388
+ return promptSkills;
1389
+ }
1390
+ /**
1391
+ * Finds a prompt-based skill by name from all connected MCP servers.
1392
+ * Returns the prompt name and skill config for fetching the prompt content.
1393
+ *
1394
+ * @param skillName - The skill name to search for
1395
+ * @returns Object with serverName, promptName, and skill config, or undefined if not found
1396
+ */
1397
+ findPromptSkill(skillName) {
1398
+ if (!skillName) return void 0;
1399
+ const clients = this.clientManager.getAllClients();
1400
+ for (const client of clients) {
1401
+ if (!client.prompts) continue;
1402
+ for (const [promptName, promptConfig] of Object.entries(client.prompts)) if (promptConfig.skill && promptConfig.skill.name === skillName) return {
1403
+ serverName: client.serverName,
1404
+ promptName,
1405
+ skill: promptConfig.skill
1406
+ };
1407
+ }
1408
+ }
1409
+ /**
1410
+ * Retrieves skill content from a prompt-based skill configuration.
1411
+ * Fetches the prompt from the MCP server and extracts text content.
1412
+ *
1413
+ * @param skillName - The skill name being requested
1414
+ * @returns SkillDescription if found and successfully fetched, undefined otherwise
1415
+ */
1416
+ async getPromptSkillContent(skillName) {
1417
+ const promptSkill = this.findPromptSkill(skillName);
1418
+ if (!promptSkill) return void 0;
1419
+ const client = this.clientManager.getClient(promptSkill.serverName);
1420
+ if (!client) {
1421
+ console.error(`Client not found for server '${promptSkill.serverName}' when fetching prompt skill '${skillName}'`);
1422
+ return;
1423
+ }
1424
+ try {
1425
+ const instructions = (await client.getPrompt(promptSkill.promptName)).messages?.map((m) => {
1426
+ const content = m.content;
1427
+ if (typeof content === "string") return content;
1428
+ if (content && typeof content === "object" && "text" in content) return String(content.text);
1429
+ return "";
1430
+ }).join("\n") || "";
1431
+ return {
1432
+ name: promptSkill.skill.name,
1433
+ location: promptSkill.skill.folder || `prompt:${promptSkill.serverName}/${promptSkill.promptName}`,
1434
+ instructions
1435
+ };
1436
+ } catch (error) {
1437
+ console.error(`Failed to get prompt-based skill '${skillName}': ${error instanceof Error ? error.message : "Unknown error"}`);
1438
+ return;
1439
+ }
1440
+ }
1441
+ /**
1336
1442
  * Builds the skills section of the tool description using a Liquid template.
1337
1443
  *
1338
- * Retrieves all available skills from the SkillService and renders them
1339
- * using the skills-description.liquid template. Skills are only prefixed
1340
- * with skill__ when their name clashes with an MCP tool or another skill.
1444
+ * Retrieves all available skills from the SkillService and prompt-based skills,
1445
+ * then renders them using the skills-description.liquid template. Skills are only
1446
+ * prefixed with skill__ when their name clashes with an MCP tool or another skill.
1341
1447
  *
1342
1448
  * @param mcpToolNames - Set of MCP tool names to check for clashes
1343
1449
  * @returns Rendered skills section string with available skills list
1344
1450
  */
1345
1451
  async buildSkillsSection(mcpToolNames) {
1346
1452
  const rawSkills = this.skillService ? await this.skillService.getSkills() : [];
1453
+ const promptSkills = this.collectPromptSkills();
1454
+ const allSkillsData = [...rawSkills.map((skill) => ({
1455
+ name: skill.name,
1456
+ displayName: skill.name,
1457
+ description: skill.description
1458
+ })), ...promptSkills];
1347
1459
  const skillNameCounts = /* @__PURE__ */ new Map();
1348
- for (const skill of rawSkills) skillNameCounts.set(skill.name, (skillNameCounts.get(skill.name) || 0) + 1);
1349
- const skills = rawSkills.map((skill) => {
1460
+ for (const skill of allSkillsData) skillNameCounts.set(skill.name, (skillNameCounts.get(skill.name) || 0) + 1);
1461
+ const skills = allSkillsData.map((skill) => {
1350
1462
  const clashesWithMcpTool = mcpToolNames.has(skill.name);
1351
1463
  const clashesWithOtherSkill = (skillNameCounts.get(skill.name) || 0) > 1;
1352
1464
  const needsPrefix = clashesWithMcpTool || clashesWithOtherSkill;
@@ -1504,13 +1616,21 @@ ${skillsSection}`,
1504
1616
  const skillName = requestedName.slice(7);
1505
1617
  if (this.skillService) {
1506
1618
  const skill = await this.skillService.getSkill(skillName);
1507
- if (skill) foundSkills.push({
1508
- name: skill.name,
1509
- location: skill.basePath,
1510
- instructions: skill.content
1511
- });
1512
- else notFoundItems.push(requestedName);
1513
- } else notFoundItems.push(requestedName);
1619
+ if (skill) {
1620
+ foundSkills.push({
1621
+ name: skill.name,
1622
+ location: skill.basePath,
1623
+ instructions: skill.content
1624
+ });
1625
+ continue;
1626
+ }
1627
+ }
1628
+ const promptSkillContent = await this.getPromptSkillContent(skillName);
1629
+ if (promptSkillContent) {
1630
+ foundSkills.push(promptSkillContent);
1631
+ continue;
1632
+ }
1633
+ notFoundItems.push(requestedName);
1514
1634
  continue;
1515
1635
  }
1516
1636
  const { serverName, actualToolName } = parseToolName(requestedName);
@@ -1544,6 +1664,11 @@ ${skillsSection}`,
1544
1664
  continue;
1545
1665
  }
1546
1666
  }
1667
+ const promptSkillContent = await this.getPromptSkillContent(actualToolName);
1668
+ if (promptSkillContent) {
1669
+ foundSkills.push(promptSkillContent);
1670
+ continue;
1671
+ }
1547
1672
  notFoundItems.push(requestedName);
1548
1673
  continue;
1549
1674
  }
@@ -1652,7 +1777,7 @@ var UseToolTool = class UseToolTool {
1652
1777
  getDefinition() {
1653
1778
  return {
1654
1779
  name: UseToolTool.TOOL_NAME,
1655
- description: `Execute an MCP tool with provided arguments. You MUST call describe_tools first to discover the tool's correct arguments. Then to use tool:
1780
+ description: `Execute an MCP tool (NOT Skill) with provided arguments. You MUST call describe_tools first to discover the tool's correct arguments. Then to use tool:
1656
1781
  - Provide toolName and toolArgs based on the schema
1657
1782
  - If multiple servers provide the same tool, specify serverName
1658
1783
  `,
@@ -1691,6 +1816,37 @@ var UseToolTool = class UseToolTool {
1691
1816
  }] };
1692
1817
  }
1693
1818
  /**
1819
+ * Finds a prompt-based skill by name from all connected MCP servers.
1820
+ *
1821
+ * @param skillName - The skill name to search for
1822
+ * @returns PromptSkillMatch if found, undefined otherwise
1823
+ */
1824
+ findPromptSkill(skillName) {
1825
+ if (!skillName) return void 0;
1826
+ const clients = this.clientManager.getAllClients();
1827
+ for (const client of clients) {
1828
+ if (!client.prompts) continue;
1829
+ for (const [promptName, promptConfig] of Object.entries(client.prompts)) if (promptConfig.skill && promptConfig.skill.name === skillName) return {
1830
+ serverName: client.serverName,
1831
+ promptName,
1832
+ skill: promptConfig.skill
1833
+ };
1834
+ }
1835
+ }
1836
+ /**
1837
+ * Returns guidance message for prompt-based skill invocation.
1838
+ *
1839
+ * @param promptSkill - The prompt skill match that was found
1840
+ * @returns CallToolResult with guidance message
1841
+ */
1842
+ executePromptSkill(promptSkill) {
1843
+ const location = promptSkill.skill.folder || `prompt:${promptSkill.serverName}/${promptSkill.promptName}`;
1844
+ return { content: [{
1845
+ type: "text",
1846
+ text: `Skill "${promptSkill.skill.name}" found. Skills provide instructions and should not be executed via use_tool.\n\nUse describe_tools to view the skill details at: ${location}\n\nThen follow the skill's instructions directly.`
1847
+ }] };
1848
+ }
1849
+ /**
1694
1850
  * Executes a tool or skill based on the provided input.
1695
1851
  *
1696
1852
  * Handles three invocation patterns:
@@ -1711,22 +1867,19 @@ var UseToolTool = class UseToolTool {
1711
1867
  const { toolName: inputToolName, toolArgs = {} } = input;
1712
1868
  if (inputToolName.startsWith(SKILL_PREFIX)) {
1713
1869
  const skillName = inputToolName.slice(7);
1714
- if (!this.skillService) return {
1715
- content: [{
1716
- type: "text",
1717
- text: `Skills are not configured. Cannot execute skill "${skillName}".`
1718
- }],
1719
- isError: true
1720
- };
1721
- const skill = await this.skillService.getSkill(skillName);
1722
- if (!skill) return {
1870
+ if (this.skillService) {
1871
+ const skill = await this.skillService.getSkill(skillName);
1872
+ if (skill) return this.executeSkill(skill);
1873
+ }
1874
+ const promptSkill = this.findPromptSkill(skillName);
1875
+ if (promptSkill) return this.executePromptSkill(promptSkill);
1876
+ return {
1723
1877
  content: [{
1724
1878
  type: "text",
1725
1879
  text: `Skill "${skillName}" not found. Use describe_tools to see available skills.`
1726
1880
  }],
1727
1881
  isError: true
1728
1882
  };
1729
- return this.executeSkill(skill);
1730
1883
  }
1731
1884
  const clients = this.clientManager.getAllClients();
1732
1885
  const { serverName, actualToolName } = parseToolName(inputToolName);
@@ -1774,6 +1927,8 @@ var UseToolTool = class UseToolTool {
1774
1927
  const skill = await this.skillService.getSkill(actualToolName);
1775
1928
  if (skill) return this.executeSkill(skill);
1776
1929
  }
1930
+ const promptSkill = this.findPromptSkill(actualToolName);
1931
+ if (promptSkill) return this.executePromptSkill(promptSkill);
1777
1932
  return {
1778
1933
  content: [{
1779
1934
  type: "text",
@@ -1840,7 +1995,10 @@ async function createServer(options) {
1840
1995
  const server = new Server({
1841
1996
  name: "@agiflowai/one-mcp",
1842
1997
  version: "0.1.0"
1843
- }, { capabilities: { tools: {} } });
1998
+ }, { capabilities: {
1999
+ tools: {},
2000
+ prompts: {}
2001
+ } });
1844
2002
  const clientManager = new McpClientManagerService();
1845
2003
  let configSkills;
1846
2004
  if (options?.configFilePath) {
@@ -1891,6 +2049,60 @@ async function createServer(options) {
1891
2049
  }
1892
2050
  throw new Error(`Unknown tool: ${name}`);
1893
2051
  });
2052
+ server.setRequestHandler(ListPromptsRequestSchema, async () => {
2053
+ const clients = clientManager.getAllClients();
2054
+ const promptToServers = /* @__PURE__ */ new Map();
2055
+ const serverPromptsMap = /* @__PURE__ */ new Map();
2056
+ await Promise.all(clients.map(async (client) => {
2057
+ try {
2058
+ const prompts = await client.listPrompts();
2059
+ serverPromptsMap.set(client.serverName, prompts);
2060
+ for (const prompt of prompts) {
2061
+ if (!promptToServers.has(prompt.name)) promptToServers.set(prompt.name, []);
2062
+ promptToServers.get(prompt.name).push(client.serverName);
2063
+ }
2064
+ } catch (error) {
2065
+ console.error(`Failed to list prompts from ${client.serverName}:`, error);
2066
+ serverPromptsMap.set(client.serverName, []);
2067
+ }
2068
+ }));
2069
+ const aggregatedPrompts = [];
2070
+ for (const client of clients) {
2071
+ const prompts = serverPromptsMap.get(client.serverName) || [];
2072
+ for (const prompt of prompts) {
2073
+ const hasClash = (promptToServers.get(prompt.name) || []).length > 1;
2074
+ aggregatedPrompts.push({
2075
+ name: hasClash ? `${client.serverName}__${prompt.name}` : prompt.name,
2076
+ description: prompt.description,
2077
+ arguments: prompt.arguments
2078
+ });
2079
+ }
2080
+ }
2081
+ return { prompts: aggregatedPrompts };
2082
+ });
2083
+ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
2084
+ const { name, arguments: args } = request.params;
2085
+ const clients = clientManager.getAllClients();
2086
+ const { serverName, actualToolName: actualPromptName } = parseToolName(name);
2087
+ if (serverName) {
2088
+ const client$1 = clientManager.getClient(serverName);
2089
+ if (!client$1) throw new Error(`Server not found: ${serverName}`);
2090
+ return await client$1.getPrompt(actualPromptName, args);
2091
+ }
2092
+ const serversWithPrompt = [];
2093
+ await Promise.all(clients.map(async (client$1) => {
2094
+ try {
2095
+ if ((await client$1.listPrompts()).some((p) => p.name === name)) serversWithPrompt.push(client$1.serverName);
2096
+ } catch (error) {
2097
+ console.error(`Failed to list prompts from ${client$1.serverName}:`, error);
2098
+ }
2099
+ }));
2100
+ if (serversWithPrompt.length === 0) throw new Error(`Prompt not found: ${name}`);
2101
+ if (serversWithPrompt.length > 1) throw new Error(`Prompt "${name}" exists on multiple servers: ${serversWithPrompt.join(", ")}. Use the prefixed format (e.g., "${serversWithPrompt[0]}__${name}") to specify which server to use.`);
2102
+ const client = clientManager.getClient(serversWithPrompt[0]);
2103
+ if (!client) throw new Error(`Server not found: ${serversWithPrompt[0]}`);
2104
+ return await client.getPrompt(name, args);
2105
+ });
1894
2106
  return server;
1895
2107
  }
1896
2108
 
@@ -204,10 +204,25 @@ function validateRemoteConfigSource(source) {
204
204
  * Claude Code / Claude Desktop standard MCP config format
205
205
  * This is the format users write in their config files
206
206
  */
207
+ /**
208
+ * Prompt skill configuration schema
209
+ * Converts a prompt to an executable skill
210
+ */
211
+ const PromptSkillConfigSchema = zod.z.object({
212
+ name: zod.z.string(),
213
+ description: zod.z.string(),
214
+ folder: zod.z.string().optional()
215
+ });
216
+ /**
217
+ * Prompt configuration schema
218
+ * Supports converting prompts to skills
219
+ */
220
+ const PromptConfigSchema = zod.z.object({ skill: PromptSkillConfigSchema.optional() });
207
221
  const AdditionalConfigSchema = zod.z.object({
208
222
  instruction: zod.z.string().optional(),
209
223
  toolBlacklist: zod.z.array(zod.z.string()).optional(),
210
- omitToolDescription: zod.z.boolean().optional()
224
+ omitToolDescription: zod.z.boolean().optional(),
225
+ prompts: zod.z.record(zod.z.string(), PromptConfigSchema).optional()
211
226
  }).optional();
212
227
  const ClaudeCodeStdioServerSchema = zod.z.object({
213
228
  command: zod.z.string(),
@@ -274,12 +289,25 @@ const McpSseConfigSchema = zod.z.object({
274
289
  url: zod.z.string().url(),
275
290
  headers: zod.z.record(zod.z.string(), zod.z.string()).optional()
276
291
  });
292
+ /**
293
+ * Internal prompt skill configuration schema
294
+ */
295
+ const InternalPromptSkillConfigSchema = zod.z.object({
296
+ name: zod.z.string(),
297
+ description: zod.z.string(),
298
+ folder: zod.z.string().optional()
299
+ });
300
+ /**
301
+ * Internal prompt configuration schema
302
+ */
303
+ const InternalPromptConfigSchema = zod.z.object({ skill: InternalPromptSkillConfigSchema.optional() });
277
304
  const McpServerConfigSchema = zod.z.discriminatedUnion("transport", [
278
305
  zod.z.object({
279
306
  name: zod.z.string(),
280
307
  instruction: zod.z.string().optional(),
281
308
  toolBlacklist: zod.z.array(zod.z.string()).optional(),
282
309
  omitToolDescription: zod.z.boolean().optional(),
310
+ prompts: zod.z.record(zod.z.string(), InternalPromptConfigSchema).optional(),
283
311
  transport: zod.z.literal("stdio"),
284
312
  config: McpStdioConfigSchema
285
313
  }),
@@ -288,6 +316,7 @@ const McpServerConfigSchema = zod.z.discriminatedUnion("transport", [
288
316
  instruction: zod.z.string().optional(),
289
317
  toolBlacklist: zod.z.array(zod.z.string()).optional(),
290
318
  omitToolDescription: zod.z.boolean().optional(),
319
+ prompts: zod.z.record(zod.z.string(), InternalPromptConfigSchema).optional(),
291
320
  transport: zod.z.literal("http"),
292
321
  config: McpHttpConfigSchema
293
322
  }),
@@ -296,6 +325,7 @@ const McpServerConfigSchema = zod.z.discriminatedUnion("transport", [
296
325
  instruction: zod.z.string().optional(),
297
326
  toolBlacklist: zod.z.array(zod.z.string()).optional(),
298
327
  omitToolDescription: zod.z.boolean().optional(),
328
+ prompts: zod.z.record(zod.z.string(), InternalPromptConfigSchema).optional(),
299
329
  transport: zod.z.literal("sse"),
300
330
  config: McpSseConfigSchema
301
331
  })
@@ -328,6 +358,7 @@ function transformClaudeCodeConfig(claudeConfig) {
328
358
  instruction: stdioConfig.instruction || stdioConfig.config?.instruction,
329
359
  toolBlacklist: stdioConfig.config?.toolBlacklist,
330
360
  omitToolDescription: stdioConfig.config?.omitToolDescription,
361
+ prompts: stdioConfig.config?.prompts,
331
362
  transport: "stdio",
332
363
  config: {
333
364
  command: interpolatedCommand,
@@ -345,6 +376,7 @@ function transformClaudeCodeConfig(claudeConfig) {
345
376
  instruction: httpConfig.instruction || httpConfig.config?.instruction,
346
377
  toolBlacklist: httpConfig.config?.toolBlacklist,
347
378
  omitToolDescription: httpConfig.config?.omitToolDescription,
379
+ prompts: httpConfig.config?.prompts,
348
380
  transport,
349
381
  config: {
350
382
  url: interpolatedUrl,
@@ -805,12 +837,14 @@ var ConfigFetcherService = class {
805
837
  //#region src/services/McpClientManagerService.ts
806
838
  /**
807
839
  * MCP Client wrapper for managing individual server connections
840
+ * This is an internal class used by McpClientManagerService
808
841
  */
809
842
  var McpClient = class {
810
843
  serverName;
811
844
  serverInstruction;
812
845
  toolBlacklist;
813
846
  omitToolDescription;
847
+ prompts;
814
848
  transport;
815
849
  client;
816
850
  childProcess;
@@ -820,6 +854,7 @@ var McpClient = class {
820
854
  this.serverInstruction = config.instruction;
821
855
  this.toolBlacklist = config.toolBlacklist;
822
856
  this.omitToolDescription = config.omitToolDescription;
857
+ this.prompts = config.prompts;
823
858
  this.transport = transport;
824
859
  this.client = client;
825
860
  }
@@ -915,7 +950,8 @@ var McpClientManagerService = class {
915
950
  const mcpClient = new McpClient(serverName, config.transport, client, {
916
951
  instruction: config.instruction,
917
952
  toolBlacklist: config.toolBlacklist,
918
- omitToolDescription: config.omitToolDescription
953
+ omitToolDescription: config.omitToolDescription,
954
+ prompts: config.prompts
919
955
  });
920
956
  try {
921
957
  await Promise.race([this.performConnection(mcpClient, config), new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error(`Connection timeout after ${timeoutMs}ms`)), timeoutMs))]);
@@ -1318,11 +1354,11 @@ function parseToolName(toolName) {
1318
1354
 
1319
1355
  //#endregion
1320
1356
  //#region src/templates/skills-description.liquid?raw
1321
- var skills_description_default = "{% if skills.size > 0 %}\n<skills>\n<instructions>\nWhen users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.\n\nHow to use skills:\n- Invoke skills using this tool with the skill name only (no arguments)\n- When you invoke a skill, you will see <command-message>The \"{name}\" skill is loading</command-message>\n- The skill's prompt will expand and provide detailed instructions on how to complete the task\n- Examples:\n - `skill: \"pdf\"` - invoke the pdf skill\n - `skill: \"xlsx\"` - invoke the xlsx skill\n - `skill: \"ms-office-suite:pdf\"` - invoke using fully qualified name\n\nImportant:\n- Only use skills listed in <available_skills> below\n- Do not invoke a skill that is already running\n- Do not use this tool for built-in CLI commands (like /help, /clear, etc.)\n</instructions>\n\n<available_skills>\n{% for skill in skills -%}\n<skill-item><name>{{ skill.displayName }}</name><description>{{ skill.description }}</description></skill-item>\n{% endfor -%}\n</available_skills>\n</skills>\n{% endif %}\n\n<usage_instructions>\nBefore you use any tools above, you MUST call this tool with a list of tool names to learn how to use them properly before use_tool; this includes:\n- Arguments schema needed to pass to the tool use\n- Description about each tool\n\nThis tool is optimized for batch queries - you can request multiple tools at once for better performance.\n</usage_instructions>\n";
1357
+ var skills_description_default = "{% if skills.size > 0 %}\n<skills>\n<instructions>\nWhen users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.\n\nHow to use skills:\n- Invoke skills using this tool with the skill name only (no arguments)\n- When you invoke a skill, you will see <command-message>The \"{name}\" skill is loading</command-message>\n- The skill's prompt will expand and provide detailed instructions on how to complete the task\n- Examples:\n - `skill: \"pdf\"` - invoke the pdf skill\n - `skill: \"xlsx\"` - invoke the xlsx skill\n - `skill: \"ms-office-suite:pdf\"` - invoke using fully qualified name\n\nImportant:\n- Only use skills listed in <available_skills> below\n- Do not invoke a skill that is already running\n- Do not use this tool for built-in CLI commands (like /help, /clear, etc.)\n</instructions>\n\n<available_skills>\n{% for skill in skills -%}\n<item><name>{{ skill.displayName }}</name><description>{{ skill.description }}</description></item>\n{% endfor -%}\n</available_skills>\n</skills>\n{% endif %}\n";
1322
1358
 
1323
1359
  //#endregion
1324
1360
  //#region src/templates/mcp-servers-description.liquid?raw
1325
- var mcp_servers_description_default = "<mcp_servers>\n{% for server in servers -%}\n<server name=\"{{ server.name }}\">\n{% if server.instruction -%}\n<instruction>{{ server.instruction }}</instruction>\n{% endif -%}\n<tools>\n{% if server.omitToolDescription -%}\n{{ server.toolNames | join: \", \" }}\n{% else -%}\n{% for tool in server.tools -%}\n<tool-item><name>{{ tool.displayName }}</name><description>{{ tool.description | default: \"No description\" }}</description></tool-item>\n{% endfor -%}\n{% endif -%}\n</tools>\n</server>\n{% endfor -%}\n</mcp_servers>\n";
1361
+ var mcp_servers_description_default = "<mcp_servers>\n<instructions>\nBefore you use any tools above, you MUST call this tool with a list of tool names to learn how to use them properly before use_tool; this includes:\n- Arguments schema needed to pass to the tool use\n- Description about each tool\n\nThis tool is optimized for batch queries - you can request multiple tools at once for better performance.\n</instructions>\n\n{% for server in servers -%}\n<server name=\"{{ server.name }}\">\n{% if server.instruction -%}\n<instruction>{{ server.instruction }}</instruction>\n{% endif -%}\n<tools>\n{% if server.omitToolDescription -%}\n{{ server.toolNames | join: \", \" }}\n{% else -%}\n{% for tool in server.tools -%}\n<item><name>{{ tool.displayName }}</name><description>{{ tool.description | default: \"No description\" }}</description></item>\n{% endfor -%}\n{% endif -%}\n</tools>\n</server>\n{% endfor -%}\n</mcp_servers>\n";
1326
1362
 
1327
1363
  //#endregion
1328
1364
  //#region src/tools/DescribeToolsTool.ts
@@ -1362,20 +1398,96 @@ var DescribeToolsTool = class DescribeToolsTool {
1362
1398
  this.skillService = skillService;
1363
1399
  }
1364
1400
  /**
1401
+ * Collects skills derived from prompt configurations across all connected MCP servers.
1402
+ * Prompts with a skill configuration are converted to skill format for display.
1403
+ *
1404
+ * @returns Array of skill template data derived from prompts
1405
+ */
1406
+ collectPromptSkills() {
1407
+ const clients = this.clientManager.getAllClients();
1408
+ const promptSkills = [];
1409
+ for (const client of clients) {
1410
+ if (!client.prompts) continue;
1411
+ for (const promptConfig of Object.values(client.prompts)) if (promptConfig.skill) promptSkills.push({
1412
+ name: promptConfig.skill.name,
1413
+ displayName: promptConfig.skill.name,
1414
+ description: promptConfig.skill.description
1415
+ });
1416
+ }
1417
+ return promptSkills;
1418
+ }
1419
+ /**
1420
+ * Finds a prompt-based skill by name from all connected MCP servers.
1421
+ * Returns the prompt name and skill config for fetching the prompt content.
1422
+ *
1423
+ * @param skillName - The skill name to search for
1424
+ * @returns Object with serverName, promptName, and skill config, or undefined if not found
1425
+ */
1426
+ findPromptSkill(skillName) {
1427
+ if (!skillName) return void 0;
1428
+ const clients = this.clientManager.getAllClients();
1429
+ for (const client of clients) {
1430
+ if (!client.prompts) continue;
1431
+ for (const [promptName, promptConfig] of Object.entries(client.prompts)) if (promptConfig.skill && promptConfig.skill.name === skillName) return {
1432
+ serverName: client.serverName,
1433
+ promptName,
1434
+ skill: promptConfig.skill
1435
+ };
1436
+ }
1437
+ }
1438
+ /**
1439
+ * Retrieves skill content from a prompt-based skill configuration.
1440
+ * Fetches the prompt from the MCP server and extracts text content.
1441
+ *
1442
+ * @param skillName - The skill name being requested
1443
+ * @returns SkillDescription if found and successfully fetched, undefined otherwise
1444
+ */
1445
+ async getPromptSkillContent(skillName) {
1446
+ const promptSkill = this.findPromptSkill(skillName);
1447
+ if (!promptSkill) return void 0;
1448
+ const client = this.clientManager.getClient(promptSkill.serverName);
1449
+ if (!client) {
1450
+ console.error(`Client not found for server '${promptSkill.serverName}' when fetching prompt skill '${skillName}'`);
1451
+ return;
1452
+ }
1453
+ try {
1454
+ const instructions = (await client.getPrompt(promptSkill.promptName)).messages?.map((m) => {
1455
+ const content = m.content;
1456
+ if (typeof content === "string") return content;
1457
+ if (content && typeof content === "object" && "text" in content) return String(content.text);
1458
+ return "";
1459
+ }).join("\n") || "";
1460
+ return {
1461
+ name: promptSkill.skill.name,
1462
+ location: promptSkill.skill.folder || `prompt:${promptSkill.serverName}/${promptSkill.promptName}`,
1463
+ instructions
1464
+ };
1465
+ } catch (error) {
1466
+ console.error(`Failed to get prompt-based skill '${skillName}': ${error instanceof Error ? error.message : "Unknown error"}`);
1467
+ return;
1468
+ }
1469
+ }
1470
+ /**
1365
1471
  * Builds the skills section of the tool description using a Liquid template.
1366
1472
  *
1367
- * Retrieves all available skills from the SkillService and renders them
1368
- * using the skills-description.liquid template. Skills are only prefixed
1369
- * with skill__ when their name clashes with an MCP tool or another skill.
1473
+ * Retrieves all available skills from the SkillService and prompt-based skills,
1474
+ * then renders them using the skills-description.liquid template. Skills are only
1475
+ * prefixed with skill__ when their name clashes with an MCP tool or another skill.
1370
1476
  *
1371
1477
  * @param mcpToolNames - Set of MCP tool names to check for clashes
1372
1478
  * @returns Rendered skills section string with available skills list
1373
1479
  */
1374
1480
  async buildSkillsSection(mcpToolNames) {
1375
1481
  const rawSkills = this.skillService ? await this.skillService.getSkills() : [];
1482
+ const promptSkills = this.collectPromptSkills();
1483
+ const allSkillsData = [...rawSkills.map((skill) => ({
1484
+ name: skill.name,
1485
+ displayName: skill.name,
1486
+ description: skill.description
1487
+ })), ...promptSkills];
1376
1488
  const skillNameCounts = /* @__PURE__ */ new Map();
1377
- for (const skill of rawSkills) skillNameCounts.set(skill.name, (skillNameCounts.get(skill.name) || 0) + 1);
1378
- const skills = rawSkills.map((skill) => {
1489
+ for (const skill of allSkillsData) skillNameCounts.set(skill.name, (skillNameCounts.get(skill.name) || 0) + 1);
1490
+ const skills = allSkillsData.map((skill) => {
1379
1491
  const clashesWithMcpTool = mcpToolNames.has(skill.name);
1380
1492
  const clashesWithOtherSkill = (skillNameCounts.get(skill.name) || 0) > 1;
1381
1493
  const needsPrefix = clashesWithMcpTool || clashesWithOtherSkill;
@@ -1533,13 +1645,21 @@ ${skillsSection}`,
1533
1645
  const skillName = requestedName.slice(7);
1534
1646
  if (this.skillService) {
1535
1647
  const skill = await this.skillService.getSkill(skillName);
1536
- if (skill) foundSkills.push({
1537
- name: skill.name,
1538
- location: skill.basePath,
1539
- instructions: skill.content
1540
- });
1541
- else notFoundItems.push(requestedName);
1542
- } else notFoundItems.push(requestedName);
1648
+ if (skill) {
1649
+ foundSkills.push({
1650
+ name: skill.name,
1651
+ location: skill.basePath,
1652
+ instructions: skill.content
1653
+ });
1654
+ continue;
1655
+ }
1656
+ }
1657
+ const promptSkillContent = await this.getPromptSkillContent(skillName);
1658
+ if (promptSkillContent) {
1659
+ foundSkills.push(promptSkillContent);
1660
+ continue;
1661
+ }
1662
+ notFoundItems.push(requestedName);
1543
1663
  continue;
1544
1664
  }
1545
1665
  const { serverName, actualToolName } = parseToolName(requestedName);
@@ -1573,6 +1693,11 @@ ${skillsSection}`,
1573
1693
  continue;
1574
1694
  }
1575
1695
  }
1696
+ const promptSkillContent = await this.getPromptSkillContent(actualToolName);
1697
+ if (promptSkillContent) {
1698
+ foundSkills.push(promptSkillContent);
1699
+ continue;
1700
+ }
1576
1701
  notFoundItems.push(requestedName);
1577
1702
  continue;
1578
1703
  }
@@ -1681,7 +1806,7 @@ var UseToolTool = class UseToolTool {
1681
1806
  getDefinition() {
1682
1807
  return {
1683
1808
  name: UseToolTool.TOOL_NAME,
1684
- description: `Execute an MCP tool with provided arguments. You MUST call describe_tools first to discover the tool's correct arguments. Then to use tool:
1809
+ description: `Execute an MCP tool (NOT Skill) with provided arguments. You MUST call describe_tools first to discover the tool's correct arguments. Then to use tool:
1685
1810
  - Provide toolName and toolArgs based on the schema
1686
1811
  - If multiple servers provide the same tool, specify serverName
1687
1812
  `,
@@ -1720,6 +1845,37 @@ var UseToolTool = class UseToolTool {
1720
1845
  }] };
1721
1846
  }
1722
1847
  /**
1848
+ * Finds a prompt-based skill by name from all connected MCP servers.
1849
+ *
1850
+ * @param skillName - The skill name to search for
1851
+ * @returns PromptSkillMatch if found, undefined otherwise
1852
+ */
1853
+ findPromptSkill(skillName) {
1854
+ if (!skillName) return void 0;
1855
+ const clients = this.clientManager.getAllClients();
1856
+ for (const client of clients) {
1857
+ if (!client.prompts) continue;
1858
+ for (const [promptName, promptConfig] of Object.entries(client.prompts)) if (promptConfig.skill && promptConfig.skill.name === skillName) return {
1859
+ serverName: client.serverName,
1860
+ promptName,
1861
+ skill: promptConfig.skill
1862
+ };
1863
+ }
1864
+ }
1865
+ /**
1866
+ * Returns guidance message for prompt-based skill invocation.
1867
+ *
1868
+ * @param promptSkill - The prompt skill match that was found
1869
+ * @returns CallToolResult with guidance message
1870
+ */
1871
+ executePromptSkill(promptSkill) {
1872
+ const location = promptSkill.skill.folder || `prompt:${promptSkill.serverName}/${promptSkill.promptName}`;
1873
+ return { content: [{
1874
+ type: "text",
1875
+ text: `Skill "${promptSkill.skill.name}" found. Skills provide instructions and should not be executed via use_tool.\n\nUse describe_tools to view the skill details at: ${location}\n\nThen follow the skill's instructions directly.`
1876
+ }] };
1877
+ }
1878
+ /**
1723
1879
  * Executes a tool or skill based on the provided input.
1724
1880
  *
1725
1881
  * Handles three invocation patterns:
@@ -1740,22 +1896,19 @@ var UseToolTool = class UseToolTool {
1740
1896
  const { toolName: inputToolName, toolArgs = {} } = input;
1741
1897
  if (inputToolName.startsWith(SKILL_PREFIX)) {
1742
1898
  const skillName = inputToolName.slice(7);
1743
- if (!this.skillService) return {
1744
- content: [{
1745
- type: "text",
1746
- text: `Skills are not configured. Cannot execute skill "${skillName}".`
1747
- }],
1748
- isError: true
1749
- };
1750
- const skill = await this.skillService.getSkill(skillName);
1751
- if (!skill) return {
1899
+ if (this.skillService) {
1900
+ const skill = await this.skillService.getSkill(skillName);
1901
+ if (skill) return this.executeSkill(skill);
1902
+ }
1903
+ const promptSkill = this.findPromptSkill(skillName);
1904
+ if (promptSkill) return this.executePromptSkill(promptSkill);
1905
+ return {
1752
1906
  content: [{
1753
1907
  type: "text",
1754
1908
  text: `Skill "${skillName}" not found. Use describe_tools to see available skills.`
1755
1909
  }],
1756
1910
  isError: true
1757
1911
  };
1758
- return this.executeSkill(skill);
1759
1912
  }
1760
1913
  const clients = this.clientManager.getAllClients();
1761
1914
  const { serverName, actualToolName } = parseToolName(inputToolName);
@@ -1803,6 +1956,8 @@ var UseToolTool = class UseToolTool {
1803
1956
  const skill = await this.skillService.getSkill(actualToolName);
1804
1957
  if (skill) return this.executeSkill(skill);
1805
1958
  }
1959
+ const promptSkill = this.findPromptSkill(actualToolName);
1960
+ if (promptSkill) return this.executePromptSkill(promptSkill);
1806
1961
  return {
1807
1962
  content: [{
1808
1963
  type: "text",
@@ -1869,7 +2024,10 @@ async function createServer(options) {
1869
2024
  const server = new __modelcontextprotocol_sdk_server_index_js.Server({
1870
2025
  name: "@agiflowai/one-mcp",
1871
2026
  version: "0.1.0"
1872
- }, { capabilities: { tools: {} } });
2027
+ }, { capabilities: {
2028
+ tools: {},
2029
+ prompts: {}
2030
+ } });
1873
2031
  const clientManager = new McpClientManagerService();
1874
2032
  let configSkills;
1875
2033
  if (options?.configFilePath) {
@@ -1920,6 +2078,60 @@ async function createServer(options) {
1920
2078
  }
1921
2079
  throw new Error(`Unknown tool: ${name}`);
1922
2080
  });
2081
+ server.setRequestHandler(__modelcontextprotocol_sdk_types_js.ListPromptsRequestSchema, async () => {
2082
+ const clients = clientManager.getAllClients();
2083
+ const promptToServers = /* @__PURE__ */ new Map();
2084
+ const serverPromptsMap = /* @__PURE__ */ new Map();
2085
+ await Promise.all(clients.map(async (client) => {
2086
+ try {
2087
+ const prompts = await client.listPrompts();
2088
+ serverPromptsMap.set(client.serverName, prompts);
2089
+ for (const prompt of prompts) {
2090
+ if (!promptToServers.has(prompt.name)) promptToServers.set(prompt.name, []);
2091
+ promptToServers.get(prompt.name).push(client.serverName);
2092
+ }
2093
+ } catch (error) {
2094
+ console.error(`Failed to list prompts from ${client.serverName}:`, error);
2095
+ serverPromptsMap.set(client.serverName, []);
2096
+ }
2097
+ }));
2098
+ const aggregatedPrompts = [];
2099
+ for (const client of clients) {
2100
+ const prompts = serverPromptsMap.get(client.serverName) || [];
2101
+ for (const prompt of prompts) {
2102
+ const hasClash = (promptToServers.get(prompt.name) || []).length > 1;
2103
+ aggregatedPrompts.push({
2104
+ name: hasClash ? `${client.serverName}__${prompt.name}` : prompt.name,
2105
+ description: prompt.description,
2106
+ arguments: prompt.arguments
2107
+ });
2108
+ }
2109
+ }
2110
+ return { prompts: aggregatedPrompts };
2111
+ });
2112
+ server.setRequestHandler(__modelcontextprotocol_sdk_types_js.GetPromptRequestSchema, async (request) => {
2113
+ const { name, arguments: args } = request.params;
2114
+ const clients = clientManager.getAllClients();
2115
+ const { serverName, actualToolName: actualPromptName } = parseToolName(name);
2116
+ if (serverName) {
2117
+ const client$1 = clientManager.getClient(serverName);
2118
+ if (!client$1) throw new Error(`Server not found: ${serverName}`);
2119
+ return await client$1.getPrompt(actualPromptName, args);
2120
+ }
2121
+ const serversWithPrompt = [];
2122
+ await Promise.all(clients.map(async (client$1) => {
2123
+ try {
2124
+ if ((await client$1.listPrompts()).some((p) => p.name === name)) serversWithPrompt.push(client$1.serverName);
2125
+ } catch (error) {
2126
+ console.error(`Failed to list prompts from ${client$1.serverName}:`, error);
2127
+ }
2128
+ }));
2129
+ if (serversWithPrompt.length === 0) throw new Error(`Prompt not found: ${name}`);
2130
+ if (serversWithPrompt.length > 1) throw new Error(`Prompt "${name}" exists on multiple servers: ${serversWithPrompt.join(", ")}. Use the prefixed format (e.g., "${serversWithPrompt[0]}__${name}") to specify which server to use.`);
2131
+ const client = clientManager.getClient(serversWithPrompt[0]);
2132
+ if (!client) throw new Error(`Server not found: ${serversWithPrompt[0]}`);
2133
+ return await client.getPrompt(name, args);
2134
+ });
1923
2135
  return server;
1924
2136
  }
1925
2137
 
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const require_http = require('./http-Q8LPwwwP.cjs');
1
+ const require_http = require('./http-xSfxBa8A.cjs');
2
2
 
3
3
  exports.HttpTransportHandler = require_http.HttpTransportHandler;
4
4
  exports.SseTransportHandler = require_http.SseTransportHandler;
package/dist/index.d.cts CHANGED
@@ -130,6 +130,7 @@ type McpServerTransportConfig = McpStdioConfig | McpHttpConfig | McpSseConfig;
130
130
  * @property instruction - Optional instruction text describing the server's purpose
131
131
  * @property toolBlacklist - Optional list of tool names to exclude from this server
132
132
  * @property omitToolDescription - Whether to omit tool descriptions in listings
133
+ * @property prompts - Optional prompts configuration for skill conversion
133
134
  * @property transport - The transport type (stdio, http, or sse)
134
135
  * @property config - Transport-specific configuration options
135
136
  */
@@ -138,6 +139,7 @@ interface McpServerConfig {
138
139
  instruction?: string;
139
140
  toolBlacklist?: string[];
140
141
  omitToolDescription?: boolean;
142
+ prompts?: Record<string, PromptConfig>;
141
143
  transport: McpServerTransportType;
142
144
  config: McpServerTransportConfig;
143
145
  }
@@ -148,6 +150,24 @@ interface McpServerConfig {
148
150
  interface SkillsConfig {
149
151
  paths: string[];
150
152
  }
153
+ /**
154
+ * Prompt skill configuration for converting prompts to executable skills
155
+ * @property name - Skill name identifier
156
+ * @property description - Skill description shown in describe_tools
157
+ * @property folder - Optional folder path for skill resources
158
+ */
159
+ interface PromptSkillConfig {
160
+ name: string;
161
+ description: string;
162
+ folder?: string;
163
+ }
164
+ /**
165
+ * Prompt configuration that can be converted to a skill
166
+ * @property skill - Optional skill conversion configuration
167
+ */
168
+ interface PromptConfig {
169
+ skill?: PromptSkillConfig;
170
+ }
151
171
  /**
152
172
  * Remote configuration response containing MCP server definitions
153
173
  * @property mcpServers - Map of server names to their configurations
@@ -202,6 +222,7 @@ interface McpPromptInfo {
202
222
  * @property serverInstruction - Optional instruction text for the server
203
223
  * @property toolBlacklist - Optional list of tool names to exclude
204
224
  * @property omitToolDescription - Whether to omit tool descriptions
225
+ * @property prompts - Optional prompts configuration for skill conversion
205
226
  * @property transport - The transport type used for this connection
206
227
  */
207
228
  interface McpClientConnection {
@@ -209,6 +230,7 @@ interface McpClientConnection {
209
230
  serverInstruction?: string;
210
231
  toolBlacklist?: string[];
211
232
  omitToolDescription?: boolean;
233
+ prompts?: Record<string, PromptConfig>;
212
234
  transport: McpServerTransportType;
213
235
  /** List available tools from the server */
214
236
  listTools(): Promise<McpToolInfo[]>;
@@ -311,4 +333,4 @@ declare class HttpTransportHandler implements HttpTransportHandler$1 {
311
333
  getHost(): string;
312
334
  }
313
335
  //#endregion
314
- export { HttpTransportHandler, McpClientConnection, McpHttpConfig, McpPromptInfo, McpResourceInfo, McpServerConfig, McpServerTransportConfig, McpServerTransportType, McpSseConfig, McpStdioConfig, McpToolInfo, RemoteMcpConfiguration, type ServerOptions, Skill, SkillMetadata, SkillsConfig, SseTransportHandler, StdioTransportHandler, TRANSPORT_MODE, Tool, ToolDefinition, TransportConfig, TransportHandler, TransportMode, createServer };
336
+ export { HttpTransportHandler, McpClientConnection, McpHttpConfig, McpPromptInfo, McpResourceInfo, McpServerConfig, McpServerTransportConfig, McpServerTransportType, McpSseConfig, McpStdioConfig, McpToolInfo, PromptConfig, PromptSkillConfig, RemoteMcpConfiguration, type ServerOptions, Skill, SkillMetadata, SkillsConfig, SseTransportHandler, StdioTransportHandler, TRANSPORT_MODE, Tool, ToolDefinition, TransportConfig, TransportHandler, TransportMode, createServer };
package/dist/index.d.mts CHANGED
@@ -130,6 +130,7 @@ type McpServerTransportConfig = McpStdioConfig | McpHttpConfig | McpSseConfig;
130
130
  * @property instruction - Optional instruction text describing the server's purpose
131
131
  * @property toolBlacklist - Optional list of tool names to exclude from this server
132
132
  * @property omitToolDescription - Whether to omit tool descriptions in listings
133
+ * @property prompts - Optional prompts configuration for skill conversion
133
134
  * @property transport - The transport type (stdio, http, or sse)
134
135
  * @property config - Transport-specific configuration options
135
136
  */
@@ -138,6 +139,7 @@ interface McpServerConfig {
138
139
  instruction?: string;
139
140
  toolBlacklist?: string[];
140
141
  omitToolDescription?: boolean;
142
+ prompts?: Record<string, PromptConfig>;
141
143
  transport: McpServerTransportType;
142
144
  config: McpServerTransportConfig;
143
145
  }
@@ -148,6 +150,24 @@ interface McpServerConfig {
148
150
  interface SkillsConfig {
149
151
  paths: string[];
150
152
  }
153
+ /**
154
+ * Prompt skill configuration for converting prompts to executable skills
155
+ * @property name - Skill name identifier
156
+ * @property description - Skill description shown in describe_tools
157
+ * @property folder - Optional folder path for skill resources
158
+ */
159
+ interface PromptSkillConfig {
160
+ name: string;
161
+ description: string;
162
+ folder?: string;
163
+ }
164
+ /**
165
+ * Prompt configuration that can be converted to a skill
166
+ * @property skill - Optional skill conversion configuration
167
+ */
168
+ interface PromptConfig {
169
+ skill?: PromptSkillConfig;
170
+ }
151
171
  /**
152
172
  * Remote configuration response containing MCP server definitions
153
173
  * @property mcpServers - Map of server names to their configurations
@@ -202,6 +222,7 @@ interface McpPromptInfo {
202
222
  * @property serverInstruction - Optional instruction text for the server
203
223
  * @property toolBlacklist - Optional list of tool names to exclude
204
224
  * @property omitToolDescription - Whether to omit tool descriptions
225
+ * @property prompts - Optional prompts configuration for skill conversion
205
226
  * @property transport - The transport type used for this connection
206
227
  */
207
228
  interface McpClientConnection {
@@ -209,6 +230,7 @@ interface McpClientConnection {
209
230
  serverInstruction?: string;
210
231
  toolBlacklist?: string[];
211
232
  omitToolDescription?: boolean;
233
+ prompts?: Record<string, PromptConfig>;
212
234
  transport: McpServerTransportType;
213
235
  /** List available tools from the server */
214
236
  listTools(): Promise<McpToolInfo[]>;
@@ -311,4 +333,4 @@ declare class HttpTransportHandler implements HttpTransportHandler$1 {
311
333
  getHost(): string;
312
334
  }
313
335
  //#endregion
314
- export { HttpTransportHandler, McpClientConnection, McpHttpConfig, McpPromptInfo, McpResourceInfo, McpServerConfig, McpServerTransportConfig, McpServerTransportType, McpSseConfig, McpStdioConfig, McpToolInfo, RemoteMcpConfiguration, type ServerOptions, Skill, SkillMetadata, SkillsConfig, SseTransportHandler, StdioTransportHandler, TRANSPORT_MODE, Tool, ToolDefinition, TransportConfig, TransportHandler, TransportMode, createServer };
336
+ export { HttpTransportHandler, McpClientConnection, McpHttpConfig, McpPromptInfo, McpResourceInfo, McpServerConfig, McpServerTransportConfig, McpServerTransportType, McpSseConfig, McpStdioConfig, McpToolInfo, PromptConfig, PromptSkillConfig, RemoteMcpConfiguration, type ServerOptions, Skill, SkillMetadata, SkillsConfig, SseTransportHandler, StdioTransportHandler, TRANSPORT_MODE, Tool, ToolDefinition, TransportConfig, TransportHandler, TransportMode, createServer };
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { i as createServer, n as SseTransportHandler, r as StdioTransportHandler, t as HttpTransportHandler } from "./http-BKDyW8YB.mjs";
1
+ import { i as createServer, n as SseTransportHandler, r as StdioTransportHandler, t as HttpTransportHandler } from "./http-D9BDXhHn.mjs";
2
2
 
3
3
  export { HttpTransportHandler, SseTransportHandler, StdioTransportHandler, createServer };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agiflowai/one-mcp",
3
3
  "description": "One MCP server package",
4
- "version": "0.2.5",
4
+ "version": "0.2.6",
5
5
  "license": "AGPL-3.0",
6
6
  "keywords": [
7
7
  "mcp",
@@ -19,7 +19,7 @@
19
19
  "README.md"
20
20
  ],
21
21
  "dependencies": {
22
- "@modelcontextprotocol/sdk": "1.19.1",
22
+ "@modelcontextprotocol/sdk": "1.24.0",
23
23
  "chalk": "5.6.2",
24
24
  "commander": "14.0.1",
25
25
  "express": "^4.21.2",
@@ -27,7 +27,7 @@
27
27
  "js-yaml": "^4.1.0",
28
28
  "liquidjs": "^10.21.0",
29
29
  "zod": "^3.24.1",
30
- "@agiflowai/aicode-utils": "1.0.8"
30
+ "@agiflowai/aicode-utils": "1.0.9"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/express": "^5.0.0",
@@ -36,7 +36,7 @@
36
36
  "tsdown": "^0.16.4",
37
37
  "typescript": "5.9.3",
38
38
  "unplugin-raw": "^0.6.3",
39
- "vitest": "^2.1.8"
39
+ "vitest": "4.0.15"
40
40
  },
41
41
  "type": "module",
42
42
  "exports": {