@agiflowai/one-mcp 0.2.7 → 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.
@@ -231,6 +231,7 @@ const ClaudeCodeStdioServerSchema = zod.z.object({
231
231
  env: zod.z.record(zod.z.string(), zod.z.string()).optional(),
232
232
  disabled: zod.z.boolean().optional(),
233
233
  instruction: zod.z.string().optional(),
234
+ timeout: zod.z.number().positive().optional(),
234
235
  config: AdditionalConfigSchema
235
236
  });
236
237
  const ClaudeCodeHttpServerSchema = zod.z.object({
@@ -239,6 +240,7 @@ const ClaudeCodeHttpServerSchema = zod.z.object({
239
240
  type: zod.z.enum(["http", "sse"]).optional(),
240
241
  disabled: zod.z.boolean().optional(),
241
242
  instruction: zod.z.string().optional(),
243
+ timeout: zod.z.number().positive().optional(),
242
244
  config: AdditionalConfigSchema
243
245
  });
244
246
  const ClaudeCodeServerConfigSchema = zod.z.union([ClaudeCodeStdioServerSchema, ClaudeCodeHttpServerSchema]);
@@ -269,6 +271,7 @@ const SkillsConfigSchema = zod.z.object({ paths: zod.z.array(zod.z.string()) });
269
271
  * Full Claude Code MCP configuration schema
270
272
  */
271
273
  const ClaudeCodeMcpConfigSchema = zod.z.object({
274
+ id: zod.z.string().optional(),
272
275
  mcpServers: zod.z.record(zod.z.string(), ClaudeCodeServerConfigSchema),
273
276
  remoteConfigs: zod.z.array(RemoteConfigSourceSchema).optional(),
274
277
  skills: SkillsConfigSchema.optional()
@@ -309,6 +312,7 @@ const McpServerConfigSchema = zod.z.discriminatedUnion("transport", [
309
312
  toolBlacklist: zod.z.array(zod.z.string()).optional(),
310
313
  omitToolDescription: zod.z.boolean().optional(),
311
314
  prompts: zod.z.record(zod.z.string(), InternalPromptConfigSchema).optional(),
315
+ timeout: zod.z.number().positive().optional(),
312
316
  transport: zod.z.literal("stdio"),
313
317
  config: McpStdioConfigSchema
314
318
  }),
@@ -318,6 +322,7 @@ const McpServerConfigSchema = zod.z.discriminatedUnion("transport", [
318
322
  toolBlacklist: zod.z.array(zod.z.string()).optional(),
319
323
  omitToolDescription: zod.z.boolean().optional(),
320
324
  prompts: zod.z.record(zod.z.string(), InternalPromptConfigSchema).optional(),
325
+ timeout: zod.z.number().positive().optional(),
321
326
  transport: zod.z.literal("http"),
322
327
  config: McpHttpConfigSchema
323
328
  }),
@@ -327,6 +332,7 @@ const McpServerConfigSchema = zod.z.discriminatedUnion("transport", [
327
332
  toolBlacklist: zod.z.array(zod.z.string()).optional(),
328
333
  omitToolDescription: zod.z.boolean().optional(),
329
334
  prompts: zod.z.record(zod.z.string(), InternalPromptConfigSchema).optional(),
335
+ timeout: zod.z.number().positive().optional(),
330
336
  transport: zod.z.literal("sse"),
331
337
  config: McpSseConfigSchema
332
338
  })
@@ -335,6 +341,7 @@ const McpServerConfigSchema = zod.z.discriminatedUnion("transport", [
335
341
  * Full internal MCP configuration schema
336
342
  */
337
343
  const InternalMcpConfigSchema = zod.z.object({
344
+ id: zod.z.string().optional(),
338
345
  mcpServers: zod.z.record(zod.z.string(), McpServerConfigSchema),
339
346
  skills: SkillsConfigSchema.optional()
340
347
  });
@@ -360,6 +367,7 @@ function transformClaudeCodeConfig(claudeConfig) {
360
367
  toolBlacklist: stdioConfig.config?.toolBlacklist,
361
368
  omitToolDescription: stdioConfig.config?.omitToolDescription,
362
369
  prompts: stdioConfig.config?.prompts,
370
+ timeout: stdioConfig.timeout,
363
371
  transport: "stdio",
364
372
  config: {
365
373
  command: interpolatedCommand,
@@ -378,6 +386,7 @@ function transformClaudeCodeConfig(claudeConfig) {
378
386
  toolBlacklist: httpConfig.config?.toolBlacklist,
379
387
  omitToolDescription: httpConfig.config?.omitToolDescription,
380
388
  prompts: httpConfig.config?.prompts,
389
+ timeout: httpConfig.timeout,
381
390
  transport,
382
391
  config: {
383
392
  url: interpolatedUrl,
@@ -387,6 +396,7 @@ function transformClaudeCodeConfig(claudeConfig) {
387
396
  }
388
397
  }
389
398
  return {
399
+ id: claudeConfig.id,
390
400
  mcpServers: transformedServers,
391
401
  skills: claudeConfig.skills
392
402
  };
@@ -836,6 +846,8 @@ var ConfigFetcherService = class {
836
846
 
837
847
  //#endregion
838
848
  //#region src/services/McpClientManagerService.ts
849
+ /** Default connection timeout in milliseconds (30 seconds) */
850
+ const DEFAULT_CONNECTION_TIMEOUT_MS = 3e4;
839
851
  /**
840
852
  * MCP Client wrapper for managing individual server connections
841
853
  * This is an internal class used by McpClientManagerService
@@ -941,8 +953,10 @@ var McpClientManagerService = class {
941
953
  }
942
954
  /**
943
955
  * Connect to an MCP server based on its configuration with timeout
956
+ * Uses the timeout from server config, falling back to default (30s)
944
957
  */
945
- async connectToServer(serverName, config, timeoutMs = 1e4) {
958
+ async connectToServer(serverName, config) {
959
+ const timeoutMs = config.timeout ?? DEFAULT_CONNECTION_TIMEOUT_MS;
946
960
  if (this.clients.has(serverName)) throw new Error(`Client for ${serverName} is already connected`);
947
961
  const client = new __modelcontextprotocol_sdk_client_index_js.Client({
948
962
  name: `@agiflowai/one-mcp-client`,
@@ -1237,6 +1251,71 @@ function extractSkillFrontMatter(content) {
1237
1251
  return null;
1238
1252
  }
1239
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
+
1240
1319
  //#endregion
1241
1320
  //#region src/services/SkillService.ts
1242
1321
  /**
@@ -1514,7 +1593,7 @@ var SkillService = class {
1514
1593
  * Prefix added to skill names when they clash with MCP tool names.
1515
1594
  * This ensures skills can be uniquely identified even when a tool has the same name.
1516
1595
  */
1517
- const SKILL_PREFIX$1 = "skill__";
1596
+ const SKILL_PREFIX = "skill__";
1518
1597
  /**
1519
1598
  * Log prefix for skill detection messages.
1520
1599
  * Used to easily filter skill detection logs in stderr output.
@@ -1525,10 +1604,15 @@ const LOG_PREFIX_SKILL_DETECTION = "[skill-detection]";
1525
1604
  * Format: "prompt:{serverName}:{promptName}"
1526
1605
  */
1527
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";
1528
1612
 
1529
1613
  //#endregion
1530
1614
  //#region src/templates/toolkit-description.liquid?raw
1531
- 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";
1532
1616
 
1533
1617
  //#endregion
1534
1618
  //#region src/tools/DescribeToolsTool.ts
@@ -1567,14 +1651,18 @@ var DescribeToolsTool = class DescribeToolsTool {
1567
1651
  liquid = new liquidjs.Liquid();
1568
1652
  /** Cache for auto-detected skills from prompt front-matter */
1569
1653
  autoDetectedSkillsCache = null;
1654
+ /** Unique server identifier for this one-mcp instance */
1655
+ serverId;
1570
1656
  /**
1571
1657
  * Creates a new DescribeToolsTool instance
1572
1658
  * @param clientManager - The MCP client manager for accessing remote servers
1573
1659
  * @param skillService - Optional skill service for loading skills
1660
+ * @param serverId - Unique server identifier for this one-mcp instance
1574
1661
  */
1575
- constructor(clientManager, skillService) {
1662
+ constructor(clientManager, skillService, serverId) {
1576
1663
  this.clientManager = clientManager;
1577
1664
  this.skillService = skillService;
1665
+ this.serverId = serverId || DEFAULT_SERVER_ID;
1578
1666
  }
1579
1667
  /**
1580
1668
  * Clears the cached auto-detected skills from prompt front-matter.
@@ -1799,14 +1887,15 @@ var DescribeToolsTool = class DescribeToolsTool {
1799
1887
  const clashesWithMcpTool = allToolNames.has(skill.name);
1800
1888
  return {
1801
1889
  name: skill.name,
1802
- displayName: clashesWithMcpTool ? `${SKILL_PREFIX$1}${skill.name}` : skill.name,
1890
+ displayName: clashesWithMcpTool ? `${SKILL_PREFIX}${skill.name}` : skill.name,
1803
1891
  description: skill.description
1804
1892
  };
1805
1893
  });
1806
1894
  return {
1807
1895
  content: await this.liquid.parseAndRender(toolkit_description_default, {
1808
1896
  servers,
1809
- skills
1897
+ skills,
1898
+ serverId: this.serverId
1810
1899
  }),
1811
1900
  toolNames: allToolNames
1812
1901
  };
@@ -1892,8 +1981,8 @@ var DescribeToolsTool = class DescribeToolsTool {
1892
1981
  const foundSkills = [];
1893
1982
  const notFoundItems = [];
1894
1983
  for (const requestedName of toolNames) {
1895
- if (requestedName.startsWith(SKILL_PREFIX$1)) {
1896
- const skillName = requestedName.slice(SKILL_PREFIX$1.length);
1984
+ if (requestedName.startsWith(SKILL_PREFIX)) {
1985
+ const skillName = requestedName.slice(SKILL_PREFIX.length);
1897
1986
  if (this.skillService) {
1898
1987
  const skill = await this.skillService.getSkill(skillName);
1899
1988
  if (skill) {
@@ -2017,10 +2106,6 @@ var DescribeToolsTool = class DescribeToolsTool {
2017
2106
  //#endregion
2018
2107
  //#region src/tools/UseToolTool.ts
2019
2108
  /**
2020
- * Prefix used to identify skill invocations (e.g., skill__pdf)
2021
- */
2022
- const SKILL_PREFIX = "skill__";
2023
- /**
2024
2109
  * UseToolTool executes MCP tools and skills with proper error handling.
2025
2110
  *
2026
2111
  * This tool supports three invocation patterns:
@@ -2037,14 +2122,18 @@ var UseToolTool = class UseToolTool {
2037
2122
  static TOOL_NAME = "use_tool";
2038
2123
  clientManager;
2039
2124
  skillService;
2125
+ /** Unique server identifier for this one-mcp instance */
2126
+ serverId;
2040
2127
  /**
2041
2128
  * Creates a new UseToolTool instance
2042
2129
  * @param clientManager - The MCP client manager for accessing remote servers
2043
2130
  * @param skillService - Optional skill service for loading and executing skills
2131
+ * @param serverId - Unique server identifier for this one-mcp instance
2044
2132
  */
2045
- constructor(clientManager, skillService) {
2133
+ constructor(clientManager, skillService, serverId) {
2046
2134
  this.clientManager = clientManager;
2047
2135
  this.skillService = skillService;
2136
+ this.serverId = serverId || DEFAULT_SERVER_ID;
2048
2137
  }
2049
2138
  /**
2050
2139
  * Returns the MCP tool definition with name, description, and input schema.
@@ -2060,6 +2149,8 @@ var UseToolTool = class UseToolTool {
2060
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:
2061
2150
  - Provide toolName and toolArgs based on the schema
2062
2151
  - If multiple servers provide the same tool, specify serverName
2152
+
2153
+ IMPORTANT: Only use tools discovered from describe_tools with id="${this.serverId}".
2063
2154
  `,
2064
2155
  inputSchema: {
2065
2156
  type: "object",
@@ -2146,7 +2237,7 @@ var UseToolTool = class UseToolTool {
2146
2237
  try {
2147
2238
  const { toolName: inputToolName, toolArgs = {} } = input;
2148
2239
  if (inputToolName.startsWith(SKILL_PREFIX)) {
2149
- const skillName = inputToolName.slice(7);
2240
+ const skillName = inputToolName.slice(SKILL_PREFIX.length);
2150
2241
  if (this.skillService) {
2151
2242
  const skill = await this.skillService.getSkill(skillName);
2152
2243
  if (skill) return this.executeSkill(skill);
@@ -2281,6 +2372,7 @@ async function createServer(options) {
2281
2372
  } });
2282
2373
  const clientManager = new McpClientManagerService();
2283
2374
  let configSkills;
2375
+ let configId;
2284
2376
  if (options?.configFilePath) {
2285
2377
  let config;
2286
2378
  try {
@@ -2292,6 +2384,7 @@ async function createServer(options) {
2292
2384
  throw new Error(`Failed to load MCP configuration from '${options.configFilePath}': ${error instanceof Error ? error.message : String(error)}`);
2293
2385
  }
2294
2386
  configSkills = config.skills;
2387
+ configId = config.id;
2295
2388
  const failedConnections = [];
2296
2389
  const connectionPromises = Object.entries(config.mcpServers).map(async ([serverName, serverConfig]) => {
2297
2390
  try {
@@ -2310,13 +2403,15 @@ async function createServer(options) {
2310
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(", ")}`);
2311
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(", ")}`);
2312
2405
  }
2406
+ const serverId = options?.serverId || configId || generateServerId();
2407
+ console.error(`[one-mcp] Server ID: ${serverId}`);
2313
2408
  const skillsConfig = options?.skills || configSkills;
2314
2409
  const toolsRef = { describeTools: null };
2315
2410
  const skillService = skillsConfig && skillsConfig.paths.length > 0 ? new SkillService(process.cwd(), skillsConfig.paths, { onCacheInvalidated: () => {
2316
2411
  toolsRef.describeTools?.clearAutoDetectedSkillsCache();
2317
2412
  } }) : void 0;
2318
- const describeTools = new DescribeToolsTool(clientManager, skillService);
2319
- const useTool = new UseToolTool(clientManager, skillService);
2413
+ const describeTools = new DescribeToolsTool(clientManager, skillService, serverId);
2414
+ const useTool = new UseToolTool(clientManager, skillService, serverId);
2320
2415
  toolsRef.describeTools = describeTools;
2321
2416
  if (skillService) skillService.startWatching().catch((error) => {
2322
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";
@@ -202,6 +202,7 @@ const ClaudeCodeStdioServerSchema = z.object({
202
202
  env: z.record(z.string(), z.string()).optional(),
203
203
  disabled: z.boolean().optional(),
204
204
  instruction: z.string().optional(),
205
+ timeout: z.number().positive().optional(),
205
206
  config: AdditionalConfigSchema
206
207
  });
207
208
  const ClaudeCodeHttpServerSchema = z.object({
@@ -210,6 +211,7 @@ const ClaudeCodeHttpServerSchema = z.object({
210
211
  type: z.enum(["http", "sse"]).optional(),
211
212
  disabled: z.boolean().optional(),
212
213
  instruction: z.string().optional(),
214
+ timeout: z.number().positive().optional(),
213
215
  config: AdditionalConfigSchema
214
216
  });
215
217
  const ClaudeCodeServerConfigSchema = z.union([ClaudeCodeStdioServerSchema, ClaudeCodeHttpServerSchema]);
@@ -240,6 +242,7 @@ const SkillsConfigSchema = z.object({ paths: z.array(z.string()) });
240
242
  * Full Claude Code MCP configuration schema
241
243
  */
242
244
  const ClaudeCodeMcpConfigSchema = z.object({
245
+ id: z.string().optional(),
243
246
  mcpServers: z.record(z.string(), ClaudeCodeServerConfigSchema),
244
247
  remoteConfigs: z.array(RemoteConfigSourceSchema).optional(),
245
248
  skills: SkillsConfigSchema.optional()
@@ -280,6 +283,7 @@ const McpServerConfigSchema = z.discriminatedUnion("transport", [
280
283
  toolBlacklist: z.array(z.string()).optional(),
281
284
  omitToolDescription: z.boolean().optional(),
282
285
  prompts: z.record(z.string(), InternalPromptConfigSchema).optional(),
286
+ timeout: z.number().positive().optional(),
283
287
  transport: z.literal("stdio"),
284
288
  config: McpStdioConfigSchema
285
289
  }),
@@ -289,6 +293,7 @@ const McpServerConfigSchema = z.discriminatedUnion("transport", [
289
293
  toolBlacklist: z.array(z.string()).optional(),
290
294
  omitToolDescription: z.boolean().optional(),
291
295
  prompts: z.record(z.string(), InternalPromptConfigSchema).optional(),
296
+ timeout: z.number().positive().optional(),
292
297
  transport: z.literal("http"),
293
298
  config: McpHttpConfigSchema
294
299
  }),
@@ -298,6 +303,7 @@ const McpServerConfigSchema = z.discriminatedUnion("transport", [
298
303
  toolBlacklist: z.array(z.string()).optional(),
299
304
  omitToolDescription: z.boolean().optional(),
300
305
  prompts: z.record(z.string(), InternalPromptConfigSchema).optional(),
306
+ timeout: z.number().positive().optional(),
301
307
  transport: z.literal("sse"),
302
308
  config: McpSseConfigSchema
303
309
  })
@@ -306,6 +312,7 @@ const McpServerConfigSchema = z.discriminatedUnion("transport", [
306
312
  * Full internal MCP configuration schema
307
313
  */
308
314
  const InternalMcpConfigSchema = z.object({
315
+ id: z.string().optional(),
309
316
  mcpServers: z.record(z.string(), McpServerConfigSchema),
310
317
  skills: SkillsConfigSchema.optional()
311
318
  });
@@ -331,6 +338,7 @@ function transformClaudeCodeConfig(claudeConfig) {
331
338
  toolBlacklist: stdioConfig.config?.toolBlacklist,
332
339
  omitToolDescription: stdioConfig.config?.omitToolDescription,
333
340
  prompts: stdioConfig.config?.prompts,
341
+ timeout: stdioConfig.timeout,
334
342
  transport: "stdio",
335
343
  config: {
336
344
  command: interpolatedCommand,
@@ -349,6 +357,7 @@ function transformClaudeCodeConfig(claudeConfig) {
349
357
  toolBlacklist: httpConfig.config?.toolBlacklist,
350
358
  omitToolDescription: httpConfig.config?.omitToolDescription,
351
359
  prompts: httpConfig.config?.prompts,
360
+ timeout: httpConfig.timeout,
352
361
  transport,
353
362
  config: {
354
363
  url: interpolatedUrl,
@@ -358,6 +367,7 @@ function transformClaudeCodeConfig(claudeConfig) {
358
367
  }
359
368
  }
360
369
  return {
370
+ id: claudeConfig.id,
361
371
  mcpServers: transformedServers,
362
372
  skills: claudeConfig.skills
363
373
  };
@@ -807,6 +817,8 @@ var ConfigFetcherService = class {
807
817
 
808
818
  //#endregion
809
819
  //#region src/services/McpClientManagerService.ts
820
+ /** Default connection timeout in milliseconds (30 seconds) */
821
+ const DEFAULT_CONNECTION_TIMEOUT_MS = 3e4;
810
822
  /**
811
823
  * MCP Client wrapper for managing individual server connections
812
824
  * This is an internal class used by McpClientManagerService
@@ -912,8 +924,10 @@ var McpClientManagerService = class {
912
924
  }
913
925
  /**
914
926
  * Connect to an MCP server based on its configuration with timeout
927
+ * Uses the timeout from server config, falling back to default (30s)
915
928
  */
916
- async connectToServer(serverName, config, timeoutMs = 1e4) {
929
+ async connectToServer(serverName, config) {
930
+ const timeoutMs = config.timeout ?? DEFAULT_CONNECTION_TIMEOUT_MS;
917
931
  if (this.clients.has(serverName)) throw new Error(`Client for ${serverName} is already connected`);
918
932
  const client = new Client({
919
933
  name: `@agiflowai/one-mcp-client`,
@@ -1208,6 +1222,71 @@ function extractSkillFrontMatter(content) {
1208
1222
  return null;
1209
1223
  }
1210
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
+
1211
1290
  //#endregion
1212
1291
  //#region src/services/SkillService.ts
1213
1292
  /**
@@ -1485,7 +1564,7 @@ var SkillService = class {
1485
1564
  * Prefix added to skill names when they clash with MCP tool names.
1486
1565
  * This ensures skills can be uniquely identified even when a tool has the same name.
1487
1566
  */
1488
- const SKILL_PREFIX$1 = "skill__";
1567
+ const SKILL_PREFIX = "skill__";
1489
1568
  /**
1490
1569
  * Log prefix for skill detection messages.
1491
1570
  * Used to easily filter skill detection logs in stderr output.
@@ -1496,10 +1575,15 @@ const LOG_PREFIX_SKILL_DETECTION = "[skill-detection]";
1496
1575
  * Format: "prompt:{serverName}:{promptName}"
1497
1576
  */
1498
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";
1499
1583
 
1500
1584
  //#endregion
1501
1585
  //#region src/templates/toolkit-description.liquid?raw
1502
- 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";
1503
1587
 
1504
1588
  //#endregion
1505
1589
  //#region src/tools/DescribeToolsTool.ts
@@ -1538,14 +1622,18 @@ var DescribeToolsTool = class DescribeToolsTool {
1538
1622
  liquid = new Liquid();
1539
1623
  /** Cache for auto-detected skills from prompt front-matter */
1540
1624
  autoDetectedSkillsCache = null;
1625
+ /** Unique server identifier for this one-mcp instance */
1626
+ serverId;
1541
1627
  /**
1542
1628
  * Creates a new DescribeToolsTool instance
1543
1629
  * @param clientManager - The MCP client manager for accessing remote servers
1544
1630
  * @param skillService - Optional skill service for loading skills
1631
+ * @param serverId - Unique server identifier for this one-mcp instance
1545
1632
  */
1546
- constructor(clientManager, skillService) {
1633
+ constructor(clientManager, skillService, serverId) {
1547
1634
  this.clientManager = clientManager;
1548
1635
  this.skillService = skillService;
1636
+ this.serverId = serverId || DEFAULT_SERVER_ID;
1549
1637
  }
1550
1638
  /**
1551
1639
  * Clears the cached auto-detected skills from prompt front-matter.
@@ -1770,14 +1858,15 @@ var DescribeToolsTool = class DescribeToolsTool {
1770
1858
  const clashesWithMcpTool = allToolNames.has(skill.name);
1771
1859
  return {
1772
1860
  name: skill.name,
1773
- displayName: clashesWithMcpTool ? `${SKILL_PREFIX$1}${skill.name}` : skill.name,
1861
+ displayName: clashesWithMcpTool ? `${SKILL_PREFIX}${skill.name}` : skill.name,
1774
1862
  description: skill.description
1775
1863
  };
1776
1864
  });
1777
1865
  return {
1778
1866
  content: await this.liquid.parseAndRender(toolkit_description_default, {
1779
1867
  servers,
1780
- skills
1868
+ skills,
1869
+ serverId: this.serverId
1781
1870
  }),
1782
1871
  toolNames: allToolNames
1783
1872
  };
@@ -1863,8 +1952,8 @@ var DescribeToolsTool = class DescribeToolsTool {
1863
1952
  const foundSkills = [];
1864
1953
  const notFoundItems = [];
1865
1954
  for (const requestedName of toolNames) {
1866
- if (requestedName.startsWith(SKILL_PREFIX$1)) {
1867
- const skillName = requestedName.slice(SKILL_PREFIX$1.length);
1955
+ if (requestedName.startsWith(SKILL_PREFIX)) {
1956
+ const skillName = requestedName.slice(SKILL_PREFIX.length);
1868
1957
  if (this.skillService) {
1869
1958
  const skill = await this.skillService.getSkill(skillName);
1870
1959
  if (skill) {
@@ -1988,10 +2077,6 @@ var DescribeToolsTool = class DescribeToolsTool {
1988
2077
  //#endregion
1989
2078
  //#region src/tools/UseToolTool.ts
1990
2079
  /**
1991
- * Prefix used to identify skill invocations (e.g., skill__pdf)
1992
- */
1993
- const SKILL_PREFIX = "skill__";
1994
- /**
1995
2080
  * UseToolTool executes MCP tools and skills with proper error handling.
1996
2081
  *
1997
2082
  * This tool supports three invocation patterns:
@@ -2008,14 +2093,18 @@ var UseToolTool = class UseToolTool {
2008
2093
  static TOOL_NAME = "use_tool";
2009
2094
  clientManager;
2010
2095
  skillService;
2096
+ /** Unique server identifier for this one-mcp instance */
2097
+ serverId;
2011
2098
  /**
2012
2099
  * Creates a new UseToolTool instance
2013
2100
  * @param clientManager - The MCP client manager for accessing remote servers
2014
2101
  * @param skillService - Optional skill service for loading and executing skills
2102
+ * @param serverId - Unique server identifier for this one-mcp instance
2015
2103
  */
2016
- constructor(clientManager, skillService) {
2104
+ constructor(clientManager, skillService, serverId) {
2017
2105
  this.clientManager = clientManager;
2018
2106
  this.skillService = skillService;
2107
+ this.serverId = serverId || DEFAULT_SERVER_ID;
2019
2108
  }
2020
2109
  /**
2021
2110
  * Returns the MCP tool definition with name, description, and input schema.
@@ -2031,6 +2120,8 @@ var UseToolTool = class UseToolTool {
2031
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:
2032
2121
  - Provide toolName and toolArgs based on the schema
2033
2122
  - If multiple servers provide the same tool, specify serverName
2123
+
2124
+ IMPORTANT: Only use tools discovered from describe_tools with id="${this.serverId}".
2034
2125
  `,
2035
2126
  inputSchema: {
2036
2127
  type: "object",
@@ -2117,7 +2208,7 @@ var UseToolTool = class UseToolTool {
2117
2208
  try {
2118
2209
  const { toolName: inputToolName, toolArgs = {} } = input;
2119
2210
  if (inputToolName.startsWith(SKILL_PREFIX)) {
2120
- const skillName = inputToolName.slice(7);
2211
+ const skillName = inputToolName.slice(SKILL_PREFIX.length);
2121
2212
  if (this.skillService) {
2122
2213
  const skill = await this.skillService.getSkill(skillName);
2123
2214
  if (skill) return this.executeSkill(skill);
@@ -2252,6 +2343,7 @@ async function createServer(options) {
2252
2343
  } });
2253
2344
  const clientManager = new McpClientManagerService();
2254
2345
  let configSkills;
2346
+ let configId;
2255
2347
  if (options?.configFilePath) {
2256
2348
  let config;
2257
2349
  try {
@@ -2263,6 +2355,7 @@ async function createServer(options) {
2263
2355
  throw new Error(`Failed to load MCP configuration from '${options.configFilePath}': ${error instanceof Error ? error.message : String(error)}`);
2264
2356
  }
2265
2357
  configSkills = config.skills;
2358
+ configId = config.id;
2266
2359
  const failedConnections = [];
2267
2360
  const connectionPromises = Object.entries(config.mcpServers).map(async ([serverName, serverConfig]) => {
2268
2361
  try {
@@ -2281,13 +2374,15 @@ async function createServer(options) {
2281
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(", ")}`);
2282
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(", ")}`);
2283
2376
  }
2377
+ const serverId = options?.serverId || configId || generateServerId();
2378
+ console.error(`[one-mcp] Server ID: ${serverId}`);
2284
2379
  const skillsConfig = options?.skills || configSkills;
2285
2380
  const toolsRef = { describeTools: null };
2286
2381
  const skillService = skillsConfig && skillsConfig.paths.length > 0 ? new SkillService(process.cwd(), skillsConfig.paths, { onCacheInvalidated: () => {
2287
2382
  toolsRef.describeTools?.clearAutoDetectedSkillsCache();
2288
2383
  } }) : void 0;
2289
- const describeTools = new DescribeToolsTool(clientManager, skillService);
2290
- const useTool = new UseToolTool(clientManager, skillService);
2384
+ const describeTools = new DescribeToolsTool(clientManager, skillService, serverId);
2385
+ const useTool = new UseToolTool(clientManager, skillService, serverId);
2291
2386
  toolsRef.describeTools = describeTools;
2292
2387
  if (skillService) skillService.startWatching().catch((error) => {
2293
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-B4NAfsQl.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;