@agent-inspect/mcp 6.31.19 → 6.31.20

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/index.cjs CHANGED
@@ -49,15 +49,94 @@ function baseMetadata(options, overrides = {}) {
49
49
  };
50
50
  return { ...options.metadata ?? {}, ...metadata };
51
51
  }
52
+ var SDK_REQUEST_OPTION_KEYS = [
53
+ "signal",
54
+ "timeout",
55
+ "onprogress",
56
+ "resetTimeoutOnProgress",
57
+ "maxTotalTimeout",
58
+ "relatedRequestId",
59
+ "resumptionToken",
60
+ "onresumptiontoken"
61
+ ];
62
+ function isSdkRequestOptions(value) {
63
+ if (!value || typeof value !== "object") return false;
64
+ const obj = value;
65
+ return SDK_REQUEST_OPTION_KEYS.some((key) => key in obj);
66
+ }
67
+ function isAgentInspectMetadataBag(value) {
68
+ if (!value || typeof value !== "object") return false;
69
+ if (isSdkRequestOptions(value)) return false;
70
+ const obj = value;
71
+ if (!("metadata" in obj)) return false;
72
+ if ("parse" in obj) return false;
73
+ return true;
74
+ }
75
+ function extractCallMetadata(bag) {
76
+ if (bag.metadata && typeof bag.metadata === "object") {
77
+ return bag.metadata;
78
+ }
79
+ return {};
80
+ }
81
+ function resolveCallToolArgs(resultSchemaOrOptions, maybeOptions) {
82
+ if (maybeOptions !== void 0) {
83
+ let callMetadata = {};
84
+ let requestOptions;
85
+ if (isAgentInspectMetadataBag(maybeOptions)) {
86
+ callMetadata = extractCallMetadata(maybeOptions);
87
+ requestOptions = void 0;
88
+ } else if (isSdkRequestOptions(maybeOptions) || maybeOptions === null) {
89
+ requestOptions = maybeOptions && typeof maybeOptions === "object" ? maybeOptions : void 0;
90
+ } else if (maybeOptions && typeof maybeOptions === "object") {
91
+ requestOptions = maybeOptions;
92
+ }
93
+ return {
94
+ resultSchema: resultSchemaOrOptions,
95
+ requestOptions,
96
+ callMetadata
97
+ };
98
+ }
99
+ if (isAgentInspectMetadataBag(resultSchemaOrOptions)) {
100
+ return {
101
+ resultSchema: void 0,
102
+ requestOptions: void 0,
103
+ callMetadata: extractCallMetadata(resultSchemaOrOptions)
104
+ };
105
+ }
106
+ if (isSdkRequestOptions(resultSchemaOrOptions)) {
107
+ return {
108
+ resultSchema: void 0,
109
+ requestOptions: resultSchemaOrOptions,
110
+ callMetadata: {}
111
+ };
112
+ }
113
+ return {
114
+ resultSchema: resultSchemaOrOptions,
115
+ requestOptions: void 0,
116
+ callMetadata: {}
117
+ };
118
+ }
119
+ function invokeCallTool(callToolImpl, params, resultSchema, requestOptions) {
120
+ const fn = callToolImpl;
121
+ if (requestOptions !== void 0) {
122
+ return fn(params, resultSchema, requestOptions);
123
+ }
124
+ if (resultSchema !== void 0) {
125
+ return fn(params, resultSchema);
126
+ }
127
+ return fn(params);
128
+ }
52
129
  function wrapMcpClient(client, options = {}) {
53
130
  const maxSummaryLength = options.maxSummaryLength ?? 240;
54
131
  const listToolsImpl = typeof client.listTools === "function" ? client.listTools.bind(client) : void 0;
55
132
  const callToolImpl = client.callTool.bind(client);
56
- const wrappedListTools = listToolsImpl ? async (params) => agentInspect.step(
133
+ const wrappedListTools = listToolsImpl ? async (params, requestOptions) => agentInspect.step(
57
134
  "mcp:tools/list",
58
135
  async () => {
59
- const result = await listToolsImpl(params);
60
- return result;
136
+ if (requestOptions !== void 0) {
137
+ return listToolsImpl(params, requestOptions);
138
+ }
139
+ return listToolsImpl(params);
61
140
  },
62
141
  {
63
142
  type: "tool",
@@ -68,32 +147,13 @@ function wrapMcpClient(client, options = {}) {
68
147
  }
69
148
  ) : void 0;
70
149
  const wrappedCallTool = async (params, resultSchemaOrOptions, maybeOptions) => {
71
- let resultSchema;
72
- let callMetadata = {};
73
- if (maybeOptions && typeof maybeOptions === "object") {
74
- resultSchema = resultSchemaOrOptions;
75
- if (maybeOptions.metadata && typeof maybeOptions.metadata === "object") {
76
- callMetadata = maybeOptions.metadata;
77
- }
78
- } else if (resultSchemaOrOptions && typeof resultSchemaOrOptions === "object" && resultSchemaOrOptions !== null && "metadata" in resultSchemaOrOptions && !("parse" in resultSchemaOrOptions)) {
79
- const bag = resultSchemaOrOptions;
80
- if (bag.metadata && typeof bag.metadata === "object") {
81
- callMetadata = bag.metadata;
82
- }
83
- } else {
84
- resultSchema = resultSchemaOrOptions;
85
- }
150
+ const { resultSchema, requestOptions, callMetadata } = resolveCallToolArgs(
151
+ resultSchemaOrOptions,
152
+ maybeOptions
153
+ );
86
154
  return agentInspect.step(
87
155
  `mcp:${params.name}`,
88
- async () => {
89
- if (resultSchema !== void 0) {
90
- return callToolImpl(
91
- params,
92
- resultSchema
93
- );
94
- }
95
- return callToolImpl(params);
96
- },
156
+ async () => invokeCallTool(callToolImpl, params, resultSchema, requestOptions),
97
157
  {
98
158
  type: "tool",
99
159
  metadata: baseMetadata(options, {
@@ -130,6 +190,7 @@ function resetMcpToolCallIdsForTests() {
130
190
 
131
191
  exports.hashServerUrl = hashServerUrl;
132
192
  exports.resetMcpToolCallIdsForTests = resetMcpToolCallIdsForTests;
193
+ exports.resolveCallToolArgs = resolveCallToolArgs;
133
194
  exports.summarizeMcpValue = summarizeMcpValue;
134
195
  exports.wrapMcpClient = wrapMcpClient;
135
196
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/summarize.ts","../src/wrap.ts"],"names":["step"],"mappings":"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","file":"index.cjs","sourcesContent":["const DEFAULT_MAX_SUMMARY_LENGTH = 240;\n\nfunction fallbackString(value: unknown): string {\n try {\n return String(value);\n } catch {\n return \"[unserializable]\";\n }\n}\n\nexport function summarizeMcpValue(\n value: unknown,\n maxLength = DEFAULT_MAX_SUMMARY_LENGTH,\n): string {\n let text: string;\n try {\n if (typeof value === \"string\") {\n text = value;\n } else {\n // JSON.stringify returns undefined (not a string) for undefined,\n // functions, and symbols; falling through with undefined would crash\n // instrumentation at text.length below.\n const serialized = JSON.stringify(value);\n text = serialized === undefined ? fallbackString(value) : serialized;\n }\n } catch {\n text = fallbackString(value);\n }\n if (text.length <= maxLength) return text;\n return `${text.slice(0, Math.max(0, maxLength - 3))}...`;\n}\n\nexport function hashServerUrl(url: string): string {\n let hash = 0;\n for (let i = 0; i < url.length; i += 1) {\n hash = (hash * 31 + url.charCodeAt(i)) >>> 0;\n }\n return hash.toString(16).padStart(8, \"0\");\n}\n","import { step } from \"agent-inspect\";\n\nimport { hashServerUrl, summarizeMcpValue } from \"./summarize.js\";\nimport type {\n McpClientLike,\n McpClientTracerOptions,\n McpTraceMetadata,\n} from \"./types.js\";\n\nlet toolCallCounter = 0;\n\nfunction nextToolCallId(prefix?: string): string {\n toolCallCounter += 1;\n const base = prefix?.trim() || \"mcp\";\n return `${base}-${toolCallCounter}`;\n}\n\nfunction baseMetadata(\n options: McpClientTracerOptions,\n overrides: Partial<McpTraceMetadata> = {},\n): Record<string, unknown> {\n const metadata: McpTraceMetadata = {\n source: { type: \"mcp-client\" },\n ...(options.serverName ? { mcpServerName: options.serverName } : {}),\n ...(options.serverUrl\n ? { mcpServerUrlHash: hashServerUrl(options.serverUrl) }\n : {}),\n ...(options.sessionId ? { sessionId: options.sessionId } : {}),\n ...overrides,\n };\n return { ...(options.metadata ?? {}), ...metadata };\n}\n\n/**\n * Wraps an MCP client so tools/list and tools/call emit local tool steps.\n * Telemetry only — does not proxy network behavior beyond the wrapped client.\n *\n * Uses a Proxy over the original client so prototype methods (`connect`,\n * `close`, `listResources`, …), private SDK state, and `instanceof` stay intact.\n * A shallow object spread would drop prototype methods and copy private fields.\n */\nexport function wrapMcpClient<T extends McpClientLike>(\n client: T,\n options: McpClientTracerOptions = {},\n): T {\n const maxSummaryLength = options.maxSummaryLength ?? 240;\n\n const listToolsImpl =\n typeof client.listTools === \"function\"\n ? client.listTools.bind(client)\n : undefined;\n const callToolImpl = client.callTool.bind(client);\n\n const wrappedListTools = listToolsImpl\n ? async (params?: unknown) =>\n step(\n \"mcp:tools/list\",\n async () => {\n const result = await listToolsImpl(params);\n return result;\n },\n {\n type: \"tool\",\n metadata: baseMetadata(options, {\n toolName: \"tools/list\",\n toolCallId: nextToolCallId(options.toolCallIdPrefix),\n }),\n },\n )\n : undefined;\n\n const wrappedCallTool = async (\n params: Parameters<McpClientLike[\"callTool\"]>[0],\n resultSchemaOrOptions?: unknown,\n maybeOptions?: { metadata?: Record<string, unknown> },\n ) => {\n let resultSchema: unknown;\n let callMetadata: Record<string, unknown> = {};\n if (maybeOptions && typeof maybeOptions === \"object\") {\n resultSchema = resultSchemaOrOptions;\n if (maybeOptions.metadata && typeof maybeOptions.metadata === \"object\") {\n callMetadata = maybeOptions.metadata;\n }\n } else if (\n resultSchemaOrOptions &&\n typeof resultSchemaOrOptions === \"object\" &&\n resultSchemaOrOptions !== null &&\n \"metadata\" in resultSchemaOrOptions &&\n !(\"parse\" in (resultSchemaOrOptions as object))\n ) {\n const bag = resultSchemaOrOptions as { metadata?: Record<string, unknown> };\n if (bag.metadata && typeof bag.metadata === \"object\") {\n callMetadata = bag.metadata;\n }\n } else {\n resultSchema = resultSchemaOrOptions;\n }\n\n return step(\n `mcp:${params.name}`,\n async () => {\n if (resultSchema !== undefined) {\n return (callToolImpl as (...args: unknown[]) => Promise<unknown>)(\n params,\n resultSchema,\n );\n }\n return callToolImpl(params);\n },\n {\n type: \"tool\",\n metadata: baseMetadata(options, {\n toolName: params.name,\n toolCallId: nextToolCallId(options.toolCallIdPrefix),\n argumentSummary: summarizeMcpValue(\n params.arguments ?? {},\n maxSummaryLength,\n ),\n ...callMetadata,\n }),\n },\n );\n };\n\n return new Proxy(client, {\n get(target, property, receiver) {\n if (property === \"listTools\" && wrappedListTools !== undefined) {\n return wrappedListTools;\n }\n if (property === \"callTool\") {\n return wrappedCallTool;\n }\n const value = Reflect.get(target, property, receiver);\n if (typeof value === \"function\") {\n return value.bind(target);\n }\n return value;\n },\n }) as T;\n}\n\n/** @internal resets tool call ids for deterministic tests */\nexport function resetMcpToolCallIdsForTests(): void {\n toolCallCounter = 0;\n}\n"]}
1
+ {"version":3,"sources":["../src/summarize.ts","../src/wrap.ts"],"names":["step"],"mappings":"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","file":"index.cjs","sourcesContent":["const DEFAULT_MAX_SUMMARY_LENGTH = 240;\n\nfunction fallbackString(value: unknown): string {\n try {\n return String(value);\n } catch {\n return \"[unserializable]\";\n }\n}\n\nexport function summarizeMcpValue(\n value: unknown,\n maxLength = DEFAULT_MAX_SUMMARY_LENGTH,\n): string {\n let text: string;\n try {\n if (typeof value === \"string\") {\n text = value;\n } else {\n // JSON.stringify returns undefined (not a string) for undefined,\n // functions, and symbols; falling through with undefined would crash\n // instrumentation at text.length below.\n const serialized = JSON.stringify(value);\n text = serialized === undefined ? fallbackString(value) : serialized;\n }\n } catch {\n text = fallbackString(value);\n }\n if (text.length <= maxLength) return text;\n return `${text.slice(0, Math.max(0, maxLength - 3))}...`;\n}\n\nexport function hashServerUrl(url: string): string {\n let hash = 0;\n for (let i = 0; i < url.length; i += 1) {\n hash = (hash * 31 + url.charCodeAt(i)) >>> 0;\n }\n return hash.toString(16).padStart(8, \"0\");\n}\n","import { step } from \"agent-inspect\";\n\nimport { hashServerUrl, summarizeMcpValue } from \"./summarize.js\";\nimport type {\n McpClientLike,\n McpClientTracerOptions,\n McpRequestOptions,\n McpTraceMetadata,\n} from \"./types.js\";\n\nlet toolCallCounter = 0;\n\nfunction nextToolCallId(prefix?: string): string {\n toolCallCounter += 1;\n const base = prefix?.trim() || \"mcp\";\n return `${base}-${toolCallCounter}`;\n}\n\nfunction baseMetadata(\n options: McpClientTracerOptions,\n overrides: Partial<McpTraceMetadata> = {},\n): Record<string, unknown> {\n const metadata: McpTraceMetadata = {\n source: { type: \"mcp-client\" },\n ...(options.serverName ? { mcpServerName: options.serverName } : {}),\n ...(options.serverUrl\n ? { mcpServerUrlHash: hashServerUrl(options.serverUrl) }\n : {}),\n ...(options.sessionId ? { sessionId: options.sessionId } : {}),\n ...overrides,\n };\n return { ...(options.metadata ?? {}), ...metadata };\n}\n\n/** SDK RequestOptions keys — must never be swallowed as AgentInspect metadata. */\nconst SDK_REQUEST_OPTION_KEYS = [\n \"signal\",\n \"timeout\",\n \"onprogress\",\n \"resetTimeoutOnProgress\",\n \"maxTotalTimeout\",\n \"relatedRequestId\",\n \"resumptionToken\",\n \"onresumptiontoken\",\n] as const;\n\nfunction isSdkRequestOptions(value: unknown): value is McpRequestOptions {\n if (!value || typeof value !== \"object\") return false;\n const obj = value as Record<string, unknown>;\n return SDK_REQUEST_OPTION_KEYS.some((key) => key in obj);\n}\n\n/**\n * AgentInspect per-call metadata bag: `{ metadata: {...} }` without SDK option keys.\n * Must not consume ordinary SDK RequestOptions that happen to be objects.\n */\nfunction isAgentInspectMetadataBag(\n value: unknown,\n): value is { metadata?: Record<string, unknown> } {\n if (!value || typeof value !== \"object\") return false;\n if (isSdkRequestOptions(value)) return false;\n const obj = value as Record<string, unknown>;\n if (!(\"metadata\" in obj)) return false;\n // Zod/result schemas expose parse — never treat those as AI bags.\n if (\"parse\" in obj) return false;\n return true;\n}\n\nfunction extractCallMetadata(bag: {\n metadata?: Record<string, unknown>;\n}): Record<string, unknown> {\n if (bag.metadata && typeof bag.metadata === \"object\") {\n return bag.metadata;\n }\n return {};\n}\n\n/**\n * Resolve SDK callTool arity:\n * callTool(params, resultSchema?, requestOptions?)\n * plus AgentInspect overloads that peel `{ metadata }` without dropping RequestOptions.\n */\nexport function resolveCallToolArgs(\n resultSchemaOrOptions?: unknown,\n maybeOptions?: unknown,\n): {\n resultSchema: unknown;\n requestOptions: McpRequestOptions | undefined;\n callMetadata: Record<string, unknown>;\n} {\n // Three-arg form: (params, schema|undefined, options)\n if (maybeOptions !== undefined) {\n let callMetadata: Record<string, unknown> = {};\n let requestOptions: McpRequestOptions | undefined;\n\n if (isAgentInspectMetadataBag(maybeOptions)) {\n callMetadata = extractCallMetadata(maybeOptions);\n // Remaining SDK keys (if any were mixed in) still forward — but AI bags exclude them.\n requestOptions = undefined;\n } else if (isSdkRequestOptions(maybeOptions) || maybeOptions === null) {\n requestOptions =\n maybeOptions && typeof maybeOptions === \"object\"\n ? (maybeOptions as McpRequestOptions)\n : undefined;\n } else if (maybeOptions && typeof maybeOptions === \"object\") {\n // Unknown object third arg — forward as RequestOptions to preserve caller intent.\n requestOptions = maybeOptions as McpRequestOptions;\n }\n\n return {\n resultSchema: resultSchemaOrOptions,\n requestOptions,\n callMetadata,\n };\n }\n\n // Two-arg form: (params, schema) OR (params, { metadata }) OR (params, RequestOptions)\n if (isAgentInspectMetadataBag(resultSchemaOrOptions)) {\n return {\n resultSchema: undefined,\n requestOptions: undefined,\n callMetadata: extractCallMetadata(resultSchemaOrOptions),\n };\n }\n\n if (isSdkRequestOptions(resultSchemaOrOptions)) {\n return {\n resultSchema: undefined,\n requestOptions: resultSchemaOrOptions,\n callMetadata: {},\n };\n }\n\n return {\n resultSchema: resultSchemaOrOptions,\n requestOptions: undefined,\n callMetadata: {},\n };\n}\n\nfunction invokeCallTool(\n callToolImpl: McpClientLike[\"callTool\"],\n params: Parameters<McpClientLike[\"callTool\"]>[0],\n resultSchema: unknown,\n requestOptions: McpRequestOptions | undefined,\n): Promise<unknown> {\n const fn = callToolImpl as (\n p: unknown,\n schema?: unknown,\n opts?: unknown,\n ) => Promise<unknown>;\n if (requestOptions !== undefined) {\n return fn(params, resultSchema, requestOptions);\n }\n if (resultSchema !== undefined) {\n return fn(params, resultSchema);\n }\n return fn(params);\n}\n\n/**\n * Wraps an MCP client so tools/list and tools/call emit local tool steps.\n * Telemetry only — does not proxy network behavior beyond the wrapped client.\n *\n * Uses a Proxy over the original client so prototype methods (`connect`,\n * `close`, `listResources`, …), private SDK state, and `instanceof` stay intact.\n * A shallow object spread would drop prototype methods and copy private fields.\n *\n * Forwards the real SDK argument positions, including `RequestOptions`\n * (`signal`, `timeout`, progress callbacks). Does not fake cancellation while\n * still dispatching the underlying request.\n */\nexport function wrapMcpClient<T extends McpClientLike>(\n client: T,\n options: McpClientTracerOptions = {},\n): T {\n const maxSummaryLength = options.maxSummaryLength ?? 240;\n\n const listToolsImpl =\n typeof client.listTools === \"function\"\n ? client.listTools.bind(client)\n : undefined;\n const callToolImpl = client.callTool.bind(client);\n\n const wrappedListTools = listToolsImpl\n ? async (params?: unknown, requestOptions?: McpRequestOptions) =>\n step(\n \"mcp:tools/list\",\n async () => {\n if (requestOptions !== undefined) {\n return (\n listToolsImpl as (\n p?: unknown,\n opts?: unknown,\n ) => Promise<unknown>\n )(params, requestOptions);\n }\n return listToolsImpl(params);\n },\n {\n type: \"tool\",\n metadata: baseMetadata(options, {\n toolName: \"tools/list\",\n toolCallId: nextToolCallId(options.toolCallIdPrefix),\n }),\n },\n )\n : undefined;\n\n const wrappedCallTool = async (\n params: Parameters<McpClientLike[\"callTool\"]>[0],\n resultSchemaOrOptions?: unknown,\n maybeOptions?: unknown,\n ) => {\n const { resultSchema, requestOptions, callMetadata } = resolveCallToolArgs(\n resultSchemaOrOptions,\n maybeOptions,\n );\n\n return step(\n `mcp:${params.name}`,\n async () =>\n invokeCallTool(callToolImpl, params, resultSchema, requestOptions),\n {\n type: \"tool\",\n metadata: baseMetadata(options, {\n toolName: params.name,\n toolCallId: nextToolCallId(options.toolCallIdPrefix),\n argumentSummary: summarizeMcpValue(\n params.arguments ?? {},\n maxSummaryLength,\n ),\n ...callMetadata,\n }),\n },\n );\n };\n\n return new Proxy(client, {\n get(target, property, receiver) {\n if (property === \"listTools\" && wrappedListTools !== undefined) {\n return wrappedListTools;\n }\n if (property === \"callTool\") {\n return wrappedCallTool;\n }\n const value = Reflect.get(target, property, receiver);\n if (typeof value === \"function\") {\n return value.bind(target);\n }\n return value;\n },\n }) as T;\n}\n\n/** @internal resets tool call ids for deterministic tests */\nexport function resetMcpToolCallIdsForTests(): void {\n toolCallCounter = 0;\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -15,13 +15,34 @@ interface McpCallToolResult {
15
15
  isError?: boolean;
16
16
  structuredContent?: unknown;
17
17
  }
18
+ /**
19
+ * Subset of MCP SDK `RequestOptions` forwarded by the wrapper.
20
+ * Compatible with @modelcontextprotocol/sdk without requiring it at runtime.
21
+ */
22
+ interface McpRequestOptions {
23
+ signal?: AbortSignal;
24
+ timeout?: number;
25
+ onprogress?: (...args: unknown[]) => void;
26
+ resetTimeoutOnProgress?: boolean;
27
+ maxTotalTimeout?: number;
28
+ relatedRequestId?: string;
29
+ resumptionToken?: string;
30
+ onresumptiontoken?: (...args: unknown[]) => void;
31
+ /** AgentInspect per-call metadata (optional; never consumes SDK option keys). */
32
+ metadata?: Record<string, unknown>;
33
+ [key: string]: unknown;
34
+ }
18
35
  /**
19
36
  * Minimal MCP client surface for local tracing. Compatible with common SDK
20
37
  * client shapes without requiring @modelcontextprotocol/sdk at runtime.
38
+ *
39
+ * Matches SDK arity: `callTool(params, resultSchema?, requestOptions?)` and
40
+ * `listTools(params?, requestOptions?)`. AgentInspect also accepts a
41
+ * `{ metadata }` bag in place of schema/options when it is not RequestOptions-shaped.
21
42
  */
22
43
  interface McpClientLike {
23
- listTools?: (params?: unknown) => Promise<McpListToolsResult>;
24
- callTool: (params: McpCallToolParams, resultSchemaOrOptions?: unknown, options?: {
44
+ listTools?: (params?: unknown, options?: McpRequestOptions) => Promise<McpListToolsResult>;
45
+ callTool: (params: McpCallToolParams, resultSchemaOrOptions?: unknown, options?: McpRequestOptions | {
25
46
  metadata?: Record<string, unknown>;
26
47
  }) => Promise<McpCallToolResult>;
27
48
  }
@@ -52,6 +73,16 @@ interface McpTraceMetadata {
52
73
  declare function summarizeMcpValue(value: unknown, maxLength?: number): string;
53
74
  declare function hashServerUrl(url: string): string;
54
75
 
76
+ /**
77
+ * Resolve SDK callTool arity:
78
+ * callTool(params, resultSchema?, requestOptions?)
79
+ * plus AgentInspect overloads that peel `{ metadata }` without dropping RequestOptions.
80
+ */
81
+ declare function resolveCallToolArgs(resultSchemaOrOptions?: unknown, maybeOptions?: unknown): {
82
+ resultSchema: unknown;
83
+ requestOptions: McpRequestOptions | undefined;
84
+ callMetadata: Record<string, unknown>;
85
+ };
55
86
  /**
56
87
  * Wraps an MCP client so tools/list and tools/call emit local tool steps.
57
88
  * Telemetry only — does not proxy network behavior beyond the wrapped client.
@@ -59,9 +90,13 @@ declare function hashServerUrl(url: string): string;
59
90
  * Uses a Proxy over the original client so prototype methods (`connect`,
60
91
  * `close`, `listResources`, …), private SDK state, and `instanceof` stay intact.
61
92
  * A shallow object spread would drop prototype methods and copy private fields.
93
+ *
94
+ * Forwards the real SDK argument positions, including `RequestOptions`
95
+ * (`signal`, `timeout`, progress callbacks). Does not fake cancellation while
96
+ * still dispatching the underlying request.
62
97
  */
63
98
  declare function wrapMcpClient<T extends McpClientLike>(client: T, options?: McpClientTracerOptions): T;
64
99
  /** @internal resets tool call ids for deterministic tests */
65
100
  declare function resetMcpToolCallIdsForTests(): void;
66
101
 
67
- export { type McpCallToolParams, type McpCallToolResult, type McpClientLike, type McpClientTracerOptions, type McpListToolsResult, type McpToolDescriptor, type McpTraceMetadata, hashServerUrl, resetMcpToolCallIdsForTests, summarizeMcpValue, wrapMcpClient };
102
+ export { type McpCallToolParams, type McpCallToolResult, type McpClientLike, type McpClientTracerOptions, type McpListToolsResult, type McpRequestOptions, type McpToolDescriptor, type McpTraceMetadata, hashServerUrl, resetMcpToolCallIdsForTests, resolveCallToolArgs, summarizeMcpValue, wrapMcpClient };
package/dist/index.d.ts CHANGED
@@ -15,13 +15,34 @@ interface McpCallToolResult {
15
15
  isError?: boolean;
16
16
  structuredContent?: unknown;
17
17
  }
18
+ /**
19
+ * Subset of MCP SDK `RequestOptions` forwarded by the wrapper.
20
+ * Compatible with @modelcontextprotocol/sdk without requiring it at runtime.
21
+ */
22
+ interface McpRequestOptions {
23
+ signal?: AbortSignal;
24
+ timeout?: number;
25
+ onprogress?: (...args: unknown[]) => void;
26
+ resetTimeoutOnProgress?: boolean;
27
+ maxTotalTimeout?: number;
28
+ relatedRequestId?: string;
29
+ resumptionToken?: string;
30
+ onresumptiontoken?: (...args: unknown[]) => void;
31
+ /** AgentInspect per-call metadata (optional; never consumes SDK option keys). */
32
+ metadata?: Record<string, unknown>;
33
+ [key: string]: unknown;
34
+ }
18
35
  /**
19
36
  * Minimal MCP client surface for local tracing. Compatible with common SDK
20
37
  * client shapes without requiring @modelcontextprotocol/sdk at runtime.
38
+ *
39
+ * Matches SDK arity: `callTool(params, resultSchema?, requestOptions?)` and
40
+ * `listTools(params?, requestOptions?)`. AgentInspect also accepts a
41
+ * `{ metadata }` bag in place of schema/options when it is not RequestOptions-shaped.
21
42
  */
22
43
  interface McpClientLike {
23
- listTools?: (params?: unknown) => Promise<McpListToolsResult>;
24
- callTool: (params: McpCallToolParams, resultSchemaOrOptions?: unknown, options?: {
44
+ listTools?: (params?: unknown, options?: McpRequestOptions) => Promise<McpListToolsResult>;
45
+ callTool: (params: McpCallToolParams, resultSchemaOrOptions?: unknown, options?: McpRequestOptions | {
25
46
  metadata?: Record<string, unknown>;
26
47
  }) => Promise<McpCallToolResult>;
27
48
  }
@@ -52,6 +73,16 @@ interface McpTraceMetadata {
52
73
  declare function summarizeMcpValue(value: unknown, maxLength?: number): string;
53
74
  declare function hashServerUrl(url: string): string;
54
75
 
76
+ /**
77
+ * Resolve SDK callTool arity:
78
+ * callTool(params, resultSchema?, requestOptions?)
79
+ * plus AgentInspect overloads that peel `{ metadata }` without dropping RequestOptions.
80
+ */
81
+ declare function resolveCallToolArgs(resultSchemaOrOptions?: unknown, maybeOptions?: unknown): {
82
+ resultSchema: unknown;
83
+ requestOptions: McpRequestOptions | undefined;
84
+ callMetadata: Record<string, unknown>;
85
+ };
55
86
  /**
56
87
  * Wraps an MCP client so tools/list and tools/call emit local tool steps.
57
88
  * Telemetry only — does not proxy network behavior beyond the wrapped client.
@@ -59,9 +90,13 @@ declare function hashServerUrl(url: string): string;
59
90
  * Uses a Proxy over the original client so prototype methods (`connect`,
60
91
  * `close`, `listResources`, …), private SDK state, and `instanceof` stay intact.
61
92
  * A shallow object spread would drop prototype methods and copy private fields.
93
+ *
94
+ * Forwards the real SDK argument positions, including `RequestOptions`
95
+ * (`signal`, `timeout`, progress callbacks). Does not fake cancellation while
96
+ * still dispatching the underlying request.
62
97
  */
63
98
  declare function wrapMcpClient<T extends McpClientLike>(client: T, options?: McpClientTracerOptions): T;
64
99
  /** @internal resets tool call ids for deterministic tests */
65
100
  declare function resetMcpToolCallIdsForTests(): void;
66
101
 
67
- export { type McpCallToolParams, type McpCallToolResult, type McpClientLike, type McpClientTracerOptions, type McpListToolsResult, type McpToolDescriptor, type McpTraceMetadata, hashServerUrl, resetMcpToolCallIdsForTests, summarizeMcpValue, wrapMcpClient };
102
+ export { type McpCallToolParams, type McpCallToolResult, type McpClientLike, type McpClientTracerOptions, type McpListToolsResult, type McpRequestOptions, type McpToolDescriptor, type McpTraceMetadata, hashServerUrl, resetMcpToolCallIdsForTests, resolveCallToolArgs, summarizeMcpValue, wrapMcpClient };
package/dist/index.mjs CHANGED
@@ -47,15 +47,94 @@ function baseMetadata(options, overrides = {}) {
47
47
  };
48
48
  return { ...options.metadata ?? {}, ...metadata };
49
49
  }
50
+ var SDK_REQUEST_OPTION_KEYS = [
51
+ "signal",
52
+ "timeout",
53
+ "onprogress",
54
+ "resetTimeoutOnProgress",
55
+ "maxTotalTimeout",
56
+ "relatedRequestId",
57
+ "resumptionToken",
58
+ "onresumptiontoken"
59
+ ];
60
+ function isSdkRequestOptions(value) {
61
+ if (!value || typeof value !== "object") return false;
62
+ const obj = value;
63
+ return SDK_REQUEST_OPTION_KEYS.some((key) => key in obj);
64
+ }
65
+ function isAgentInspectMetadataBag(value) {
66
+ if (!value || typeof value !== "object") return false;
67
+ if (isSdkRequestOptions(value)) return false;
68
+ const obj = value;
69
+ if (!("metadata" in obj)) return false;
70
+ if ("parse" in obj) return false;
71
+ return true;
72
+ }
73
+ function extractCallMetadata(bag) {
74
+ if (bag.metadata && typeof bag.metadata === "object") {
75
+ return bag.metadata;
76
+ }
77
+ return {};
78
+ }
79
+ function resolveCallToolArgs(resultSchemaOrOptions, maybeOptions) {
80
+ if (maybeOptions !== void 0) {
81
+ let callMetadata = {};
82
+ let requestOptions;
83
+ if (isAgentInspectMetadataBag(maybeOptions)) {
84
+ callMetadata = extractCallMetadata(maybeOptions);
85
+ requestOptions = void 0;
86
+ } else if (isSdkRequestOptions(maybeOptions) || maybeOptions === null) {
87
+ requestOptions = maybeOptions && typeof maybeOptions === "object" ? maybeOptions : void 0;
88
+ } else if (maybeOptions && typeof maybeOptions === "object") {
89
+ requestOptions = maybeOptions;
90
+ }
91
+ return {
92
+ resultSchema: resultSchemaOrOptions,
93
+ requestOptions,
94
+ callMetadata
95
+ };
96
+ }
97
+ if (isAgentInspectMetadataBag(resultSchemaOrOptions)) {
98
+ return {
99
+ resultSchema: void 0,
100
+ requestOptions: void 0,
101
+ callMetadata: extractCallMetadata(resultSchemaOrOptions)
102
+ };
103
+ }
104
+ if (isSdkRequestOptions(resultSchemaOrOptions)) {
105
+ return {
106
+ resultSchema: void 0,
107
+ requestOptions: resultSchemaOrOptions,
108
+ callMetadata: {}
109
+ };
110
+ }
111
+ return {
112
+ resultSchema: resultSchemaOrOptions,
113
+ requestOptions: void 0,
114
+ callMetadata: {}
115
+ };
116
+ }
117
+ function invokeCallTool(callToolImpl, params, resultSchema, requestOptions) {
118
+ const fn = callToolImpl;
119
+ if (requestOptions !== void 0) {
120
+ return fn(params, resultSchema, requestOptions);
121
+ }
122
+ if (resultSchema !== void 0) {
123
+ return fn(params, resultSchema);
124
+ }
125
+ return fn(params);
126
+ }
50
127
  function wrapMcpClient(client, options = {}) {
51
128
  const maxSummaryLength = options.maxSummaryLength ?? 240;
52
129
  const listToolsImpl = typeof client.listTools === "function" ? client.listTools.bind(client) : void 0;
53
130
  const callToolImpl = client.callTool.bind(client);
54
- const wrappedListTools = listToolsImpl ? async (params) => step(
131
+ const wrappedListTools = listToolsImpl ? async (params, requestOptions) => step(
55
132
  "mcp:tools/list",
56
133
  async () => {
57
- const result = await listToolsImpl(params);
58
- return result;
134
+ if (requestOptions !== void 0) {
135
+ return listToolsImpl(params, requestOptions);
136
+ }
137
+ return listToolsImpl(params);
59
138
  },
60
139
  {
61
140
  type: "tool",
@@ -66,32 +145,13 @@ function wrapMcpClient(client, options = {}) {
66
145
  }
67
146
  ) : void 0;
68
147
  const wrappedCallTool = async (params, resultSchemaOrOptions, maybeOptions) => {
69
- let resultSchema;
70
- let callMetadata = {};
71
- if (maybeOptions && typeof maybeOptions === "object") {
72
- resultSchema = resultSchemaOrOptions;
73
- if (maybeOptions.metadata && typeof maybeOptions.metadata === "object") {
74
- callMetadata = maybeOptions.metadata;
75
- }
76
- } else if (resultSchemaOrOptions && typeof resultSchemaOrOptions === "object" && resultSchemaOrOptions !== null && "metadata" in resultSchemaOrOptions && !("parse" in resultSchemaOrOptions)) {
77
- const bag = resultSchemaOrOptions;
78
- if (bag.metadata && typeof bag.metadata === "object") {
79
- callMetadata = bag.metadata;
80
- }
81
- } else {
82
- resultSchema = resultSchemaOrOptions;
83
- }
148
+ const { resultSchema, requestOptions, callMetadata } = resolveCallToolArgs(
149
+ resultSchemaOrOptions,
150
+ maybeOptions
151
+ );
84
152
  return step(
85
153
  `mcp:${params.name}`,
86
- async () => {
87
- if (resultSchema !== void 0) {
88
- return callToolImpl(
89
- params,
90
- resultSchema
91
- );
92
- }
93
- return callToolImpl(params);
94
- },
154
+ async () => invokeCallTool(callToolImpl, params, resultSchema, requestOptions),
95
155
  {
96
156
  type: "tool",
97
157
  metadata: baseMetadata(options, {
@@ -126,6 +186,6 @@ function resetMcpToolCallIdsForTests() {
126
186
  toolCallCounter = 0;
127
187
  }
128
188
 
129
- export { hashServerUrl, resetMcpToolCallIdsForTests, summarizeMcpValue, wrapMcpClient };
189
+ export { hashServerUrl, resetMcpToolCallIdsForTests, resolveCallToolArgs, summarizeMcpValue, wrapMcpClient };
130
190
  //# sourceMappingURL=index.mjs.map
131
191
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/summarize.ts","../src/wrap.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["const DEFAULT_MAX_SUMMARY_LENGTH = 240;\n\nfunction fallbackString(value: unknown): string {\n try {\n return String(value);\n } catch {\n return \"[unserializable]\";\n }\n}\n\nexport function summarizeMcpValue(\n value: unknown,\n maxLength = DEFAULT_MAX_SUMMARY_LENGTH,\n): string {\n let text: string;\n try {\n if (typeof value === \"string\") {\n text = value;\n } else {\n // JSON.stringify returns undefined (not a string) for undefined,\n // functions, and symbols; falling through with undefined would crash\n // instrumentation at text.length below.\n const serialized = JSON.stringify(value);\n text = serialized === undefined ? fallbackString(value) : serialized;\n }\n } catch {\n text = fallbackString(value);\n }\n if (text.length <= maxLength) return text;\n return `${text.slice(0, Math.max(0, maxLength - 3))}...`;\n}\n\nexport function hashServerUrl(url: string): string {\n let hash = 0;\n for (let i = 0; i < url.length; i += 1) {\n hash = (hash * 31 + url.charCodeAt(i)) >>> 0;\n }\n return hash.toString(16).padStart(8, \"0\");\n}\n","import { step } from \"agent-inspect\";\n\nimport { hashServerUrl, summarizeMcpValue } from \"./summarize.js\";\nimport type {\n McpClientLike,\n McpClientTracerOptions,\n McpTraceMetadata,\n} from \"./types.js\";\n\nlet toolCallCounter = 0;\n\nfunction nextToolCallId(prefix?: string): string {\n toolCallCounter += 1;\n const base = prefix?.trim() || \"mcp\";\n return `${base}-${toolCallCounter}`;\n}\n\nfunction baseMetadata(\n options: McpClientTracerOptions,\n overrides: Partial<McpTraceMetadata> = {},\n): Record<string, unknown> {\n const metadata: McpTraceMetadata = {\n source: { type: \"mcp-client\" },\n ...(options.serverName ? { mcpServerName: options.serverName } : {}),\n ...(options.serverUrl\n ? { mcpServerUrlHash: hashServerUrl(options.serverUrl) }\n : {}),\n ...(options.sessionId ? { sessionId: options.sessionId } : {}),\n ...overrides,\n };\n return { ...(options.metadata ?? {}), ...metadata };\n}\n\n/**\n * Wraps an MCP client so tools/list and tools/call emit local tool steps.\n * Telemetry only — does not proxy network behavior beyond the wrapped client.\n *\n * Uses a Proxy over the original client so prototype methods (`connect`,\n * `close`, `listResources`, …), private SDK state, and `instanceof` stay intact.\n * A shallow object spread would drop prototype methods and copy private fields.\n */\nexport function wrapMcpClient<T extends McpClientLike>(\n client: T,\n options: McpClientTracerOptions = {},\n): T {\n const maxSummaryLength = options.maxSummaryLength ?? 240;\n\n const listToolsImpl =\n typeof client.listTools === \"function\"\n ? client.listTools.bind(client)\n : undefined;\n const callToolImpl = client.callTool.bind(client);\n\n const wrappedListTools = listToolsImpl\n ? async (params?: unknown) =>\n step(\n \"mcp:tools/list\",\n async () => {\n const result = await listToolsImpl(params);\n return result;\n },\n {\n type: \"tool\",\n metadata: baseMetadata(options, {\n toolName: \"tools/list\",\n toolCallId: nextToolCallId(options.toolCallIdPrefix),\n }),\n },\n )\n : undefined;\n\n const wrappedCallTool = async (\n params: Parameters<McpClientLike[\"callTool\"]>[0],\n resultSchemaOrOptions?: unknown,\n maybeOptions?: { metadata?: Record<string, unknown> },\n ) => {\n let resultSchema: unknown;\n let callMetadata: Record<string, unknown> = {};\n if (maybeOptions && typeof maybeOptions === \"object\") {\n resultSchema = resultSchemaOrOptions;\n if (maybeOptions.metadata && typeof maybeOptions.metadata === \"object\") {\n callMetadata = maybeOptions.metadata;\n }\n } else if (\n resultSchemaOrOptions &&\n typeof resultSchemaOrOptions === \"object\" &&\n resultSchemaOrOptions !== null &&\n \"metadata\" in resultSchemaOrOptions &&\n !(\"parse\" in (resultSchemaOrOptions as object))\n ) {\n const bag = resultSchemaOrOptions as { metadata?: Record<string, unknown> };\n if (bag.metadata && typeof bag.metadata === \"object\") {\n callMetadata = bag.metadata;\n }\n } else {\n resultSchema = resultSchemaOrOptions;\n }\n\n return step(\n `mcp:${params.name}`,\n async () => {\n if (resultSchema !== undefined) {\n return (callToolImpl as (...args: unknown[]) => Promise<unknown>)(\n params,\n resultSchema,\n );\n }\n return callToolImpl(params);\n },\n {\n type: \"tool\",\n metadata: baseMetadata(options, {\n toolName: params.name,\n toolCallId: nextToolCallId(options.toolCallIdPrefix),\n argumentSummary: summarizeMcpValue(\n params.arguments ?? {},\n maxSummaryLength,\n ),\n ...callMetadata,\n }),\n },\n );\n };\n\n return new Proxy(client, {\n get(target, property, receiver) {\n if (property === \"listTools\" && wrappedListTools !== undefined) {\n return wrappedListTools;\n }\n if (property === \"callTool\") {\n return wrappedCallTool;\n }\n const value = Reflect.get(target, property, receiver);\n if (typeof value === \"function\") {\n return value.bind(target);\n }\n return value;\n },\n }) as T;\n}\n\n/** @internal resets tool call ids for deterministic tests */\nexport function resetMcpToolCallIdsForTests(): void {\n toolCallCounter = 0;\n}\n"]}
1
+ {"version":3,"sources":["../src/summarize.ts","../src/wrap.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["const DEFAULT_MAX_SUMMARY_LENGTH = 240;\n\nfunction fallbackString(value: unknown): string {\n try {\n return String(value);\n } catch {\n return \"[unserializable]\";\n }\n}\n\nexport function summarizeMcpValue(\n value: unknown,\n maxLength = DEFAULT_MAX_SUMMARY_LENGTH,\n): string {\n let text: string;\n try {\n if (typeof value === \"string\") {\n text = value;\n } else {\n // JSON.stringify returns undefined (not a string) for undefined,\n // functions, and symbols; falling through with undefined would crash\n // instrumentation at text.length below.\n const serialized = JSON.stringify(value);\n text = serialized === undefined ? fallbackString(value) : serialized;\n }\n } catch {\n text = fallbackString(value);\n }\n if (text.length <= maxLength) return text;\n return `${text.slice(0, Math.max(0, maxLength - 3))}...`;\n}\n\nexport function hashServerUrl(url: string): string {\n let hash = 0;\n for (let i = 0; i < url.length; i += 1) {\n hash = (hash * 31 + url.charCodeAt(i)) >>> 0;\n }\n return hash.toString(16).padStart(8, \"0\");\n}\n","import { step } from \"agent-inspect\";\n\nimport { hashServerUrl, summarizeMcpValue } from \"./summarize.js\";\nimport type {\n McpClientLike,\n McpClientTracerOptions,\n McpRequestOptions,\n McpTraceMetadata,\n} from \"./types.js\";\n\nlet toolCallCounter = 0;\n\nfunction nextToolCallId(prefix?: string): string {\n toolCallCounter += 1;\n const base = prefix?.trim() || \"mcp\";\n return `${base}-${toolCallCounter}`;\n}\n\nfunction baseMetadata(\n options: McpClientTracerOptions,\n overrides: Partial<McpTraceMetadata> = {},\n): Record<string, unknown> {\n const metadata: McpTraceMetadata = {\n source: { type: \"mcp-client\" },\n ...(options.serverName ? { mcpServerName: options.serverName } : {}),\n ...(options.serverUrl\n ? { mcpServerUrlHash: hashServerUrl(options.serverUrl) }\n : {}),\n ...(options.sessionId ? { sessionId: options.sessionId } : {}),\n ...overrides,\n };\n return { ...(options.metadata ?? {}), ...metadata };\n}\n\n/** SDK RequestOptions keys — must never be swallowed as AgentInspect metadata. */\nconst SDK_REQUEST_OPTION_KEYS = [\n \"signal\",\n \"timeout\",\n \"onprogress\",\n \"resetTimeoutOnProgress\",\n \"maxTotalTimeout\",\n \"relatedRequestId\",\n \"resumptionToken\",\n \"onresumptiontoken\",\n] as const;\n\nfunction isSdkRequestOptions(value: unknown): value is McpRequestOptions {\n if (!value || typeof value !== \"object\") return false;\n const obj = value as Record<string, unknown>;\n return SDK_REQUEST_OPTION_KEYS.some((key) => key in obj);\n}\n\n/**\n * AgentInspect per-call metadata bag: `{ metadata: {...} }` without SDK option keys.\n * Must not consume ordinary SDK RequestOptions that happen to be objects.\n */\nfunction isAgentInspectMetadataBag(\n value: unknown,\n): value is { metadata?: Record<string, unknown> } {\n if (!value || typeof value !== \"object\") return false;\n if (isSdkRequestOptions(value)) return false;\n const obj = value as Record<string, unknown>;\n if (!(\"metadata\" in obj)) return false;\n // Zod/result schemas expose parse — never treat those as AI bags.\n if (\"parse\" in obj) return false;\n return true;\n}\n\nfunction extractCallMetadata(bag: {\n metadata?: Record<string, unknown>;\n}): Record<string, unknown> {\n if (bag.metadata && typeof bag.metadata === \"object\") {\n return bag.metadata;\n }\n return {};\n}\n\n/**\n * Resolve SDK callTool arity:\n * callTool(params, resultSchema?, requestOptions?)\n * plus AgentInspect overloads that peel `{ metadata }` without dropping RequestOptions.\n */\nexport function resolveCallToolArgs(\n resultSchemaOrOptions?: unknown,\n maybeOptions?: unknown,\n): {\n resultSchema: unknown;\n requestOptions: McpRequestOptions | undefined;\n callMetadata: Record<string, unknown>;\n} {\n // Three-arg form: (params, schema|undefined, options)\n if (maybeOptions !== undefined) {\n let callMetadata: Record<string, unknown> = {};\n let requestOptions: McpRequestOptions | undefined;\n\n if (isAgentInspectMetadataBag(maybeOptions)) {\n callMetadata = extractCallMetadata(maybeOptions);\n // Remaining SDK keys (if any were mixed in) still forward — but AI bags exclude them.\n requestOptions = undefined;\n } else if (isSdkRequestOptions(maybeOptions) || maybeOptions === null) {\n requestOptions =\n maybeOptions && typeof maybeOptions === \"object\"\n ? (maybeOptions as McpRequestOptions)\n : undefined;\n } else if (maybeOptions && typeof maybeOptions === \"object\") {\n // Unknown object third arg — forward as RequestOptions to preserve caller intent.\n requestOptions = maybeOptions as McpRequestOptions;\n }\n\n return {\n resultSchema: resultSchemaOrOptions,\n requestOptions,\n callMetadata,\n };\n }\n\n // Two-arg form: (params, schema) OR (params, { metadata }) OR (params, RequestOptions)\n if (isAgentInspectMetadataBag(resultSchemaOrOptions)) {\n return {\n resultSchema: undefined,\n requestOptions: undefined,\n callMetadata: extractCallMetadata(resultSchemaOrOptions),\n };\n }\n\n if (isSdkRequestOptions(resultSchemaOrOptions)) {\n return {\n resultSchema: undefined,\n requestOptions: resultSchemaOrOptions,\n callMetadata: {},\n };\n }\n\n return {\n resultSchema: resultSchemaOrOptions,\n requestOptions: undefined,\n callMetadata: {},\n };\n}\n\nfunction invokeCallTool(\n callToolImpl: McpClientLike[\"callTool\"],\n params: Parameters<McpClientLike[\"callTool\"]>[0],\n resultSchema: unknown,\n requestOptions: McpRequestOptions | undefined,\n): Promise<unknown> {\n const fn = callToolImpl as (\n p: unknown,\n schema?: unknown,\n opts?: unknown,\n ) => Promise<unknown>;\n if (requestOptions !== undefined) {\n return fn(params, resultSchema, requestOptions);\n }\n if (resultSchema !== undefined) {\n return fn(params, resultSchema);\n }\n return fn(params);\n}\n\n/**\n * Wraps an MCP client so tools/list and tools/call emit local tool steps.\n * Telemetry only — does not proxy network behavior beyond the wrapped client.\n *\n * Uses a Proxy over the original client so prototype methods (`connect`,\n * `close`, `listResources`, …), private SDK state, and `instanceof` stay intact.\n * A shallow object spread would drop prototype methods and copy private fields.\n *\n * Forwards the real SDK argument positions, including `RequestOptions`\n * (`signal`, `timeout`, progress callbacks). Does not fake cancellation while\n * still dispatching the underlying request.\n */\nexport function wrapMcpClient<T extends McpClientLike>(\n client: T,\n options: McpClientTracerOptions = {},\n): T {\n const maxSummaryLength = options.maxSummaryLength ?? 240;\n\n const listToolsImpl =\n typeof client.listTools === \"function\"\n ? client.listTools.bind(client)\n : undefined;\n const callToolImpl = client.callTool.bind(client);\n\n const wrappedListTools = listToolsImpl\n ? async (params?: unknown, requestOptions?: McpRequestOptions) =>\n step(\n \"mcp:tools/list\",\n async () => {\n if (requestOptions !== undefined) {\n return (\n listToolsImpl as (\n p?: unknown,\n opts?: unknown,\n ) => Promise<unknown>\n )(params, requestOptions);\n }\n return listToolsImpl(params);\n },\n {\n type: \"tool\",\n metadata: baseMetadata(options, {\n toolName: \"tools/list\",\n toolCallId: nextToolCallId(options.toolCallIdPrefix),\n }),\n },\n )\n : undefined;\n\n const wrappedCallTool = async (\n params: Parameters<McpClientLike[\"callTool\"]>[0],\n resultSchemaOrOptions?: unknown,\n maybeOptions?: unknown,\n ) => {\n const { resultSchema, requestOptions, callMetadata } = resolveCallToolArgs(\n resultSchemaOrOptions,\n maybeOptions,\n );\n\n return step(\n `mcp:${params.name}`,\n async () =>\n invokeCallTool(callToolImpl, params, resultSchema, requestOptions),\n {\n type: \"tool\",\n metadata: baseMetadata(options, {\n toolName: params.name,\n toolCallId: nextToolCallId(options.toolCallIdPrefix),\n argumentSummary: summarizeMcpValue(\n params.arguments ?? {},\n maxSummaryLength,\n ),\n ...callMetadata,\n }),\n },\n );\n };\n\n return new Proxy(client, {\n get(target, property, receiver) {\n if (property === \"listTools\" && wrappedListTools !== undefined) {\n return wrappedListTools;\n }\n if (property === \"callTool\") {\n return wrappedCallTool;\n }\n const value = Reflect.get(target, property, receiver);\n if (typeof value === \"function\") {\n return value.bind(target);\n }\n return value;\n },\n }) as T;\n}\n\n/** @internal resets tool call ids for deterministic tests */\nexport function resetMcpToolCallIdsForTests(): void {\n toolCallCounter = 0;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-inspect/mcp",
3
- "version": "6.31.19",
3
+ "version": "6.31.20",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "Local MCP client tool-call tracing for AgentInspect",
@@ -35,7 +35,7 @@
35
35
  "dist"
36
36
  ],
37
37
  "dependencies": {
38
- "agent-inspect": "6.31.19"
38
+ "agent-inspect": "6.31.20"
39
39
  },
40
40
  "publishConfig": {
41
41
  "access": "public"