@agimon-ai/mcp-proxy 0.7.2 → 0.7.3

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_src = require('./src-BXEt-Hpg.cjs');
2
+ const require_src = require('./src-Dp2m9_I_.cjs');
3
3
  let node_fs = require("node:fs");
4
4
  let node_fs_promises = require("node:fs/promises");
5
5
  let js_yaml = require("js-yaml");
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { C as DefinitionsCacheService, D as version, T as findConfigFile, b as RuntimeStateService, d as StdioHttpTransportHandler, f as StdioTransportHandler, m as HttpTransportHandler, n as createServer, o as createProxyIoCContainer, p as SseTransportHandler, r as createSessionServer, t as TRANSPORT_MODE, u as initializeSharedServices, w as generateServerId, y as StopServerService } from "./src-NZo_eM6U.mjs";
2
+ import { C as DefinitionsCacheService, D as version, T as findConfigFile, b as RuntimeStateService, d as StdioHttpTransportHandler, f as StdioTransportHandler, m as HttpTransportHandler, n as createServer, o as createProxyIoCContainer, p as SseTransportHandler, r as createSessionServer, t as TRANSPORT_MODE, u as initializeSharedServices, w as generateServerId, y as StopServerService } from "./src-Y-cyyxaw.mjs";
3
3
  import { constants, existsSync, readFileSync } from "node:fs";
4
4
  import { access, writeFile } from "node:fs/promises";
5
5
  import yaml from "js-yaml";
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const require_src = require('./src-BXEt-Hpg.cjs');
1
+ const require_src = require('./src-Dp2m9_I_.cjs');
2
2
 
3
3
  exports.ConfigFetcherService = require_src.ConfigFetcherService;
4
4
  exports.DefinitionsCacheService = require_src.DefinitionsCacheService;
package/dist/index.d.cts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as _modelcontextprotocol_sdk_server_index_js0 from "@modelcontextprotocol/sdk/server/index.js";
2
2
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
3
  import { CallToolResult, GetPromptResult, ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
4
+ import { z } from "zod";
4
5
  import { NodeTelemetryHandle } from "@agimon-ai/log-sink-mcp";
5
6
 
6
7
  //#region src/types/index.d.ts
@@ -14,12 +15,7 @@ import { NodeTelemetryHandle } from "@agimon-ai/log-sink-mcp";
14
15
  interface ToolDefinition {
15
16
  name: string;
16
17
  description: string;
17
- inputSchema: {
18
- type: string;
19
- properties: Record<string, unknown>;
20
- required?: string[];
21
- additionalProperties?: boolean;
22
- };
18
+ inputSchema: Record<string, unknown>;
23
19
  _meta?: Record<string, unknown>;
24
20
  }
25
21
  /**
@@ -28,6 +24,7 @@ interface ToolDefinition {
28
24
  */
29
25
  interface Tool<TInput = unknown> {
30
26
  getDefinition(): ToolDefinition | Promise<ToolDefinition>;
27
+ getInputSchema(): z.ZodObject<z.ZodRawShape>;
31
28
  execute(input: TInput): Promise<CallToolResult>;
32
29
  }
33
30
  /**
@@ -743,6 +740,7 @@ declare class DefinitionsCacheService {
743
740
  getDefinitions(): Promise<DefinitionsCacheFile>;
744
741
  getServerDefinitions(): Promise<CachedServerDefinition[]>;
745
742
  getServersForTool(toolName: string): Promise<string[]>;
743
+ getToolSchema(serverName: string, toolName: string): Promise<Record<string, unknown> | undefined>;
746
744
  getServersForResource(uri: string): Promise<string[]>;
747
745
  getPromptSkillByName(skillName: string): Promise<PromptSkillMatch | undefined>;
748
746
  getCachedFileSkills(): Promise<CachedFileSkillInfo[]>;
@@ -890,9 +888,10 @@ declare class StopServerService {
890
888
  * Input schema for the DescribeToolsTool
891
889
  * @property toolNames - Array of tool names to get detailed information about
892
890
  */
893
- interface DescribeToolsToolInput {
894
- toolNames: string[];
895
- }
891
+ declare const DescribeToolsToolInputSchema: z.ZodObject<{
892
+ toolNames: z.ZodArray<z.ZodString>;
893
+ }, z.core.$strip>;
894
+ type DescribeToolsToolInput = z.infer<typeof DescribeToolsToolInputSchema>;
896
895
  /**
897
896
  * DescribeToolsTool provides progressive disclosure of MCP tools and skills.
898
897
  *
@@ -998,6 +997,7 @@ declare class DescribeToolsTool implements Tool<DescribeToolsToolInput> {
998
997
  *
999
998
  * @returns Tool definition with description and input schema
1000
999
  */
1000
+ getInputSchema(): z.ZodObject<z.ZodRawShape>;
1001
1001
  getDefinition(): Promise<ToolDefinition>;
1002
1002
  /**
1003
1003
  * Executes tool description lookup for the requested tool and skill names.
@@ -1010,22 +1010,24 @@ declare class DescribeToolsTool implements Tool<DescribeToolsToolInput> {
1010
1010
  * @param input - Object containing toolNames array
1011
1011
  * @returns CallToolResult with tool/skill descriptions or error
1012
1012
  */
1013
- execute(input: DescribeToolsToolInput): Promise<CallToolResult>;
1013
+ execute(rawInput: Record<string, unknown>): Promise<CallToolResult>;
1014
1014
  }
1015
1015
  //#endregion
1016
1016
  //#region src/tools/SearchListToolsTool.d.ts
1017
- interface SearchListToolsToolInput {
1018
- capability?: string;
1019
- serverName?: string;
1020
- }
1017
+ declare const SearchListToolsToolInputSchema: z.ZodObject<{
1018
+ capability: z.ZodOptional<z.ZodString>;
1019
+ serverName: z.ZodOptional<z.ZodString>;
1020
+ }, z.core.$strip>;
1021
+ type SearchListToolsToolInput = z.infer<typeof SearchListToolsToolInputSchema>;
1021
1022
  declare class SearchListToolsTool implements Tool<SearchListToolsToolInput> {
1022
1023
  private readonly _clientManager;
1023
1024
  private readonly definitionsCacheService;
1024
1025
  static readonly TOOL_NAME = "list_tools";
1025
1026
  constructor(_clientManager: unknown, definitionsCacheService: DefinitionsCacheService);
1026
1027
  private formatToolName;
1028
+ getInputSchema(): z.ZodObject<z.ZodRawShape>;
1027
1029
  getDefinition(): Promise<ToolDefinition>;
1028
- execute(input: SearchListToolsToolInput): Promise<CallToolResult>;
1030
+ execute(rawInput: Record<string, unknown>): Promise<CallToolResult>;
1029
1031
  }
1030
1032
  //#endregion
1031
1033
  //#region src/tools/UseToolTool.d.ts
