@agiflowai/one-mcp 0.3.0 → 0.3.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/cli.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const require_http = require('./http-BYBRKvD4.cjs');
2
+ const require_http = require('./http-C4IfZSwW.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");
@@ -69,7 +69,7 @@ async function startServer(handler) {
69
69
  /**
70
70
  * MCP Serve command
71
71
  */
72
- 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 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").option("--id <id>", "Unique server identifier (overrides config file id, auto-generated if not provided)").action(async (options) => {
73
73
  const transportType = options.type.toLowerCase();
74
74
  if (!isValidTransportType(transportType)) {
75
75
  console.error(`Unknown transport type: '${transportType}'. Valid options: stdio, http, sse`);
@@ -78,7 +78,8 @@ const mcpServeCommand = new commander.Command("mcp-serve").description("Start MC
78
78
  try {
79
79
  const serverOptions = {
80
80
  configFilePath: options.config || require_http.findConfigFile() || void 0,
81
- noCache: options.cache === false
81
+ noCache: options.cache === false,
82
+ serverId: options.id
82
83
  };
83
84
  if (transportType === "stdio") await startServer(new require_http.StdioTransportHandler(await require_http.createServer(serverOptions)));
84
85
  else if (transportType === "http") await startServer(new require_http.HttpTransportHandler(await require_http.createServer(serverOptions), {
@@ -1002,7 +1003,7 @@ const prefetchCommand = new commander.Command("prefetch").description("Pre-downl
1002
1003
 
1003
1004
  //#endregion
1004
1005
  //#region package.json
1005
- var version = "0.2.2";
1006
+ var version = "0.3.0";
1006
1007
 
1007
1008
  //#endregion
1008
1009
  //#region src/cli.ts
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as SkillService, c as ConfigFetcherService, i as createServer, n as SseTransportHandler, o as findConfigFile, r as StdioTransportHandler, s as McpClientManagerService, t as HttpTransportHandler } from "./http-Bi2N9PUM.mjs";
2
+ import { a as SkillService, c as ConfigFetcherService, i as createServer, n as SseTransportHandler, o as findConfigFile, r as StdioTransportHandler, s as McpClientManagerService, t as HttpTransportHandler } from "./http-xi_ha63Y.mjs";
3
3
  import { writeFile } from "node:fs/promises";
4
4
  import { resolve } from "node:path";
5
5
  import { Liquid } from "liquidjs";
@@ -69,7 +69,7 @@ async function startServer(handler) {
69
69
  /**
70
70
  * MCP Serve command
71
71
  */
72
- 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 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").option("--id <id>", "Unique server identifier (overrides config file id, auto-generated if not provided)").action(async (options) => {
73
73
  const transportType = options.type.toLowerCase();
74
74
  if (!isValidTransportType(transportType)) {
75
75
  console.error(`Unknown transport type: '${transportType}'. Valid options: stdio, http, sse`);
@@ -78,7 +78,8 @@ const mcpServeCommand = new Command("mcp-serve").description("Start MCP server w
78
78
  try {
79
79
  const serverOptions = {
80
80
  configFilePath: options.config || findConfigFile() || void 0,
81
- noCache: options.cache === false
81
+ noCache: options.cache === false,
82
+ serverId: options.id
82
83
  };
83
84
  if (transportType === "stdio") await startServer(new StdioTransportHandler(await createServer(serverOptions)));
84
85
  else if (transportType === "http") await startServer(new HttpTransportHandler(await createServer(serverOptions), {
@@ -1002,7 +1003,7 @@ const prefetchCommand = new Command("prefetch").description("Pre-download packag
1002
1003
 
1003
1004
  //#endregion
1004
1005
  //#region package.json
1005
- var version = "0.2.2";
1006
+ var version = "0.3.0";
1006
1007
 
1007
1008
  //#endregion
1008
1009
  //#region src/cli.ts
@@ -271,6 +271,7 @@ const SkillsConfigSchema = zod.z.object({ paths: zod.z.array(zod.z.string()) });
271
271
  * Full Claude Code MCP configuration schema
272
272
  */
273
273
  const ClaudeCodeMcpConfigSchema = zod.z.object({
274
+ id: zod.z.string().optional(),
274
275
  mcpServers: zod.z.record(zod.z.string(), ClaudeCodeServerConfigSchema),
275
276
  remoteConfigs: zod.z.array(RemoteConfigSourceSchema).optional(),
276
277
  skills: SkillsConfigSchema.optional()
@@ -340,6 +341,7 @@ const McpServerConfigSchema = zod.z.discriminatedUnion("transport", [
340
341
  * Full internal MCP configuration schema
341
342
  */
342
343
  const InternalMcpConfigSchema = zod.z.object({
344
+ id: zod.z.string().optional(),
343
345
  mcpServers: zod.z.record(zod.z.string(), McpServerConfigSchema),
344
346
  skills: SkillsConfigSchema.optional()
345
347
  });
@@ -394,6 +396,7 @@ function transformClaudeCodeConfig(claudeConfig) {
394
396
  }
395
397
  }
396
398
  return {
399
+ id: claudeConfig.id,
397
400
  mcpServers: transformedServers,
398
401
  skills: claudeConfig.skills
399
402
  };
@@ -1248,6 +1251,71 @@ function extractSkillFrontMatter(content) {
1248
1251
  return null;
1249
1252
  }
1250
1253
 
1254
+ //#endregion
1255
+ //#region src/utils/generateServerId.ts
1256
+ /**
1257
+ * generateServerId Utilities
1258
+ *
1259
+ * DESIGN PATTERNS:
1260
+ * - Pure functions with no side effects
1261
+ * - Single responsibility per function
1262
+ * - Functional programming approach
1263
+ *
1264
+ * CODING STANDARDS:
1265
+ * - Export individual functions, not classes
1266
+ * - Use descriptive function names with verbs
1267
+ * - Add JSDoc comments for complex logic
1268
+ * - Keep functions small and focused
1269
+ *
1270
+ * AVOID:
1271
+ * - Side effects (mutating external state)
1272
+ * - Stateful logic (use services for state)
1273
+ * - Complex external dependencies
1274
+ */
1275
+ /**
1276
+ * Character set for generating human-readable IDs.
1277
+ * Excludes confusing characters: 0, O, 1, l, I
1278
+ */
1279
+ const CHARSET = "23456789abcdefghjkmnpqrstuvwxyz";
1280
+ /**
1281
+ * Default length for generated server IDs (6 characters)
1282
+ */
1283
+ const DEFAULT_ID_LENGTH = 6;
1284
+ /**
1285
+ * Generate a short, human-readable server ID.
1286
+ *
1287
+ * Uses Node.js crypto.randomBytes for cryptographically secure randomness
1288
+ * with rejection sampling to avoid modulo bias.
1289
+ *
1290
+ * The generated ID:
1291
+ * - Is 6 characters long by default
1292
+ * - Uses only lowercase alphanumeric characters
1293
+ * - Excludes confusing characters (0, O, 1, l, I)
1294
+ *
1295
+ * @param length - Length of the ID to generate (default: 6)
1296
+ * @returns A random, human-readable ID
1297
+ *
1298
+ * @example
1299
+ * generateServerId() // "abc234"
1300
+ * generateServerId(4) // "x7mn"
1301
+ */
1302
+ function generateServerId(length = DEFAULT_ID_LENGTH) {
1303
+ const charsetLength = 31;
1304
+ const maxUnbiased = Math.floor(256 / charsetLength) * charsetLength - 1;
1305
+ let result = "";
1306
+ let remaining = length;
1307
+ while (remaining > 0) {
1308
+ const bytes = (0, node_crypto.randomBytes)(remaining);
1309
+ for (let i = 0; i < bytes.length && remaining > 0; i++) {
1310
+ const byte = bytes[i];
1311
+ if (byte > maxUnbiased) continue;
1312
+ result += CHARSET[byte % charsetLength];
1313
+ remaining--;
1314
+ }
1315
+ }
1316
+ return result;
1317
+ }
1318
+
1251
1319
  //#endregion
1252
1320
  //#region src/services/SkillService.ts
1253
1321
  /**
@@ -1525,7 +1593,7 @@ var SkillService = class {
1525
1593
  * Prefix added to skill names when they clash with MCP tool names.
1526
1594
  * This ensures skills can be uniquely identified even when a tool has the same name.
1527
1595
  */
1528
- const SKILL_PREFIX$1 = "skill__";
1596
+ const SKILL_PREFIX = "skill__";
1529
1597
  /**
1530
1598
  * Log prefix for skill detection messages.
1531
1599
  * Used to easily filter skill detection logs in stderr output.
@@ -1536,10 +1604,15 @@ const LOG_PREFIX_SKILL_DETECTION = "[skill-detection]";
1536
1604
  * Format: "prompt:{serverName}:{promptName}"
1537
1605
  */
1538
1606
  const PROMPT_LOCATION_PREFIX = "prompt:";
1607
+ /**
1608
+ * Default server ID used when no ID is provided via CLI or config.
1609
+ * This fallback is used when auto-generation also fails.
1610
+ */
1611
+ const DEFAULT_SERVER_ID = "unknown";
1539
1612
 
1540
1613
  //#endregion
1541
1614
  //#region src/templates/toolkit-description.liquid?raw
1542
- var toolkit_description_default = "<toolkit>\n<instruction>\nBefore you use any capabilities below, you MUST call this tool with a list of names to learn how to use them properly; this includes:\n- For tools: Arguments schema needed to pass to use_tool\n- For skills: Detailed instructions that will expand when invoked (Prefer to be explored first when relevant)\n\nThis tool is optimized for batch queries - you can request multiple capabilities at once for better performance.\n\nHow to invoke:\n- For MCP tools: Use use_tool with toolName and toolArgs based on the schema\n- For skills: Use this tool with the skill name to get expanded instructions\n</instruction>\n\n<available_capabilities>\n{% for server in servers -%}\n<group name=\"{{ server.name }}\">\n{% if server.instruction -%}\n<group_instruction>{{ server.instruction }}</group_instruction>\n{% endif -%}\n{% if server.omitToolDescription -%}\n{% for toolName in server.toolNames -%}\n<item name=\"{{ toolName }}\"></item>\n{% endfor -%}\n{% else -%}\n{% for tool in server.tools -%}\n<item name=\"{{ tool.displayName }}\"><description>{{ tool.description | default: \"No description\" }}</description></item>\n{% endfor -%}\n{% endif -%}\n</group>\n{% endfor -%}\n{% if skills.size > 0 -%}\n<group name=\"skills\">\n{% for skill in skills -%}\n<item name=\"{{ skill.displayName }}\"><description>{{ skill.description }}</description></item>\n{% endfor -%}\n</group>\n{% endif -%}\n</available_capabilities>\n</toolkit>\n";
1615
+ var toolkit_description_default = "<toolkit id=\"{{ serverId }}\">\n<instruction>\nBefore you use any capabilities below, you MUST call this tool with a list of names to learn how to use them properly; this includes:\n- For tools: Arguments schema needed to pass to use_tool\n- For skills: Detailed instructions that will expand when invoked (Prefer to be explored first when relevant)\n\nThis tool is optimized for batch queries - you can request multiple capabilities at once for better performance.\n\nHow to invoke:\n- For MCP tools: Use use_tool with toolName and toolArgs based on the schema\n- For skills: Use this tool with the skill name to get expanded instructions\n</instruction>\n\n<available_capabilities>\n{% for server in servers -%}\n<group name=\"{{ server.name }}\">\n{% if server.instruction -%}\n<group_instruction>{{ server.instruction }}</group_instruction>\n{% endif -%}\n{% if server.omitToolDescription -%}\n{% for toolName in server.toolNames -%}\n<item name=\"{{ toolName }}\"></item>\n{% endfor -%}\n{% else -%}\n{% for tool in server.tools -%}\n<item name=\"{{ tool.displayName }}\"><description>{{ tool.description | default: \"No description\" }}</description></item>\n{% endfor -%}\n{% endif -%}\n</group>\n{% endfor -%}\n{% if skills.size > 0 -%}\n<group name=\"skills\">\n{% for skill in skills -%}\n<item name=\"{{ skill.displayName }}\"><description>{{ skill.description }}</description></item>\n{% endfor -%}\n</group>\n{% endif -%}\n</available_capabilities>\n</toolkit>\n";
1543
1616
 
1544
1617
  //#endregion
1545
1618
  //#region src/tools/DescribeToolsTool.ts
@@ -1578,14 +1651,18 @@ var DescribeToolsTool = class DescribeToolsTool {
1578
1651
  liquid = new liquidjs.Liquid();
1579
1652
  /** Cache for auto-detected skills from prompt front-matter */
1580
1653
  autoDetectedSkillsCache = null;
1654
+ /** Unique server identifier for this one-mcp instance */
1655
+ serverId;
1581
1656
  /**
1582
1657
  * Creates a new DescribeToolsTool instance
1583
1658
  * @param clientManager - The MCP client manager for accessing remote servers
1584
1659
  * @param skillService - Optional skill service for loading skills
1660
+ * @param serverId - Unique server identifier for this one-mcp instance
1585
1661
  */
1586
- constructor(clientManager, skillService) {
1662
+ constructor(clientManager, skillService, serverId) {
1587
1663
  this.clientManager = clientManager;
1588
1664
  this.skillService = skillService;
1665
+ this.serverId = serverId || DEFAULT_SERVER_ID;
1589
1666
  }
1590
1667
  /**
1591
1668
  * Clears the cached auto-detected skills from prompt front-matter.
@@ -1810,14 +1887,15 @@ var DescribeToolsTool = class DescribeToolsTool {
1810
1887
  const clashesWithMcpTool = allToolNames.has(skill.name);
1811
1888
  return {
1812
1889
  name: skill.name,
1813
- displayName: clashesWithMcpTool ? `${SKILL_PREFIX$1}${skill.name}` : skill.name,
1890
+ displayName: clashesWithMcpTool ? `${SKILL_PREFIX}${skill.name}` : skill.name,
1814
1891
  description: skill.description
1815
1892
  };
1816
1893
  });
1817
1894
  return {
1818
1895
  content: await this.liquid.parseAndRender(toolkit_description_default, {
1819
1896
  servers,
1820
- skills
1897
+ skills,
1898
+ serverId: this.serverId
1821
1899
  }),
1822
1900
  toolNames: allToolNames
1823
1901
  };
@@ -1903,8 +1981,8 @@ var DescribeToolsTool = class DescribeToolsTool {
1903
1981
  const foundSkills = [];
1904
1982
  const notFoundItems = [];
1905
1983
  for (const requestedName of toolNames) {
1906
- if (requestedName.startsWith(SKILL_PREFIX$1)) {
1907
- const skillName = requestedName.slice(SKILL_PREFIX$1.length);
1984
+ if (requestedName.startsWith(SKILL_PREFIX)) {
1985
+ const skillName = requestedName.slice(SKILL_PREFIX.length);
1908
1986
  if (this.skillService) {
1909
1987
  const skill = await this.skillService.getSkill(skillName);
1910
1988
  if (skill) {
@@ -2028,10 +2106,6 @@ var DescribeToolsTool = class DescribeToolsTool {
2028
2106
  //#endregion
2029
2107
  //#region src/tools/UseToolTool.ts
2030
2108
  /**
2031
- * Prefix used to identify skill invocations (e.g., skill__pdf)
2032
- */
2033
- const SKILL_PREFIX = "skill__";
2034
- /**
2035
2109
  * UseToolTool executes MCP tools and skills with proper error handling.
2036
2110
  *
2037
2111
  * This tool supports three invocation patterns:
@@ -2048,14 +2122,18 @@ var UseToolTool = class UseToolTool {
2048
2122
  static TOOL_NAME = "use_tool";
2049
2123
  clientManager;
2050
2124
  skillService;
2125
+ /** Unique server identifier for this one-mcp instance */
2126
+ serverId;
2051
2127
  /**
2052
2128
  * Creates a new UseToolTool instance
2053
2129
  * @param clientManager - The MCP client manager for accessing remote servers
2054
2130
  * @param skillService - Optional skill service for loading and executing skills
2131
+ * @param serverId - Unique server identifier for this one-mcp instance
2055
2132
  */
2056
- constructor(clientManager, skillService) {
2133
+ constructor(clientManager, skillService, serverId) {
2057
2134
  this.clientManager = clientManager;
2058
2135
  this.skillService = skillService;
2136
+ this.serverId = serverId || DEFAULT_SERVER_ID;
2059
2137
  }
2060
2138
  /**
2061
2139
  * Returns the MCP tool definition with name, description, and input schema.
@@ -2071,6 +2149,8 @@ var UseToolTool = class UseToolTool {
2071
2149
  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:
2072
2150
  - Provide toolName and toolArgs based on the schema
2073
2151
  - If multiple servers provide the same tool, specify serverName
2152
+
2153
+ IMPORTANT: Only use tools discovered from describe_tools with id="${this.serverId}".
2074
2154
  `,
2075
2155
  inputSchema: {
2076
2156
  type: "object",
@@ -2157,7 +2237,7 @@ var UseToolTool = class UseToolTool {
2157
2237
  try {
2158
2238
  const { toolName: inputToolName, toolArgs = {} } = input;
2159
2239
  if (inputToolName.startsWith(SKILL_PREFIX)) {
2160
- const skillName = inputToolName.slice(7);
2240
+ const skillName = inputToolName.slice(SKILL_PREFIX.length);
2161
2241
  if (this.skillService) {
2162
2242
  const skill = await this.skillService.getSkill(skillName);
2163
2243
  if (skill) return this.executeSkill(skill);
@@ -2292,6 +2372,7 @@ async function createServer(options) {
2292
2372
  } });
2293
2373
  const clientManager = new McpClientManagerService();
2294
2374
  let configSkills;
2375
+ let configId;
2295
2376
  if (options?.configFilePath) {
2296
2377
  let config;
2297
2378
  try {
@@ -2303,6 +2384,7 @@ async function createServer(options) {
2303
2384
  throw new Error(`Failed to load MCP configuration from '${options.configFilePath}': ${error instanceof Error ? error.message : String(error)}`);
2304
2385
  }
2305
2386
  configSkills = config.skills;
2387
+ configId = config.id;
2306
2388
  const failedConnections = [];
2307
2389
  const connectionPromises = Object.entries(config.mcpServers).map(async ([serverName, serverConfig]) => {
2308
2390
  try {
@@ -2321,13 +2403,15 @@ async function createServer(options) {
2321
2403
  if (failedConnections.length > 0 && failedConnections.length < Object.keys(config.mcpServers).length) console.error(`Warning: Some MCP server connections failed: ${failedConnections.map((f) => f.serverName).join(", ")}`);
2322
2404
  if (failedConnections.length > 0 && failedConnections.length === Object.keys(config.mcpServers).length) throw new Error(`All MCP server connections failed: ${failedConnections.map((f) => `${f.serverName}: ${f.error.message}`).join(", ")}`);
2323
2405
  }
2406
+ const serverId = options?.serverId || configId || generateServerId();
2407
+ console.error(`[one-mcp] Server ID: ${serverId}`);
2324
2408
  const skillsConfig = options?.skills || configSkills;
2325
2409
  const toolsRef = { describeTools: null };
2326
2410
  const skillService = skillsConfig && skillsConfig.paths.length > 0 ? new SkillService(process.cwd(), skillsConfig.paths, { onCacheInvalidated: () => {
2327
2411
  toolsRef.describeTools?.clearAutoDetectedSkillsCache();
2328
2412
  } }) : void 0;
2329
- const describeTools = new DescribeToolsTool(clientManager, skillService);
2330
- const useTool = new UseToolTool(clientManager, skillService);
2413
+ const describeTools = new DescribeToolsTool(clientManager, skillService, serverId);
2414
+ const useTool = new UseToolTool(clientManager, skillService, serverId);
2331
2415
  toolsRef.describeTools = describeTools;
2332
2416
  if (skillService) skillService.startWatching().catch((error) => {
2333
2417
  console.error(`[skill-watcher] File watcher failed (non-critical): ${error instanceof Error ? error.message : "Unknown error"}`);
@@ -4,7 +4,7 @@ import { access, mkdir, readFile, readdir, stat, unlink, watch, writeFile } from
4
4
  import { existsSync } from "node:fs";
5
5
  import yaml from "js-yaml";
6
6
  import { z } from "zod";
7
- import { createHash, randomUUID } from "node:crypto";
7
+ import { createHash, randomBytes, randomUUID } from "node:crypto";
8
8
  import { dirname, isAbsolute, join, resolve } from "node:path";
9
9
  import { tmpdir } from "node:os";
10
10
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
@@ -242,6 +242,7 @@ const SkillsConfigSchema = z.object({ paths: z.array(z.string()) });
242
242
  * Full Claude Code MCP configuration schema
243
243
  */
244
244
  const ClaudeCodeMcpConfigSchema = z.object({
245
+ id: z.string().optional(),
245
246
  mcpServers: z.record(z.string(), ClaudeCodeServerConfigSchema),
246
247
  remoteConfigs: z.array(RemoteConfigSourceSchema).optional(),
247
248
  skills: SkillsConfigSchema.optional()
@@ -311,6 +312,7 @@ const McpServerConfigSchema = z.discriminatedUnion("transport", [
311
312
  * Full internal MCP configuration schema
312
313
  */
313
314
  const InternalMcpConfigSchema = z.object({
315
+ id: z.string().optional(),
314
316
  mcpServers: z.record(z.string(), McpServerConfigSchema),
315
317
  skills: SkillsConfigSchema.optional()
316
318
  });
@@ -365,6 +367,7 @@ function transformClaudeCodeConfig(claudeConfig) {
365
367
  }
366
368
  }
367
369
  return {
370
+ id: claudeConfig.id,
368
371
  mcpServers: transformedServers,
369
372
  skills: claudeConfig.skills
370
373
  };
@@ -1219,6 +1222,71 @@ function extractSkillFrontMatter(content) {
1219
1222
  return null;
1220
1223
  }
1221
1224
 
1225
+ //#endregion
1226
+ //#region src/utils/generateServerId.ts
1227
+ /**
1228
+ * generateServerId Utilities
1229
+ *
1230
+ * DESIGN PATTERNS:
1231
+ * - Pure functions with no side effects
1232
+ * - Single responsibility per function
1233
+ * - Functional programming approach
1234
+ *
1235
+ * CODING STANDARDS:
1236
+ * - Export individual functions, not classes
1237
+ * - Use descriptive function names with verbs
1238
+ * - Add JSDoc comments for complex logic
1239
+ * - Keep functions small and focused
1240
+ *
1241
+ * AVOID:
1242
+ * - Side effects (mutating external state)
1243
+ * - Stateful logic (use services for state)
1244
+ * - Complex external dependencies
1245
+ */
1246
+ /**
1247
+ * Character set for generating human-readable IDs.
1248
+ * Excludes confusing characters: 0, O, 1, l, I
1249
+ */
1250
+ const CHARSET = "23456789abcdefghjkmnpqrstuvwxyz";
1251
+ /**
1252
+ * Default length for generated server IDs (6 characters)
1253
+ */
1254
+ const DEFAULT_ID_LENGTH = 6;
1255
+ /**
1256
+ * Generate a short, human-readable server ID.
1257
+ *
1258
+ * Uses Node.js crypto.randomBytes for cryptographically secure randomness
1259
+ * with rejection sampling to avoid modulo bias.
1260
+ *
1261
+ * The generated ID:
1262
+ * - Is 6 characters long by default
1263
+ * - Uses only lowercase alphanumeric characters
1264
+ * - Excludes confusing characters (0, O, 1, l, I)
1265
+ *
1266
+ * @param length - Length of the ID to generate (default: 6)
1267
+ * @returns A random, human-readable ID
1268
+ *
1269
+ * @example
1270
+ * generateServerId() // "abc234"
1271
+ * generateServerId(4) // "x7mn"
1272
+ */
1273
+ function generateServerId(length = DEFAULT_ID_LENGTH) {
1274
+ const charsetLength = 31;
1275
+ const maxUnbiased = Math.floor(256 / charsetLength) * charsetLength - 1;
1276
+ let result = "";
1277
+ let remaining = length;
1278
+ while (remaining > 0) {
1279
+ const bytes = randomBytes(remaining);
1280
+ for (let i = 0; i < bytes.length && remaining > 0; i++) {
1281
+ const byte = bytes[i];
1282
+ if (byte > maxUnbiased) continue;
1283
+ result += CHARSET[byte % charsetLength];
1284
+ remaining--;
1285
+ }
1286
+ }
1287
+ return result;
1288
+ }
1289
+
1222
1290
  //#endregion
1223
1291
  //#region src/services/SkillService.ts
1224
1292
  /**
@@ -1496,7 +1564,7 @@ var SkillService = class {
1496
1564
  * Prefix added to skill names when they clash with MCP tool names.
1497
1565
  * This ensures skills can be uniquely identified even when a tool has the same name.
1498
1566
  */
1499
- const SKILL_PREFIX$1 = "skill__";
1567
+ const SKILL_PREFIX = "skill__";
1500
1568
  /**
1501
1569
  * Log prefix for skill detection messages.
1502
1570
  * Used to easily filter skill detection logs in stderr output.
@@ -1507,10 +1575,15 @@ const LOG_PREFIX_SKILL_DETECTION = "[skill-detection]";
1507
1575
  * Format: "prompt:{serverName}:{promptName}"
1508
1576
  */
1509
1577
  const PROMPT_LOCATION_PREFIX = "prompt:";
1578
+ /**
1579
+ * Default server ID used when no ID is provided via CLI or config.
1580
+ * This fallback is used when auto-generation also fails.
1581
+ */
1582
+ const DEFAULT_SERVER_ID = "unknown";
1510
1583
 
1511
1584
  //#endregion
1512
1585
  //#region src/templates/toolkit-description.liquid?raw
1513
- var toolkit_description_default = "<toolkit>\n<instruction>\nBefore you use any capabilities below, you MUST call this tool with a list of names to learn how to use them properly; this includes:\n- For tools: Arguments schema needed to pass to use_tool\n- For skills: Detailed instructions that will expand when invoked (Prefer to be explored first when relevant)\n\nThis tool is optimized for batch queries - you can request multiple capabilities at once for better performance.\n\nHow to invoke:\n- For MCP tools: Use use_tool with toolName and toolArgs based on the schema\n- For skills: Use this tool with the skill name to get expanded instructions\n</instruction>\n\n<available_capabilities>\n{% for server in servers -%}\n<group name=\"{{ server.name }}\">\n{% if server.instruction -%}\n<group_instruction>{{ server.instruction }}</group_instruction>\n{% endif -%}\n{% if server.omitToolDescription -%}\n{% for toolName in server.toolNames -%}\n<item name=\"{{ toolName }}\"></item>\n{% endfor -%}\n{% else -%}\n{% for tool in server.tools -%}\n<item name=\"{{ tool.displayName }}\"><description>{{ tool.description | default: \"No description\" }}</description></item>\n{% endfor -%}\n{% endif -%}\n</group>\n{% endfor -%}\n{% if skills.size > 0 -%}\n<group name=\"skills\">\n{% for skill in skills -%}\n<item name=\"{{ skill.displayName }}\"><description>{{ skill.description }}</description></item>\n{% endfor -%}\n</group>\n{% endif -%}\n</available_capabilities>\n</toolkit>\n";
1586
+ var toolkit_description_default = "<toolkit id=\"{{ serverId }}\">\n<instruction>\nBefore you use any capabilities below, you MUST call this tool with a list of names to learn how to use them properly; this includes:\n- For tools: Arguments schema needed to pass to use_tool\n- For skills: Detailed instructions that will expand when invoked (Prefer to be explored first when relevant)\n\nThis tool is optimized for batch queries - you can request multiple capabilities at once for better performance.\n\nHow to invoke:\n- For MCP tools: Use use_tool with toolName and toolArgs based on the schema\n- For skills: Use this tool with the skill name to get expanded instructions\n</instruction>\n\n<available_capabilities>\n{% for server in servers -%}\n<group name=\"{{ server.name }}\">\n{% if server.instruction -%}\n<group_instruction>{{ server.instruction }}</group_instruction>\n{% endif -%}\n{% if server.omitToolDescription -%}\n{% for toolName in server.toolNames -%}\n<item name=\"{{ toolName }}\"></item>\n{% endfor -%}\n{% else -%}\n{% for tool in server.tools -%}\n<item name=\"{{ tool.displayName }}\"><description>{{ tool.description | default: \"No description\" }}</description></item>\n{% endfor -%}\n{% endif -%}\n</group>\n{% endfor -%}\n{% if skills.size > 0 -%}\n<group name=\"skills\">\n{% for skill in skills -%}\n<item name=\"{{ skill.displayName }}\"><description>{{ skill.description }}</description></item>\n{% endfor -%}\n</group>\n{% endif -%}\n</available_capabilities>\n</toolkit>\n";
1514
1587
 
1515
1588
  //#endregion
1516
1589
  //#region src/tools/DescribeToolsTool.ts
@@ -1549,14 +1622,18 @@ var DescribeToolsTool = class DescribeToolsTool {
1549
1622
  liquid = new Liquid();
1550
1623
  /** Cache for auto-detected skills from prompt front-matter */
1551
1624
  autoDetectedSkillsCache = null;
1625
+ /** Unique server identifier for this one-mcp instance */
1626
+ serverId;
1552
1627
  /**
1553
1628
  * Creates a new DescribeToolsTool instance
1554
1629
  * @param clientManager - The MCP client manager for accessing remote servers
1555
1630
  * @param skillService - Optional skill service for loading skills
1631
+ * @param serverId - Unique server identifier for this one-mcp instance
1556
1632
  */
1557
- constructor(clientManager, skillService) {
1633
+ constructor(clientManager, skillService, serverId) {
1558
1634
  this.clientManager = clientManager;
1559
1635
  this.skillService = skillService;
1636
+ this.serverId = serverId || DEFAULT_SERVER_ID;
1560
1637
  }
1561
1638
  /**
1562
1639
  * Clears the cached auto-detected skills from prompt front-matter.
@@ -1781,14 +1858,15 @@ var DescribeToolsTool = class DescribeToolsTool {
1781
1858
  const clashesWithMcpTool = allToolNames.has(skill.name);
1782
1859
  return {
1783
1860
  name: skill.name,
1784
- displayName: clashesWithMcpTool ? `${SKILL_PREFIX$1}${skill.name}` : skill.name,
1861
+ displayName: clashesWithMcpTool ? `${SKILL_PREFIX}${skill.name}` : skill.name,
1785
1862
  description: skill.description
1786
1863
  };
1787
1864
  });
1788
1865
  return {
1789
1866
  content: await this.liquid.parseAndRender(toolkit_description_default, {
1790
1867
  servers,
1791
- skills
1868
+ skills,
1869
+ serverId: this.serverId
1792
1870
  }),
1793
1871
  toolNames: allToolNames
1794
1872
  };
@@ -1874,8 +1952,8 @@ var DescribeToolsTool = class DescribeToolsTool {
1874
1952
  const foundSkills = [];
1875
1953
  const notFoundItems = [];
1876
1954
  for (const requestedName of toolNames) {
1877
- if (requestedName.startsWith(SKILL_PREFIX$1)) {
1878
- const skillName = requestedName.slice(SKILL_PREFIX$1.length);
1955
+ if (requestedName.startsWith(SKILL_PREFIX)) {
1956
+ const skillName = requestedName.slice(SKILL_PREFIX.length);
1879
1957
  if (this.skillService) {
1880
1958
  const skill = await this.skillService.getSkill(skillName);
1881
1959
  if (skill) {
@@ -1999,10 +2077,6 @@ var DescribeToolsTool = class DescribeToolsTool {
1999
2077
  //#endregion
2000
2078
  //#region src/tools/UseToolTool.ts
2001
2079
  /**
2002
- * Prefix used to identify skill invocations (e.g., skill__pdf)
2003
- */
2004
- const SKILL_PREFIX = "skill__";
2005
- /**
2006
2080
  * UseToolTool executes MCP tools and skills with proper error handling.
2007
2081
  *
2008
2082
  * This tool supports three invocation patterns:
@@ -2019,14 +2093,18 @@ var UseToolTool = class UseToolTool {
2019
2093
  static TOOL_NAME = "use_tool";
2020
2094
  clientManager;
2021
2095
  skillService;
2096
+ /** Unique server identifier for this one-mcp instance */
2097
+ serverId;
2022
2098
  /**
2023
2099
  * Creates a new UseToolTool instance
2024
2100
  * @param clientManager - The MCP client manager for accessing remote servers
2025
2101
  * @param skillService - Optional skill service for loading and executing skills
2102
+ * @param serverId - Unique server identifier for this one-mcp instance
2026
2103
  */
2027
- constructor(clientManager, skillService) {
2104
+ constructor(clientManager, skillService, serverId) {
2028
2105
  this.clientManager = clientManager;
2029
2106
  this.skillService = skillService;
2107
+ this.serverId = serverId || DEFAULT_SERVER_ID;
2030
2108
  }
2031
2109
  /**
2032
2110
  * Returns the MCP tool definition with name, description, and input schema.
@@ -2042,6 +2120,8 @@ var UseToolTool = class UseToolTool {
2042
2120
  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:
2043
2121
  - Provide toolName and toolArgs based on the schema
2044
2122
  - If multiple servers provide the same tool, specify serverName
2123
+
2124
+ IMPORTANT: Only use tools discovered from describe_tools with id="${this.serverId}".
2045
2125
  `,
2046
2126
  inputSchema: {
2047
2127
  type: "object",
@@ -2128,7 +2208,7 @@ var UseToolTool = class UseToolTool {
2128
2208
  try {
2129
2209
  const { toolName: inputToolName, toolArgs = {} } = input;
2130
2210
  if (inputToolName.startsWith(SKILL_PREFIX)) {
2131
- const skillName = inputToolName.slice(7);
2211
+ const skillName = inputToolName.slice(SKILL_PREFIX.length);
2132
2212
  if (this.skillService) {
2133
2213
  const skill = await this.skillService.getSkill(skillName);
2134
2214
  if (skill) return this.executeSkill(skill);
@@ -2263,6 +2343,7 @@ async function createServer(options) {
2263
2343
  } });
2264
2344
  const clientManager = new McpClientManagerService();
2265
2345
  let configSkills;
2346
+ let configId;
2266
2347
  if (options?.configFilePath) {
2267
2348
  let config;
2268
2349
  try {
@@ -2274,6 +2355,7 @@ async function createServer(options) {
2274
2355
  throw new Error(`Failed to load MCP configuration from '${options.configFilePath}': ${error instanceof Error ? error.message : String(error)}`);
2275
2356
  }
2276
2357
  configSkills = config.skills;
2358
+ configId = config.id;
2277
2359
  const failedConnections = [];
2278
2360
  const connectionPromises = Object.entries(config.mcpServers).map(async ([serverName, serverConfig]) => {
2279
2361
  try {
@@ -2292,13 +2374,15 @@ async function createServer(options) {
2292
2374
  if (failedConnections.length > 0 && failedConnections.length < Object.keys(config.mcpServers).length) console.error(`Warning: Some MCP server connections failed: ${failedConnections.map((f) => f.serverName).join(", ")}`);
2293
2375
  if (failedConnections.length > 0 && failedConnections.length === Object.keys(config.mcpServers).length) throw new Error(`All MCP server connections failed: ${failedConnections.map((f) => `${f.serverName}: ${f.error.message}`).join(", ")}`);
2294
2376
  }
2377
+ const serverId = options?.serverId || configId || generateServerId();
2378
+ console.error(`[one-mcp] Server ID: ${serverId}`);
2295
2379
  const skillsConfig = options?.skills || configSkills;
2296
2380
  const toolsRef = { describeTools: null };
2297
2381
  const skillService = skillsConfig && skillsConfig.paths.length > 0 ? new SkillService(process.cwd(), skillsConfig.paths, { onCacheInvalidated: () => {
2298
2382
  toolsRef.describeTools?.clearAutoDetectedSkillsCache();
2299
2383
  } }) : void 0;
2300
- const describeTools = new DescribeToolsTool(clientManager, skillService);
2301
- const useTool = new UseToolTool(clientManager, skillService);
2384
+ const describeTools = new DescribeToolsTool(clientManager, skillService, serverId);
2385
+ const useTool = new UseToolTool(clientManager, skillService, serverId);
2302
2386
  toolsRef.describeTools = describeTools;
2303
2387
  if (skillService) skillService.startWatching().catch((error) => {
2304
2388
  console.error(`[skill-watcher] File watcher failed (non-critical): ${error instanceof Error ? error.message : "Unknown error"}`);
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const require_http = require('./http-BYBRKvD4.cjs');
1
+ const require_http = require('./http-C4IfZSwW.cjs');
2
2
 
3
3
  exports.HttpTransportHandler = require_http.HttpTransportHandler;
4
4
  exports.SseTransportHandler = require_http.SseTransportHandler;
package/dist/index.d.cts CHANGED
@@ -8,6 +8,7 @@ import { CallToolResult, GetPromptResult, ReadResourceResult } from "@modelconte
8
8
  * @property configFilePath - Path to the MCP configuration file
9
9
  * @property noCache - Skip cache when fetching remote configuration
10
10
  * @property skills - Skills configuration with paths array (optional, skills disabled if not provided)
11
+ * @property serverId - CLI-provided server ID (takes precedence over config file id)
11
12
  */
12
13
  interface ServerOptions {
13
14
  configFilePath?: string;
@@ -15,6 +16,7 @@ interface ServerOptions {
15
16
  skills?: {
16
17
  paths: string[];
17
18
  };
19
+ serverId?: string;
18
20
  }
19
21
  declare function createServer(options?: ServerOptions): Promise<Server>;
20
22
  //#endregion
@@ -174,10 +176,12 @@ interface PromptConfig {
174
176
  }
175
177
  /**
176
178
  * Remote configuration response containing MCP server definitions
179
+ * @property id - Optional unique server identifier
177
180
  * @property mcpServers - Map of server names to their configurations
178
181
  * @property skills - Optional skills configuration with paths
179
182
  */
180
183
  interface RemoteMcpConfiguration {
184
+ id?: string;
181
185
  mcpServers: Record<string, McpServerConfig>;
182
186
  skills?: SkillsConfig;
183
187
  }
package/dist/index.d.mts CHANGED
@@ -8,6 +8,7 @@ import { CallToolResult, GetPromptResult, ReadResourceResult } from "@modelconte
8
8
  * @property configFilePath - Path to the MCP configuration file
9
9
  * @property noCache - Skip cache when fetching remote configuration
10
10
  * @property skills - Skills configuration with paths array (optional, skills disabled if not provided)
11
+ * @property serverId - CLI-provided server ID (takes precedence over config file id)
11
12
  */
12
13
  interface ServerOptions {
13
14
  configFilePath?: string;
@@ -15,6 +16,7 @@ interface ServerOptions {
15
16
  skills?: {
16
17
  paths: string[];
17
18
  };
19
+ serverId?: string;
18
20
  }
19
21
  declare function createServer(options?: ServerOptions): Promise<Server>;
20
22
  //#endregion
@@ -174,10 +176,12 @@ interface PromptConfig {
174
176
  }
175
177
  /**
176
178
  * Remote configuration response containing MCP server definitions
179
+ * @property id - Optional unique server identifier
177
180
  * @property mcpServers - Map of server names to their configurations
178
181
  * @property skills - Optional skills configuration with paths
179
182
  */
180
183
  interface RemoteMcpConfiguration {
184
+ id?: string;
181
185
  mcpServers: Record<string, McpServerConfig>;
182
186
  skills?: SkillsConfig;
183
187
  }
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-Bi2N9PUM.mjs";
1
+ import { i as createServer, n as SseTransportHandler, r as StdioTransportHandler, t as HttpTransportHandler } from "./http-xi_ha63Y.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.3.0",
4
+ "version": "0.3.1",
5
5
  "license": "AGPL-3.0",
6
6
  "keywords": [
7
7
  "mcp",