@@ -1034,10 +1036,11 @@ declare class SearchListToolsTool implements Tool<SearchListToolsToolInput> {
1034
1036
  * @property toolName - Name of the tool or skill to execute
1035
1037
  * @property toolArgs - Arguments to pass to the tool (from describe_tools schema)
1036
1038
  */
1037
- interface UseToolToolInput {
1038
- toolName: string;
1039
- toolArgs?: Record<string, unknown>;
1040
- }
1039
+ declare const UseToolToolInputSchema: z.ZodObject<{
1040
+ toolName: z.ZodString;
1041
+ toolArgs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
1042
+ }, z.core.$strip>;
1043
+ type UseToolToolInput = z.infer<typeof UseToolToolInputSchema>;
1041
1044
  /**
1042
1045
  * UseToolTool executes MCP tools and skills with proper error handling.
1043
1046
  *
@@ -1073,6 +1076,7 @@ declare class UseToolTool implements Tool<UseToolToolInput> {
1073
1076
  *
1074
1077
  * @returns The tool definition conforming to MCP spec
1075
1078
  */
1079
+ getInputSchema(): z.ZodObject<z.ZodRawShape>;
1076
1080
  getDefinition(): ToolDefinition;
1077
1081
  /**
1078
1082
  * Returns guidance message for skill invocation.
@@ -1084,6 +1088,12 @@ declare class UseToolTool implements Tool<UseToolToolInput> {
1084
1088
  * @param skill - The skill that was requested
1085
1089
  * @returns CallToolResult with guidance message
1086
1090
  */
1091
+ /**
1092
+ * Coerce toolArgs using the downstream tool's cached JSON Schema.
1093
+ * Converts the schema to Zod and runs coerceArgs so that string-encoded
1094
+ * objects/arrays are parsed before being forwarded to the downstream server.
1095
+ */
1096
+ private coerceToolArgs;
1087
1097
  private executeSkill;
1088
1098
  /**
1089
1099
  * Finds a prompt-based skill by name from all connected MCP servers.
@@ -1115,7 +1125,7 @@ declare class UseToolTool implements Tool<UseToolToolInput> {
1115
1125
  * @param input - The tool/skill name and optional arguments
1116
1126
  * @returns CallToolResult with execution output or error
1117
1127
  */
1118
- execute(input: UseToolToolInput): Promise<CallToolResult>;
1128
+ execute(rawInput: Record<string, unknown>): Promise<CallToolResult>;
1119
1129
  }
1120
1130
  //#endregion
1121
1131
  //#region src/transports/http.d.ts
package/dist/index.d.mts CHANGED
@@ -15,12 +15,7 @@ import { NodeTelemetryHandle } from "@agimon-ai/log-sink-mcp";
15
15
  interface ToolDefinition {
16
16
  name: string;
17
17
  description: string;
18
- inputSchema: {
19
- type: string;
20
- properties: Record<string, unknown>;
21
- required?: string[];
22
- additionalProperties?: boolean;
23
- };
18
+ inputSchema: Record<string, unknown>;
24
19
  _meta?: Record<string, unknown>;
25
20
  }
26
21
  /**
@@ -29,6 +24,7 @@ interface ToolDefinition {
29
24
  */
30
25
  interface Tool<TInput = unknown> {
31
26
  getDefinition(): ToolDefinition | Promise<ToolDefinition>;
27
+ getInputSchema(): z.ZodObject<z.ZodRawShape>;
32
28
  execute(input: TInput): Promise<CallToolResult>;
33
29
  }
34
30
  /**
@@ -744,6 +740,7 @@ declare class DefinitionsCacheService {
744
740
  getDefinitions(): Promise<DefinitionsCacheFile>;
745
741
  getServerDefinitions(): Promise<CachedServerDefinition[]>;
746
742
  getServersForTool(toolName: string): Promise<string[]>;
743
+ getToolSchema(serverName: string, toolName: string): Promise<Record<string, unknown> | undefined>;
747
744
  getServersForResource(uri: string): Promise<string[]>;
748
745
  getPromptSkillByName(skillName: string): Promise<PromptSkillMatch | undefined>;
749
746
  getCachedFileSkills(): Promise<CachedFileSkillInfo[]>;
@@ -891,9 +888,10 @@ declare class StopServerService {
891
888
  * Input schema for the DescribeToolsTool
892
889
  * @property toolNames - Array of tool names to get detailed information about
893
890
  */
894
- interface DescribeToolsToolInput {
895
- toolNames: string[];
896
- }
891
+ declare const DescribeToolsToolInputSchema: z.ZodObject<{
892
+ toolNames: z.ZodArray<z.ZodString>;
893
+ }, z.core.$strip>;
894
+ type DescribeToolsToolInput = z.infer<typeof DescribeToolsToolInputSchema>;
897
895
  /**
898
896
  * DescribeToolsTool provides progressive disclosure of MCP tools and skills.
899
897
  *
@@ -999,6 +997,7 @@ declare class DescribeToolsTool implements Tool<DescribeToolsToolInput> {
999
997
  *
1000
998
  * @returns Tool definition with description and input schema
1001
999
  */
1000
+ getInputSchema(): z.ZodObject<z.ZodRawShape>;
1002
1001
  getDefinition(): Promise<ToolDefinition>;
1003
1002
  /**
1004
1003
  * Executes tool description lookup for the requested tool and skill names.
@@ -1011,22 +1010,24 @@ declare class DescribeToolsTool implements Tool<DescribeToolsToolInput> {
1011
1010
  * @param input - Object containing toolNames array
1012
1011
  * @returns CallToolResult with tool/skill descriptions or error
1013
1012
  */
1014
- execute(input: DescribeToolsToolInput): Promise<CallToolResult>;
1013
+ execute(rawInput: Record<string, unknown>): Promise<CallToolResult>;
1015
1014
  }
1016
1015
  //#endregion
1017
1016
  //#region src/tools/SearchListToolsTool.d.ts
1018
- interface SearchListToolsToolInput {
1019
- capability?: string;
1020
- serverName?: string;
1021
- }
1017
+ declare const SearchListToolsToolInputSchema: z.ZodObject<{
1018
+ capability: z.ZodOptional<z.ZodString>;
1019
+ serverName: z.ZodOptional<z.ZodString>;
1020
+ }, z.core.$strip>;
1021
+ type SearchListToolsToolInput = z.infer<typeof SearchListToolsToolInputSchema>;
1022
1022
  declare class SearchListToolsTool implements Tool<SearchListToolsToolInput> {
1023
1023
  private readonly _clientManager;
1024
1024
  private readonly definitionsCacheService;
1025
1025
  static readonly TOOL_NAME = "list_tools";
1026
1026
  constructor(_clientManager: unknown, definitionsCacheService: DefinitionsCacheService);
1027
1027
  private formatToolName;
1028
+ getInputSchema(): z.ZodObject<z.ZodRawShape>;
1028
1029
  getDefinition(): Promise<ToolDefinition>;
1029
- execute(input: SearchListToolsToolInput): Promise<CallToolResult>;
1030
+ execute(rawInput: Record<string, unknown>): Promise<CallToolResult>;
1030
1031
  }
1031
1032
  //#endregion
1032
1033
  //#region src/tools/UseToolTool.d.ts
@@ -1035,10 +1036,11 @@ declare class SearchListToolsTool implements Tool<SearchListToolsToolInput> {
1035
1036
  * @property toolName - Name of the tool or skill to execute
1036
1037
  * @property toolArgs - Arguments to pass to the tool (from describe_tools schema)
1037
1038
  */
1038
- interface UseToolToolInput {
1039
- toolName: string;
1040
- toolArgs?: Record<string, unknown>;
1041
- }
1039
+ declare const UseToolToolInputSchema: z.ZodObject<{
1040
+ toolName: z.ZodString;
1041
+ toolArgs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
1042
+ }, z.core.$strip>;
1043
+ type UseToolToolInput = z.infer<typeof UseToolToolInputSchema>;
1042
1044
  /**
1043
1045
  * UseToolTool executes MCP tools and skills with proper error handling.
1044
1046
  *
@@ -1074,6 +1076,7 @@ declare class UseToolTool implements Tool<UseToolToolInput> {
1074
1076
  *
1075
1077
  * @returns The tool definition conforming to MCP spec
1076
1078
  */
1079
+ getInputSchema(): z.ZodObject<z.ZodRawShape>;
1077
1080
  getDefinition(): ToolDefinition;
1078
1081
  /**
1079
1082
  * Returns guidance message for skill invocation.
@@ -1085,6 +1088,12 @@ declare class UseToolTool implements Tool<UseToolToolInput> {
1085
1088
  * @param skill - The skill that was requested
1086
1089
  * @returns CallToolResult with guidance message
1087
1090
  */
1091
+ /**
1092
+ * Coerce toolArgs using the downstream tool's cached JSON Schema.
1093
+ * Converts the schema to Zod and runs coerceArgs so that string-encoded
1094
+ * objects/arrays are parsed before being forwarded to the downstream server.
1095
+ */
1096
+ private coerceToolArgs;
1088
1097
  private executeSkill;
1089
1098
  /**
1090
1099
  * Finds a prompt-based skill by name from all connected MCP servers.
@@ -1116,7 +1125,7 @@ declare class UseToolTool implements Tool<UseToolToolInput> {
1116
1125
  * @param input - The tool/skill name and optional arguments
1117
1126
  * @returns CallToolResult with execution output or error
1118
1127
  */
1119
- execute(input: UseToolToolInput): Promise<CallToolResult>;
1128
+ execute(rawInput: Record<string, unknown>): Promise<CallToolResult>;
1120
1129
  }
1121
1130
  //#endregion
1122
1131
  //#region src/transports/http.d.ts
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { C as DefinitionsCacheService, E as ConfigFetcherService, S as createProxyLogger, T as findConfigFile, _ as DescribeToolsTool, a as createProxyContainer, b as RuntimeStateService, c as createStdioHttpTransportHandler, d as StdioHttpTransportHandler, f as StdioTransportHandler, g as SearchListToolsTool, h as UseToolTool, i as createHttpTransportHandler, l as createStdioTransportHandler, m as HttpTransportHandler, n as createServer, p as SseTransportHandler, r as createSessionServer, s as createSseTransportHandler, t as TRANSPORT_MODE, u as initializeSharedServices, v as SkillService, w as generateServerId, x as McpClientManagerService, y as StopServerService } from "./src-NZo_eM6U.mjs";
1
+ import { C as DefinitionsCacheService, E as ConfigFetcherService, S as createProxyLogger, T as findConfigFile, _ as DescribeToolsTool, a as createProxyContainer, b as RuntimeStateService, c as createStdioHttpTransportHandler, d as StdioHttpTransportHandler, f as StdioTransportHandler, g as SearchListToolsTool, h as UseToolTool, i as createHttpTransportHandler, l as createStdioTransportHandler, m as HttpTransportHandler, n as createServer, p as SseTransportHandler, r as createSessionServer, s as createSseTransportHandler, t as TRANSPORT_MODE, u as initializeSharedServices, v as SkillService, w as generateServerId, x as McpClientManagerService, y as StopServerService } from "./src-Y-cyyxaw.mjs";
2
2
 
3
3
  export { ConfigFetcherService, DefinitionsCacheService, DescribeToolsTool, HttpTransportHandler, McpClientManagerService, RuntimeStateService, SearchListToolsTool, SkillService, SseTransportHandler, StdioHttpTransportHandler, StdioTransportHandler, StopServerService, TRANSPORT_MODE, UseToolTool, createHttpTransportHandler, createProxyContainer, createProxyLogger, createServer, createSessionServer, createSseTransportHandler, createStdioHttpTransportHandler, createStdioTransportHandler, findConfigFile, generateServerId, initializeSharedServices };
@@ -25,13 +25,14 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
  }) : target, mod));
26
26
 
27
27
  //#endregion
28
+ let __agimon_ai_foundation_validator = require("@agimon-ai/foundation-validator");
28
29
  let __modelcontextprotocol_sdk_server_index_js = require("@modelcontextprotocol/sdk/server/index.js");
29
30
  let __modelcontextprotocol_sdk_types_js = require("@modelcontextprotocol/sdk/types.js");
31
+ let zod = require("zod");
30
32
  let node_fs = require("node:fs");
31
33
  let node_fs_promises = require("node:fs/promises");
32
34
  let js_yaml = require("js-yaml");
33
35
  js_yaml = __toESM(js_yaml);
34
- let zod = require("zod");
35
36
  let node_crypto = require("node:crypto");
36
37
  let node_os = require("node:os");
37
38
  let node_path = require("node:path");
@@ -52,7 +53,7 @@ let __modelcontextprotocol_sdk_server_sse_js = require("@modelcontextprotocol/sd
52
53
  let __modelcontextprotocol_sdk_server_stdio_js = require("@modelcontextprotocol/sdk/server/stdio.js");
53
54
 
54
55
  //#region package.json
55
- var version = "0.7.1";
56
+ var version = "0.7.2";
56
57
 
57
58
  //#endregion
58
59
  //#region src/utils/mcpConfigSchema.ts
@@ -1365,6 +1366,9 @@ var DefinitionsCacheService = class {
1365
1366
  async getServersForTool(toolName) {
1366
1367
  return (await this.getServerDefinitions()).filter((serverDefinition) => serverDefinition.tools.some((tool) => tool.name === toolName)).map((serverDefinition) => serverDefinition.serverName);
1367
1368
  }
1369
+ async getToolSchema(serverName, toolName) {
1370
+ return (await this.getDefinitions()).servers[serverName]?.tools.find((t) => t.name === toolName)?.inputSchema;
1371
+ }
1368
1372
  async getServersForResource(uri) {
1369
1373
  return (await this.getServerDefinitions()).filter((serverDefinition) => serverDefinition.resources.some((resource) => resource.uri === uri)).map((serverDefinition) => serverDefinition.serverName);
1370
1374
  }
@@ -1810,7 +1814,7 @@ var McpClientManagerService = class {
1810
1814
  async createConnection(serverName, config) {
1811
1815
  const timeoutMs = config.timeout ?? DEFAULT_CONNECTION_TIMEOUT_MS;
1812
1816
  const client = new __modelcontextprotocol_sdk_client_index_js.Client({
1813
- name: `@agimon-ai/mcp-proxy-client`,
1817
+ name: "@agimon-ai/mcp-proxy-client",
1814
1818
  version: "0.1.0"
1815
1819
  }, { capabilities: {} });
1816
1820
  const mcpClient = new McpClient(serverName, config.transport, client, this.logger, {
@@ -2994,7 +2998,7 @@ var PrefetchService = class {
2994
2998
 
2995
2999
  //#endregion
2996
3000
  //#region src/templates/toolkit-description.liquid?raw
2997
- 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";
3001
+ 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 original-mcp-server=\"{{ 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";
2998
3002
 
2999
3003
  //#endregion
3000
3004
  //#region src/tools/DescribeToolsTool.ts
@@ -3010,6 +3014,11 @@ function formatSkillInstructions(name, instructions) {
3010
3014
  return `<command-message>The "${name}" skill is loading</command-message>\n${instructions}`;
3011
3015
  }
3012
3016
  /**
3017
+ * Input schema for the DescribeToolsTool
3018
+ * @property toolNames - Array of tool names to get detailed information about
3019
+ */
3020
+ const DescribeToolsToolInputSchema = zod.z.object({ toolNames: zod.z.array(zod.z.string().min(1)).min(1).describe("List of tool names to get detailed information about") });
3021
+ /**
3013
3022
  * DescribeToolsTool provides progressive disclosure of MCP tools and skills.
3014
3023
  *
3015
3024
  * This tool lists available tools from all connected MCP servers and skills
@@ -3266,25 +3275,15 @@ var DescribeToolsTool = class DescribeToolsTool {
3266
3275
  *
3267
3276
  * @returns Tool definition with description and input schema
3268
3277
  */
3278
+ getInputSchema() {
3279
+ return DescribeToolsToolInputSchema;
3280
+ }
3269
3281
  async getDefinition() {
3270
3282
  const { content } = await this.buildToolkitDescription();
3271
3283
  return {
3272
3284
  name: DescribeToolsTool.TOOL_NAME,
3273
3285
  description: content,
3274
- inputSchema: {
3275
- type: "object",
3276
- properties: { toolNames: {
3277
- type: "array",
3278
- items: {
3279
- type: "string",
3280
- minLength: 1
3281
- },
3282
- description: "List of tool names to get detailed information about",
3283
- minItems: 1
3284
- } },
3285
- required: ["toolNames"],
3286
- additionalProperties: false
3287
- }
3286
+ inputSchema: zod.z.toJSONSchema(DescribeToolsToolInputSchema, { reused: "inline" })
3288
3287
  };
3289
3288
  }
3290
3289
  /**
@@ -3298,9 +3297,9 @@ var DescribeToolsTool = class DescribeToolsTool {
3298
3297
  * @param input - Object containing toolNames array
3299
3298
  * @returns CallToolResult with tool/skill descriptions or error
3300
3299
  */
3301
- async execute(input) {
3300
+ async execute(rawInput) {
3302
3301
  try {
3303
- const { toolNames } = input;
3302
+ const { toolNames } = DescribeToolsToolInputSchema.parse(rawInput);
3304
3303
  const serverDefinitions = await this.definitionsCacheService.getServerDefinitions();
3305
3304
  if (!toolNames || toolNames.length === 0) return {
3306
3305
  content: [{
@@ -3474,6 +3473,10 @@ function getUniqueSortedCapabilities(tools) {
3474
3473
 
3475
3474
  //#endregion
3476
3475
  //#region src/tools/SearchListToolsTool.ts
3476
+ const SearchListToolsToolInputSchema = zod.z.object({
3477
+ capability: zod.z.string().optional().describe("Optional capability filter. Matches explicit capability tags first, then server summaries, server names, tool names, and tool descriptions."),
3478
+ serverName: zod.z.string().optional().describe("Optional server name filter.")
3479
+ });
3477
3480
  var SearchListToolsTool = class SearchListToolsTool {
3478
3481
  static TOOL_NAME = "list_tools";
3479
3482
  constructor(_clientManager, definitionsCacheService) {
@@ -3483,6 +3486,9 @@ var SearchListToolsTool = class SearchListToolsTool {
3483
3486
  formatToolName(toolName, serverName, toolToServers) {
3484
3487
  return (toolToServers.get(toolName) || []).length > 1 ? `${serverName}__${toolName}` : toolName;
3485
3488
  }
3489
+ getInputSchema() {
3490
+ return SearchListToolsToolInputSchema;
3491
+ }
3486
3492
  async getDefinition() {
3487
3493
  const serverDefinitions = await this.definitionsCacheService.getServerDefinitions();
3488
3494
  const capabilitySummary = serverDefinitions.length > 0 ? serverDefinitions.map((server) => {
@@ -3493,23 +3499,11 @@ var SearchListToolsTool = class SearchListToolsTool {
3493
3499
  return {
3494
3500
  name: SearchListToolsTool.TOOL_NAME,
3495
3501
  description: `Search proxied MCP tools by server capability summary.\n\nAvailable capabilities:\n${capabilitySummary}`,
3496
- inputSchema: {
3497
- type: "object",
3498
- properties: {
3499
- capability: {
3500
- type: "string",
3501
- description: "Optional capability filter. Matches explicit capability tags first, then server summaries, server names, tool names, and tool descriptions."
3502
- },
3503
- serverName: {
3504
- type: "string",
3505
- description: "Optional server name filter."
3506
- }
3507
- },
3508
- additionalProperties: false
3509
- }
3502
+ inputSchema: zod.z.toJSONSchema(SearchListToolsToolInputSchema, { reused: "inline" })
3510
3503
  };
3511
3504
  }
3512
- async execute(input) {
3505
+ async execute(rawInput) {
3506
+ const input = SearchListToolsToolInputSchema.parse(rawInput);
3513
3507
  const serverDefinitions = await this.definitionsCacheService.getServerDefinitions();
3514
3508
  const capabilityFilter = input.capability?.trim().toLowerCase();
3515
3509
  const serverNameFilter = input.serverName?.trim().toLowerCase();
@@ -3552,6 +3546,39 @@ var SearchListToolsTool = class SearchListToolsTool {
3552
3546
  //#endregion
3553
3547
  //#region src/tools/UseToolTool.ts
3554
3548
  /**
3549
+ * UseToolTool - Progressive disclosure tool for calling MCP tools and skills
3550
+ *
3551
+ * DESIGN PATTERNS:
3552
+ * - Tool pattern with getDefinition() and execute() methods
3553
+ * - Dependency injection for client manager and skill service
3554
+ * - Progressive disclosure pattern
3555
+ * - Proxy pattern for forwarding tool calls
3556
+ *
3557
+ * CODING STANDARDS:
3558
+ * - Implement Tool interface from ../types
3559
+ * - Use TOOL_NAME constant with snake_case
3560
+ * - Return CallToolResult with content array
3561
+ * - Handle errors with isError flag
3562
+ *
3563
+ * AVOID:
3564
+ * - Complex business logic in execute method
3565
+ * - Unhandled promise rejections
3566
+ * - Missing error handling
3567
+ *
3568
+ * NAMING CONVENTIONS:
3569
+ * - Tools from MCP servers use serverName__toolName format when clashing
3570
+ * - Skills use skill__skillName format (skill__ prefix)
3571
+ */
3572
+ /**
3573
+ * Input schema for UseToolTool
3574
+ * @property toolName - Name of the tool or skill to execute
3575
+ * @property toolArgs - Arguments to pass to the tool (from describe_tools schema)
3576
+ */
3577
+ const UseToolToolInputSchema = zod.z.object({
3578
+ toolName: zod.z.string().min(1).describe("Name of the tool to execute"),
3579
+ toolArgs: zod.z.record(zod.z.string(), zod.z.unknown()).optional().describe("Arguments to pass to the tool, as discovered from describe_tools")
3580
+ });
3581
+ /**
3555
3582
  * UseToolTool executes MCP tools and skills with proper error handling.
3556
3583
  *
3557
3584
  * This tool supports three invocation patterns:
@@ -3591,6 +3618,9 @@ var UseToolTool = class UseToolTool {
3591
3618
  *
3592
3619
  * @returns The tool definition conforming to MCP spec
3593
3620
  */
3621
+ getInputSchema() {
3622
+ return UseToolToolInputSchema;
3623
+ }
3594
3624
  getDefinition() {
3595
3625
  return {
3596
3626
  name: UseToolTool.TOOL_NAME,
@@ -3600,22 +3630,7 @@ var UseToolTool = class UseToolTool {
3600
3630
 
3601
3631
  IMPORTANT: Only use tools discovered from describe_tools with id="${this.serverId}".
3602
3632
  `,
3603
- inputSchema: {
3604
- type: "object",
3605
- properties: {
3606
- toolName: {
3607
- type: "string",
3608
- description: "Name of the tool to execute",
3609
- minLength: 1
3610
- },
3611
- toolArgs: {
3612
- type: "object",
3613
- description: "Arguments to pass to the tool, as discovered from describe_tools"
3614
- }
3615
- },
3616
- required: ["toolName"],
3617
- additionalProperties: false
3618
- }
3633
+ inputSchema: zod.z.toJSONSchema(UseToolToolInputSchema, { reused: "inline" })
3619
3634
  };
3620
3635
  }
3621
3636
  /**
@@ -3628,6 +3643,16 @@ IMPORTANT: Only use tools discovered from describe_tools with id="${this.serverI
3628
3643
  * @param skill - The skill that was requested
3629
3644
  * @returns CallToolResult with guidance message
3630
3645
  */
3646
+ /**
3647
+ * Coerce toolArgs using the downstream tool's cached JSON Schema.
3648
+ * Converts the schema to Zod and runs coerceArgs so that string-encoded
3649
+ * objects/arrays are parsed before being forwarded to the downstream server.
3650
+ */
3651
+ async coerceToolArgs(serverName, toolName, toolArgs) {
3652
+ const jsonSchema = await this.definitionsCacheService.getToolSchema(serverName, toolName);
3653
+ if (!jsonSchema) return toolArgs;
3654
+ return (0, __agimon_ai_foundation_validator.coerceArgs)(toolArgs, (0, __agimon_ai_foundation_validator.jsonSchemaToZod)(jsonSchema));
3655
+ }
3631
3656
  executeSkill(skill) {
3632
3657
  return { content: [{
3633
3658
  type: "text",
@@ -3673,9 +3698,9 @@ IMPORTANT: Only use tools discovered from describe_tools with id="${this.serverI
3673
3698
  * @param input - The tool/skill name and optional arguments
3674
3699
  * @returns CallToolResult with execution output or error
3675
3700
  */
3676
- async execute(input) {
3701
+ async execute(rawInput) {
3677
3702
  try {
3678
- const { toolName: inputToolName, toolArgs = {} } = input;
3703
+ const { toolName: inputToolName, toolArgs = {} } = UseToolToolInputSchema.parse(rawInput);
3679
3704
  if (inputToolName.startsWith(SKILL_PREFIX)) {
3680
3705
  const skillName = inputToolName.slice(SKILL_PREFIX.length);
3681
3706
  if (this.skillService) {
@@ -3704,7 +3729,8 @@ IMPORTANT: Only use tools discovered from describe_tools with id="${this.serverI
3704
3729
  isError: true
3705
3730
  };
3706
3731
  const reqTimeout = this.clientManager.getServerRequestTimeout(serverName);
3707
- return await client.callTool(actualToolName, toolArgs, reqTimeout ? { timeout: reqTimeout } : void 0);
3732
+ const coercedArgs = await this.coerceToolArgs(serverName, actualToolName, toolArgs);
3733
+ return await client.callTool(actualToolName, coercedArgs, reqTimeout ? { timeout: reqTimeout } : void 0);
3708
3734
  } catch (error) {
3709
3735
  return {
3710
3736
  content: [{
@@ -3741,7 +3767,8 @@ IMPORTANT: Only use tools discovered from describe_tools with id="${this.serverI
3741
3767
  const targetServerName = matchingServers[0];
3742
3768
  const client = await this.clientManager.ensureConnected(targetServerName);
3743
3769
  const targetReqTimeout = this.clientManager.getServerRequestTimeout(targetServerName);
3744
- return await client.callTool(actualToolName, toolArgs, targetReqTimeout ? { timeout: targetReqTimeout } : void 0);
3770
+ const coercedArgs = await this.coerceToolArgs(targetServerName, actualToolName, toolArgs);
3771
+ return await client.callTool(actualToolName, coercedArgs, targetReqTimeout ? { timeout: targetReqTimeout } : void 0);
3745
3772
  } catch (error) {
3746
3773
  return {
3747
3774
  content: [{
@@ -4975,21 +5002,27 @@ async function createSessionServer(shared) {
4975
5002
  })() : [await describeTools.getDefinition(), useToolWithCache.getDefinition()] }));
4976
5003
  server.setRequestHandler(__modelcontextprotocol_sdk_types_js.CallToolRequestSchema, async (request) => {
4977
5004
  const { name, arguments: args } = request.params;
4978
- if (name === DescribeToolsTool.TOOL_NAME) try {
4979
- return await describeTools.execute(args);
4980
- } catch (error) {
4981
- throw new Error(`Failed to execute ${name}: ${error instanceof Error ? error.message : String(error)}`);
4982
- }
4983
- if (name === UseToolTool.TOOL_NAME) try {
4984
- return await useToolWithCache.execute(args);
4985
- } catch (error) {
4986
- throw new Error(`Failed to execute ${name}: ${error instanceof Error ? error.message : String(error)}`);
4987
- }
4988
- if (name === SearchListToolsTool.TOOL_NAME && proxyMode === "search") try {
4989
- return await searchListTools.execute(args);
4990
- } catch (error) {
4991
- throw new Error(`Failed to execute ${name}: ${error instanceof Error ? error.message : String(error)}`);
4992
- }
5005
+ const executeWithCoercion = async (tool, toolName) => {
5006
+ const coerced = (0, __agimon_ai_foundation_validator.coerceArgs)(args ?? {}, tool.getInputSchema());
5007
+ try {
5008
+ return await tool.execute(coerced);
5009
+ } catch (error) {
5010
+ if (error instanceof zod.z.ZodError) return {
5011
+ content: [{
5012
+ type: "text",
5013
+ text: (0, __agimon_ai_foundation_validator.formatZodError)(error, {
5014
+ schemaName: toolName,
5015
+ schema: tool.getInputSchema()
5016
+ })
5017
+ }],
5018
+ isError: true
5019
+ };
5020
+ throw new Error(`Failed to execute ${toolName}: ${error instanceof Error ? error.message : String(error)}`);
5021
+ }
5022
+ };
5023
+ if (name === DescribeToolsTool.TOOL_NAME) return await executeWithCoercion(describeTools, name);
5024
+ if (name === UseToolTool.TOOL_NAME) return await executeWithCoercion(useToolWithCache, name);
5025
+ if (name === SearchListToolsTool.TOOL_NAME && proxyMode === "search") return await executeWithCoercion(searchListTools, name);
4993
5026
  if (proxyMode === "flat") return await useToolWithCache.execute({
4994
5027
  toolName: name,
4995
5028
  toolArgs: args || {}
@@ -1,9 +1,10 @@
1
+ import { coerceArgs, formatZodError, jsonSchemaToZod } from "@agimon-ai/foundation-validator";
1
2
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
3
  import { CallToolRequestSchema, ElicitRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
4
+ import { z } from "zod";
3
5
  import { existsSync } from "node:fs";
4
6
  import { access, mkdir, readFile, readdir, rm, stat, unlink, watch, writeFile } from "node:fs/promises";
5
7
  import yaml from "js-yaml";
6
- import { z } from "zod";
7
8
  import { createHash, randomBytes, randomUUID } from "node:crypto";
8
9
  import { homedir, tmpdir } from "node:os";
9
10
  import { dirname, isAbsolute, join, resolve } from "node:path";
@@ -24,7 +25,7 @@ import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
24
25
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
25
26
 
26
27
  //#region package.json
27
- var version = "0.7.1";
28
+ var version = "0.7.2";
28
29
 
29
30
  //#endregion
30
31
  //#region src/utils/mcpConfigSchema.ts
@@ -1337,6 +1338,9 @@ var DefinitionsCacheService = class {
1337
1338
  async getServersForTool(toolName) {
1338
1339
  return (await this.getServerDefinitions()).filter((serverDefinition) => serverDefinition.tools.some((tool) => tool.name === toolName)).map((serverDefinition) => serverDefinition.serverName);
1339
1340
  }
1341
+ async getToolSchema(serverName, toolName) {
1342
+ return (await this.getDefinitions()).servers[serverName]?.tools.find((t) => t.name === toolName)?.inputSchema;
1343
+ }
1340
1344
  async getServersForResource(uri) {
1341
1345
  return (await this.getServerDefinitions()).filter((serverDefinition) => serverDefinition.resources.some((resource) => resource.uri === uri)).map((serverDefinition) => serverDefinition.serverName);
1342
1346
  }
@@ -1782,7 +1786,7 @@ var McpClientManagerService = class {
1782
1786
  async createConnection(serverName, config) {
1783
1787
  const timeoutMs = config.timeout ?? DEFAULT_CONNECTION_TIMEOUT_MS;
1784
1788
  const client = new Client({
1785
- name: `@agimon-ai/mcp-proxy-client`,
1789
+ name: "@agimon-ai/mcp-proxy-client",
1786
1790
  version: "0.1.0"
1787
1791
  }, { capabilities: {} });
1788
1792
  const mcpClient = new McpClient(serverName, config.transport, client, this.logger, {
@@ -2966,7 +2970,7 @@ var PrefetchService = class {
2966
2970
 
2967
2971
  //#endregion
2968
2972
  //#region src/templates/toolkit-description.liquid?raw
2969
- 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";
2973
+ 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 original-mcp-server=\"{{ 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";
2970
2974
 
2971
2975
  //#endregion
2972
2976
  //#region src/tools/DescribeToolsTool.ts
@@ -2982,6 +2986,11 @@ function formatSkillInstructions(name, instructions) {
2982
2986
  return `<command-message>The "${name}" skill is loading</command-message>\n${instructions}`;
2983
2987
  }
2984
2988
  /**
2989
+ * Input schema for the DescribeToolsTool
2990
+ * @property toolNames - Array of tool names to get detailed information about
2991
+ */
2992
+ const DescribeToolsToolInputSchema = z.object({ toolNames: z.array(z.string().min(1)).min(1).describe("List of tool names to get detailed information about") });
2993
+ /**
2985
2994
  * DescribeToolsTool provides progressive disclosure of MCP tools and skills.
2986
2995
  *
2987
2996
  * This tool lists available tools from all connected MCP servers and skills
@@ -3238,25 +3247,15 @@ var DescribeToolsTool = class DescribeToolsTool {
3238
3247
  *
3239
3248
  * @returns Tool definition with description and input schema
3240
3249
  */
3250
+ getInputSchema() {
3251
+ return DescribeToolsToolInputSchema;
3252
+ }
3241
3253
  async getDefinition() {
3242
3254
  const { content } = await this.buildToolkitDescription();
3243
3255
  return {
3244
3256
  name: DescribeToolsTool.TOOL_NAME,
3245
3257
  description: content,
3246
- inputSchema: {
3247
- type: "object",
3248
- properties: { toolNames: {
3249
- type: "array",
3250
- items: {
3251
- type: "string",
3252
- minLength: 1
3253
- },
3254
- description: "List of tool names to get detailed information about",
3255
- minItems: 1
3256
- } },
3257
- required: ["toolNames"],
3258
- additionalProperties: false
3259
- }
3258
+ inputSchema: z.toJSONSchema(DescribeToolsToolInputSchema, { reused: "inline" })
3260
3259
  };
3261
3260
  }
3262
3261
  /**
@@ -3270,9 +3269,9 @@ var DescribeToolsTool = class DescribeToolsTool {
3270
3269
  * @param input - Object containing toolNames array
3271
3270
  * @returns CallToolResult with tool/skill descriptions or error
3272
3271
  */
3273
- async execute(input) {
3272
+ async execute(rawInput) {
3274
3273
  try {
3275
- const { toolNames } = input;
3274
+ const { toolNames } = DescribeToolsToolInputSchema.parse(rawInput);
3276
3275
  const serverDefinitions = await this.definitionsCacheService.getServerDefinitions();
3277
3276
  if (!toolNames || toolNames.length === 0) return {
3278
3277
  content: [{
@@ -3446,6 +3445,10 @@ function getUniqueSortedCapabilities(tools) {
3446
3445
 
3447
3446
  //#endregion
3448
3447
  //#region src/tools/SearchListToolsTool.ts
3448
+ const SearchListToolsToolInputSchema = z.object({
3449
+ capability: z.string().optional().describe("Optional capability filter. Matches explicit capability tags first, then server summaries, server names, tool names, and tool descriptions."),
3450
+ serverName: z.string().optional().describe("Optional server name filter.")
3451
+ });
3449
3452
  var SearchListToolsTool = class SearchListToolsTool {
3450
3453
  static TOOL_NAME = "list_tools";
3451
3454
  constructor(_clientManager, definitionsCacheService) {
@@ -3455,6 +3458,9 @@ var SearchListToolsTool = class SearchListToolsTool {
3455
3458
  formatToolName(toolName, serverName, toolToServers) {
3456
3459
  return (toolToServers.get(toolName) || []).length > 1 ? `${serverName}__${toolName}` : toolName;
3457
3460
  }
3461
+ getInputSchema() {
3462
+ return SearchListToolsToolInputSchema;
3463
+ }
3458
3464
  async getDefinition() {
3459
3465
  const serverDefinitions = await this.definitionsCacheService.getServerDefinitions();
3460
3466
  const capabilitySummary = serverDefinitions.length > 0 ? serverDefinitions.map((server) => {
@@ -3465,23 +3471,11 @@ var SearchListToolsTool = class SearchListToolsTool {
3465
3471
  return {
3466
3472
  name: SearchListToolsTool.TOOL_NAME,
3467
3473
  description: `Search proxied MCP tools by server capability summary.\n\nAvailable capabilities:\n${capabilitySummary}`,
3468
- inputSchema: {
3469
- type: "object",
3470
- properties: {
3471
- capability: {
3472
- type: "string",
3473
- description: "Optional capability filter. Matches explicit capability tags first, then server summaries, server names, tool names, and tool descriptions."
3474
- },
3475
- serverName: {
3476
- type: "string",
3477
- description: "Optional server name filter."
3478
- }
3479
- },
3480
- additionalProperties: false
3481
- }
3474
+ inputSchema: z.toJSONSchema(SearchListToolsToolInputSchema, { reused: "inline" })
3482
3475
  };
3483
3476
  }
3484
- async execute(input) {
3477
+ async execute(rawInput) {
3478
+ const input = SearchListToolsToolInputSchema.parse(rawInput);
3485
3479
  const serverDefinitions = await this.definitionsCacheService.getServerDefinitions();
3486
3480
  const capabilityFilter = input.capability?.trim().toLowerCase();
3487
3481
  const serverNameFilter = input.serverName?.trim().toLowerCase();
@@ -3524,6 +3518,39 @@ var SearchListToolsTool = class SearchListToolsTool {
3524
3518
  //#endregion
3525
3519
  //#region src/tools/UseToolTool.ts
3526
3520
  /**
3521
+ * UseToolTool - Progressive disclosure tool for calling MCP tools and skills
3522
+ *
3523
+ * DESIGN PATTERNS:
3524
+ * - Tool pattern with getDefinition() and execute() methods
3525
+ * - Dependency injection for client manager and skill service
3526
+ * - Progressive disclosure pattern
3527
+ * - Proxy pattern for forwarding tool calls
3528
+ *
3529
+ * CODING STANDARDS:
3530
+ * - Implement Tool interface from ../types
3531
+ * - Use TOOL_NAME constant with snake_case
3532
+ * - Return CallToolResult with content array
3533
+ * - Handle errors with isError flag
3534
+ *
3535
+ * AVOID:
3536
+ * - Complex business logic in execute method
3537
+ * - Unhandled promise rejections
3538
+ * - Missing error handling
3539
+ *
3540
+ * NAMING CONVENTIONS:
3541
+ * - Tools from MCP servers use serverName__toolName format when clashing
3542
+ * - Skills use skill__skillName format (skill__ prefix)
3543
+ */
3544
+ /**
3545
+ * Input schema for UseToolTool
3546
+ * @property toolName - Name of the tool or skill to execute
3547
+ * @property toolArgs - Arguments to pass to the tool (from describe_tools schema)
3548
+ */
3549
+ const UseToolToolInputSchema = z.object({
3550
+ toolName: z.string().min(1).describe("Name of the tool to execute"),
3551
+ toolArgs: z.record(z.string(), z.unknown()).optional().describe("Arguments to pass to the tool, as discovered from describe_tools")
3552
+ });
3553
+ /**
3527
3554
  * UseToolTool executes MCP tools and skills with proper error handling.
3528
3555
  *
3529
3556
  * This tool supports three invocation patterns:
@@ -3563,6 +3590,9 @@ var UseToolTool = class UseToolTool {
3563
3590
  *
3564
3591
  * @returns The tool definition conforming to MCP spec
3565
3592
  */
3593
+ getInputSchema() {
3594
+ return UseToolToolInputSchema;
3595
+ }
3566
3596
  getDefinition() {
3567
3597
  return {
3568
3598
  name: UseToolTool.TOOL_NAME,
@@ -3572,22 +3602,7 @@ var UseToolTool = class UseToolTool {
3572
3602
 
3573
3603
  IMPORTANT: Only use tools discovered from describe_tools with id="${this.serverId}".
3574
3604
  `,
3575
- inputSchema: {
3576
- type: "object",
3577
- properties: {
3578
- toolName: {
3579
- type: "string",
3580
- description: "Name of the tool to execute",
3581
- minLength: 1
3582
- },
3583
- toolArgs: {
3584
- type: "object",
3585
- description: "Arguments to pass to the tool, as discovered from describe_tools"
3586
- }
3587
- },
3588
- required: ["toolName"],
3589
- additionalProperties: false
3590
- }
3605
+ inputSchema: z.toJSONSchema(UseToolToolInputSchema, { reused: "inline" })
3591
3606
  };
3592
3607
  }
3593
3608
  /**
@@ -3600,6 +3615,16 @@ IMPORTANT: Only use tools discovered from describe_tools with id="${this.serverI
3600
3615
  * @param skill - The skill that was requested
3601
3616
  * @returns CallToolResult with guidance message
3602
3617
  */
3618
+ /**
3619
+ * Coerce toolArgs using the downstream tool's cached JSON Schema.
3620
+ * Converts the schema to Zod and runs coerceArgs so that string-encoded
3621
+ * objects/arrays are parsed before being forwarded to the downstream server.
3622
+ */
3623
+ async coerceToolArgs(serverName, toolName, toolArgs) {
3624
+ const jsonSchema = await this.definitionsCacheService.getToolSchema(serverName, toolName);
3625
+ if (!jsonSchema) return toolArgs;
3626
+ return coerceArgs(toolArgs, jsonSchemaToZod(jsonSchema));
3627
+ }
3603
3628
  executeSkill(skill) {
3604
3629
  return { content: [{
3605
3630
  type: "text",
@@ -3645,9 +3670,9 @@ IMPORTANT: Only use tools discovered from describe_tools with id="${this.serverI
3645
3670
  * @param input - The tool/skill name and optional arguments
3646
3671
  * @returns CallToolResult with execution output or error
3647
3672
  */
3648
- async execute(input) {
3673
+ async execute(rawInput) {
3649
3674
  try {
3650
- const { toolName: inputToolName, toolArgs = {} } = input;
3675
+ const { toolName: inputToolName, toolArgs = {} } = UseToolToolInputSchema.parse(rawInput);
3651
3676
  if (inputToolName.startsWith(SKILL_PREFIX)) {
3652
3677
  const skillName = inputToolName.slice(SKILL_PREFIX.length);
3653
3678
  if (this.skillService) {
@@ -3676,7 +3701,8 @@ IMPORTANT: Only use tools discovered from describe_tools with id="${this.serverI
3676
3701
  isError: true
3677
3702
  };
3678
3703
  const reqTimeout = this.clientManager.getServerRequestTimeout(serverName);
3679
- return await client.callTool(actualToolName, toolArgs, reqTimeout ? { timeout: reqTimeout } : void 0);
3704
+ const coercedArgs = await this.coerceToolArgs(serverName, actualToolName, toolArgs);
3705
+ return await client.callTool(actualToolName, coercedArgs, reqTimeout ? { timeout: reqTimeout } : void 0);
3680
3706
  } catch (error) {
3681
3707
  return {
3682
3708
  content: [{
@@ -3713,7 +3739,8 @@ IMPORTANT: Only use tools discovered from describe_tools with id="${this.serverI
3713
3739
  const targetServerName = matchingServers[0];
3714
3740
  const client = await this.clientManager.ensureConnected(targetServerName);
3715
3741
  const targetReqTimeout = this.clientManager.getServerRequestTimeout(targetServerName);
3716
- return await client.callTool(actualToolName, toolArgs, targetReqTimeout ? { timeout: targetReqTimeout } : void 0);
3742
+ const coercedArgs = await this.coerceToolArgs(targetServerName, actualToolName, toolArgs);
3743
+ return await client.callTool(actualToolName, coercedArgs, targetReqTimeout ? { timeout: targetReqTimeout } : void 0);
3717
3744
  } catch (error) {
3718
3745
  return {
3719
3746
  content: [{
@@ -4947,21 +4974,27 @@ async function createSessionServer(shared) {
4947
4974
  })() : [await describeTools.getDefinition(), useToolWithCache.getDefinition()] }));
4948
4975
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
4949
4976
  const { name, arguments: args } = request.params;
4950
- if (name === DescribeToolsTool.TOOL_NAME) try {
4951
- return await describeTools.execute(args);
4952
- } catch (error) {
4953
- throw new Error(`Failed to execute ${name}: ${error instanceof Error ? error.message : String(error)}`);
4954
- }
4955
- if (name === UseToolTool.TOOL_NAME) try {
4956
- return await useToolWithCache.execute(args);
4957
- } catch (error) {
4958
- throw new Error(`Failed to execute ${name}: ${error instanceof Error ? error.message : String(error)}`);
4959
- }
4960
- if (name === SearchListToolsTool.TOOL_NAME && proxyMode === "search") try {
4961
- return await searchListTools.execute(args);
4962
- } catch (error) {
4963
- throw new Error(`Failed to execute ${name}: ${error instanceof Error ? error.message : String(error)}`);
4964
- }
4977
+ const executeWithCoercion = async (tool, toolName) => {
4978
+ const coerced = coerceArgs(args ?? {}, tool.getInputSchema());
4979
+ try {
4980
+ return await tool.execute(coerced);
4981
+ } catch (error) {
4982
+ if (error instanceof z.ZodError) return {
4983
+ content: [{
4984
+ type: "text",
4985
+ text: formatZodError(error, {
4986
+ schemaName: toolName,
4987
+ schema: tool.getInputSchema()
4988
+ })
4989
+ }],
4990
+ isError: true
4991
+ };
4992
+ throw new Error(`Failed to execute ${toolName}: ${error instanceof Error ? error.message : String(error)}`);
4993
+ }
4994
+ };
4995
+ if (name === DescribeToolsTool.TOOL_NAME) return await executeWithCoercion(describeTools, name);
4996
+ if (name === UseToolTool.TOOL_NAME) return await executeWithCoercion(useToolWithCache, name);
4997
+ if (name === SearchListToolsTool.TOOL_NAME && proxyMode === "search") return await executeWithCoercion(searchListTools, name);
4965
4998
  if (proxyMode === "flat") return await useToolWithCache.execute({
4966
4999
  toolName: name,
4967
5000
  toolArgs: args || {}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agimon-ai/mcp-proxy",
3
3
  "description": "MCP proxy server package",
4
- "version": "0.7.2",
4
+ "version": "0.7.3",
5
5
  "license": "AGPL-3.0",
6
6
  "keywords": [
7
7
  "mcp",
@@ -27,10 +27,11 @@
27
27
  "gray-matter": "^4.0.3",
28
28
  "js-yaml": "^4.1.0",
29
29
  "liquidjs": "^10.21.0",
30
- "zod": "^3.24.1",
30
+ "zod": "4.3.6",
31
31
  "@agimon-ai/foundation-process-registry": "0.5.2",
32
32
  "@agimon-ai/foundation-port-registry": "0.5.2",
33
- "@agimon-ai/log-sink-mcp": "0.5.2"
33
+ "@agimon-ai/log-sink-mcp": "0.5.3",
34
+ "@agimon-ai/foundation-validator": "0.2.0"
34
35
  },
35
36
  "devDependencies": {
36
37
  "@types/js-yaml": "^4.0.9",