@agent-inspect/mcp 6.31.19 → 6.31.21

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,107 @@ 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 peelOptionsObject(value) {
82
+ if (value === null || value === void 0) {
83
+ return { callMetadata: {}, requestOptions: void 0 };
84
+ }
85
+ if (typeof value !== "object") {
86
+ return { callMetadata: {}, requestOptions: void 0 };
87
+ }
88
+ const obj = value;
89
+ const callMetadata = extractCallMetadata(obj);
90
+ if (isAgentInspectMetadataBag(value)) {
91
+ return { callMetadata, requestOptions: void 0 };
92
+ }
93
+ if (isSdkRequestOptions(value) || Object.keys(obj).length > 0) {
94
+ const { metadata: _ignored, ...rest } = obj;
95
+ return {
96
+ callMetadata,
97
+ requestOptions: rest
98
+ };
99
+ }
100
+ return { callMetadata, requestOptions: void 0 };
101
+ }
102
+ function resolveCallToolArgs(resultSchemaOrOptions, maybeOptions) {
103
+ if (maybeOptions !== void 0) {
104
+ const peeled = peelOptionsObject(maybeOptions);
105
+ return {
106
+ resultSchema: resultSchemaOrOptions,
107
+ requestOptions: peeled.requestOptions,
108
+ callMetadata: peeled.callMetadata
109
+ };
110
+ }
111
+ if (isAgentInspectMetadataBag(resultSchemaOrOptions)) {
112
+ return {
113
+ resultSchema: void 0,
114
+ requestOptions: void 0,
115
+ callMetadata: extractCallMetadata(resultSchemaOrOptions)
116
+ };
117
+ }
118
+ if (isSdkRequestOptions(resultSchemaOrOptions)) {
119
+ const peeled = peelOptionsObject(resultSchemaOrOptions);
120
+ return {
121
+ resultSchema: void 0,
122
+ requestOptions: peeled.requestOptions,
123
+ callMetadata: peeled.callMetadata
124
+ };
125
+ }
126
+ return {
127
+ resultSchema: resultSchemaOrOptions,
128
+ requestOptions: void 0,
129
+ callMetadata: {}
130
+ };
131
+ }
132
+ function invokeCallTool(callToolImpl, params, resultSchema, requestOptions) {
133
+ const fn = callToolImpl;
134
+ if (requestOptions !== void 0) {
135
+ return fn(params, resultSchema, requestOptions);
136
+ }
137
+ if (resultSchema !== void 0) {
138
+ return fn(params, resultSchema);
139
+ }
140
+ return fn(params);
141
+ }
52
142
  function wrapMcpClient(client, options = {}) {
53
143
  const maxSummaryLength = options.maxSummaryLength ?? 240;
54
144
  const listToolsImpl = typeof client.listTools === "function" ? client.listTools.bind(client) : void 0;
55
145
  const callToolImpl = client.callTool.bind(client);
56
- const wrappedListTools = listToolsImpl ? async (params) => agentInspect.step(
146
+ const wrappedListTools = listToolsImpl ? async (params, requestOptions) => agentInspect.step(
57
147
  "mcp:tools/list",
58
148
  async () => {
59
- const result = await listToolsImpl(params);
60
- return result;
149
+ if (requestOptions !== void 0) {
150
+ return listToolsImpl(params, requestOptions);
151
+ }
152
+ return listToolsImpl(params);
61
153
  },
62
154
  {
63
155
  type: "tool",
@@ -68,32 +160,13 @@ function wrapMcpClient(client, options = {}) {
68
160
  }
69
161
  ) : void 0;
70
162
  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
- }
163
+ const { resultSchema, requestOptions, callMetadata } = resolveCallToolArgs(
164
+ resultSchemaOrOptions,
165
+ maybeOptions
166
+ );
86
167
  return agentInspect.step(
87
168
  `mcp:${params.name}`,
88
- async () => {
89
- if (resultSchema !== void 0) {
90
- return callToolImpl(
91
- params,
92
- resultSchema
93
- );
94
- }
95
- return callToolImpl(params);
96
- },
169
+ async () => invokeCallTool(callToolImpl, params, resultSchema, requestOptions),
97
170
  {
98
171
  type: "tool",
99
172
  metadata: baseMetadata(options, {
@@ -130,6 +203,7 @@ function resetMcpToolCallIdsForTests() {
130
203
 
131
204
  exports.hashServerUrl = hashServerUrl;
132
205
  exports.resetMcpToolCallIdsForTests = resetMcpToolCallIdsForTests;
206
+ exports.resolveCallToolArgs = resolveCallToolArgs;
133
207
  exports.summarizeMcpValue = summarizeMcpValue;
134
208
  exports.wrapMcpClient = wrapMcpClient;
135
209
  //# 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":";;;;;AAAA,IAAM,0BAAA,GAA6B,GAAA;AAEnC,SAAS,eAAe,KAAA,EAAwB;AAC9C,EAAA,IAAI;AACF,IAAA,OAAO,OAAO,KAAK,CAAA;AAAA,EACrB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,kBAAA;AAAA,EACT;AACF;AAEO,SAAS,iBAAA,CACd,KAAA,EACA,SAAA,GAAY,0BAAA,EACJ;AACR,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI;AACF,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,MAAA,IAAA,GAAO,KAAA;AAAA,IACT,CAAA,MAAO;AAIL,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA;AACvC,MAAA,IAAA,GAAO,UAAA,KAAe,KAAA,CAAA,GAAY,cAAA,CAAe,KAAK,CAAA,GAAI,UAAA;AAAA,IAC5D;AAAA,EACF,CAAA,CAAA,MAAQ;AACN,IAAA,IAAA,GAAO,eAAe,KAAK,CAAA;AAAA,EAC7B;AACA,EAAA,IAAI,IAAA,CAAK,MAAA,IAAU,SAAA,EAAW,OAAO,IAAA;AACrC,EAAA,OAAO,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,IAAA,CAAK,IAAI,CAAA,EAAG,SAAA,GAAY,CAAC,CAAC,CAAC,CAAA,GAAA,CAAA;AACrD;AAEO,SAAS,cAAc,GAAA,EAAqB;AACjD,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,MAAA,EAAQ,KAAK,CAAA,EAAG;AACtC,IAAA,IAAA,GAAQ,IAAA,GAAO,EAAA,GAAK,GAAA,CAAI,UAAA,CAAW,CAAC,CAAA,KAAO,CAAA;AAAA,EAC7C;AACA,EAAA,OAAO,KAAK,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AAC1C;AC5BA,IAAI,eAAA,GAAkB,CAAA;AAEtB,SAAS,eAAe,MAAA,EAAyB;AAC/C,EAAA,eAAA,IAAmB,CAAA;AACnB,EAAA,MAAM,IAAA,GAAO,MAAA,EAAQ,IAAA,EAAK,IAAK,KAAA;AAC/B,EAAA,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,eAAe,CAAA,CAAA;AACnC;AAEA,SAAS,YAAA,CACP,OAAA,EACA,SAAA,GAAuC,EAAC,EACf;AACzB,EAAA,MAAM,QAAA,GAA6B;AAAA,IACjC,MAAA,EAAQ,EAAE,IAAA,EAAM,YAAA,EAAa;AAAA,IAC7B,GAAI,QAAQ,UAAA,GAAa,EAAE,eAAe,OAAA,CAAQ,UAAA,KAAe,EAAC;AAAA,IAClE,GAAI,OAAA,CAAQ,SAAA,GACR,EAAE,gBAAA,EAAkB,cAAc,OAAA,CAAQ,SAAS,CAAA,EAAE,GACrD,EAAC;AAAA,IACL,GAAI,QAAQ,SAAA,GAAY,EAAE,WAAW,OAAA,CAAQ,SAAA,KAAc,EAAC;AAAA,IAC5D,GAAG;AAAA,GACL;AACA,EAAA,OAAO,EAAE,GAAI,OAAA,CAAQ,YAAY,EAAC,EAAI,GAAG,QAAA,EAAS;AACpD;AAGA,IAAM,uBAAA,GAA0B;AAAA,EAC9B,QAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA;AAAA,EACA,wBAAA;AAAA,EACA,iBAAA;AAAA,EACA,kBAAA;AAAA,EACA,iBAAA;AAAA,EACA;AACF,CAAA;AAEA,SAAS,oBAAoB,KAAA,EAA4C;AACvE,EAAA,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,UAAU,OAAO,KAAA;AAChD,EAAA,MAAM,GAAA,GAAM,KAAA;AACZ,EAAA,OAAO,uBAAA,CAAwB,IAAA,CAAK,CAAC,GAAA,KAAQ,OAAO,GAAG,CAAA;AACzD;AAMA,SAAS,0BACP,KAAA,EACiD;AACjD,EAAA,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,UAAU,OAAO,KAAA;AAChD,EAAA,IAAI,mBAAA,CAAoB,KAAK,CAAA,EAAG,OAAO,KAAA;AACvC,EAAA,MAAM,GAAA,GAAM,KAAA;AACZ,EAAA,IAAI,EAAE,UAAA,IAAc,GAAA,CAAA,EAAM,OAAO,KAAA;AAEjC,EAAA,IAAI,OAAA,IAAW,KAAK,OAAO,KAAA;AAC3B,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,oBAAoB,GAAA,EAED;AAC1B,EAAA,IAAI,GAAA,CAAI,QAAA,IAAY,OAAO,GAAA,CAAI,aAAa,QAAA,EAAU;AACpD,IAAA,OAAO,GAAA,CAAI,QAAA;AAAA,EACb;AACA,EAAA,OAAO,EAAC;AACV;AAGA,SAAS,kBAAkB,KAAA,EAGzB;AACA,EAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,MAAA,EAAW;AACzC,IAAA,OAAO,EAAE,YAAA,EAAc,EAAC,EAAG,gBAAgB,MAAA,EAAU;AAAA,EACvD;AACA,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,EAAE,YAAA,EAAc,EAAC,EAAG,gBAAgB,MAAA,EAAU;AAAA,EACvD;AACA,EAAA,MAAM,GAAA,GAAM,KAAA;AACZ,EAAA,MAAM,YAAA,GAAe,oBAAoB,GAAG,CAAA;AAG5C,EAAA,IAAI,yBAAA,CAA0B,KAAK,CAAA,EAAG;AACpC,IAAA,OAAO,EAAE,YAAA,EAAc,cAAA,EAAgB,MAAA,EAAU;AAAA,EACnD;AAEA,EAAA,IAAI,mBAAA,CAAoB,KAAK,CAAA,IAAK,MAAA,CAAO,KAAK,GAAG,CAAA,CAAE,SAAS,CAAA,EAAG;AAC7D,IAAA,MAAM,EAAE,QAAA,EAAU,QAAA,EAAU,GAAG,MAAK,GAAI,GAAA;AACxC,IAAA,OAAO;AAAA,MACL,YAAA;AAAA,MACA,cAAA,EAAgB;AAAA,KAClB;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,YAAA,EAAc,cAAA,EAAgB,MAAA,EAAU;AACnD;AAQO,SAAS,mBAAA,CACd,uBACA,YAAA,EAKA;AAEA,EAAA,IAAI,iBAAiB,MAAA,EAAW;AAC9B,IAAA,MAAM,MAAA,GAAS,kBAAkB,YAAY,CAAA;AAC7C,IAAA,OAAO;AAAA,MACL,YAAA,EAAc,qBAAA;AAAA,MACd,gBAAgB,MAAA,CAAO,cAAA;AAAA,MACvB,cAAc,MAAA,CAAO;AAAA,KACvB;AAAA,EACF;AAGA,EAAA,IAAI,yBAAA,CAA0B,qBAAqB,CAAA,EAAG;AACpD,IAAA,OAAO;AAAA,MACL,YAAA,EAAc,MAAA;AAAA,MACd,cAAA,EAAgB,MAAA;AAAA,MAChB,YAAA,EAAc,oBAAoB,qBAAqB;AAAA,KACzD;AAAA,EACF;AAEA,EAAA,IAAI,mBAAA,CAAoB,qBAAqB,CAAA,EAAG;AAC9C,IAAA,MAAM,MAAA,GAAS,kBAAkB,qBAAqB,CAAA;AACtD,IAAA,OAAO;AAAA,MACL,YAAA,EAAc,MAAA;AAAA,MACd,gBAAgB,MAAA,CAAO,cAAA;AAAA,MACvB,cAAc,MAAA,CAAO;AAAA,KACvB;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,YAAA,EAAc,qBAAA;AAAA,IACd,cAAA,EAAgB,MAAA;AAAA,IAChB,cAAc;AAAC,GACjB;AACF;AAEA,SAAS,cAAA,CACP,YAAA,EACA,MAAA,EACA,YAAA,EACA,cAAA,EACkB;AAClB,EAAA,MAAM,EAAA,GAAK,YAAA;AAKX,EAAA,IAAI,mBAAmB,MAAA,EAAW;AAChC,IAAA,OAAO,EAAA,CAAG,MAAA,EAAQ,YAAA,EAAc,cAAc,CAAA;AAAA,EAChD;AACA,EAAA,IAAI,iBAAiB,MAAA,EAAW;AAC9B,IAAA,OAAO,EAAA,CAAG,QAAQ,YAAY,CAAA;AAAA,EAChC;AACA,EAAA,OAAO,GAAG,MAAM,CAAA;AAClB;AAcO,SAAS,aAAA,CACd,MAAA,EACA,OAAA,GAAkC,EAAC,EAChC;AACH,EAAA,MAAM,gBAAA,GAAmB,QAAQ,gBAAA,IAAoB,GAAA;AAErD,EAAA,MAAM,aAAA,GACJ,OAAO,MAAA,CAAO,SAAA,KAAc,aACxB,MAAA,CAAO,SAAA,CAAU,IAAA,CAAK,MAAM,CAAA,GAC5B,MAAA;AACN,EAAA,MAAM,YAAA,GAAe,MAAA,CAAO,QAAA,CAAS,IAAA,CAAK,MAAM,CAAA;AAEhD,EAAA,MAAM,gBAAA,GAAmB,aAAA,GACrB,OAAO,MAAA,EAAkB,cAAA,KACvBA,iBAAA;AAAA,IACE,gBAAA;AAAA,IACA,YAAY;AACV,MAAA,IAAI,mBAAmB,MAAA,EAAW;AAChC,QAAA,OACE,aAAA,CAIA,QAAQ,cAAc,CAAA;AAAA,MAC1B;AACA,MAAA,OAAO,cAAc,MAAM,CAAA;AAAA,IAC7B,CAAA;AAAA,IACA;AAAA,MACE,IAAA,EAAM,MAAA;AAAA,MACN,QAAA,EAAU,aAAa,OAAA,EAAS;AAAA,QAC9B,QAAA,EAAU,YAAA;AAAA,QACV,UAAA,EAAY,cAAA,CAAe,OAAA,CAAQ,gBAAgB;AAAA,OACpD;AAAA;AACH,GACF,GACF,MAAA;AAEJ,EAAA,MAAM,eAAA,GAAkB,OACtB,MAAA,EACA,qBAAA,EACA,YAAA,KACG;AACH,IAAA,MAAM,EAAE,YAAA,EAAc,cAAA,EAAgB,YAAA,EAAa,GAAI,mBAAA;AAAA,MACrD,qBAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,OAAOA,iBAAA;AAAA,MACL,CAAA,IAAA,EAAO,OAAO,IAAI,CAAA,CAAA;AAAA,MAClB,YACE,cAAA,CAAe,YAAA,EAAc,MAAA,EAAQ,cAAc,cAAc,CAAA;AAAA,MACnE;AAAA,QACE,IAAA,EAAM,MAAA;AAAA,QACN,QAAA,EAAU,aAAa,OAAA,EAAS;AAAA,UAC9B,UAAU,MAAA,CAAO,IAAA;AAAA,UACjB,UAAA,EAAY,cAAA,CAAe,OAAA,CAAQ,gBAAgB,CAAA;AAAA,UACnD,eAAA,EAAiB,iBAAA;AAAA,YACf,MAAA,CAAO,aAAa,EAAC;AAAA,YACrB;AAAA,WACF;AAAA,UACA,GAAG;AAAA,SACJ;AAAA;AACH,KACF;AAAA,EACF,CAAA;AAEA,EAAA,OAAO,IAAI,MAAM,MAAA,EAAQ;AAAA,IACvB,GAAA,CAAI,MAAA,EAAQ,QAAA,EAAU,QAAA,EAAU;AAC9B,MAAA,IAAI,QAAA,KAAa,WAAA,IAAe,gBAAA,KAAqB,MAAA,EAAW;AAC9D,QAAA,OAAO,gBAAA;AAAA,MACT;AACA,MAAA,IAAI,aAAa,UAAA,EAAY;AAC3B,QAAA,OAAO,eAAA;AAAA,MACT;AACA,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,UAAU,QAAQ,CAAA;AACpD,MAAA,IAAI,OAAO,UAAU,UAAA,EAAY;AAC/B,QAAA,OAAO,KAAA,CAAM,KAAK,MAAM,CAAA;AAAA,MAC1B;AACA,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,GACD,CAAA;AACH;AAGO,SAAS,2BAAA,GAAoC;AAClD,EAAA,eAAA,GAAkB,CAAA;AACpB","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/** Peel AgentInspect `metadata` without consuming SDK RequestOptions keys. */\nfunction peelOptionsObject(value: unknown): {\n callMetadata: Record<string, unknown>;\n requestOptions: McpRequestOptions | undefined;\n} {\n if (value === null || value === undefined) {\n return { callMetadata: {}, requestOptions: undefined };\n }\n if (typeof value !== \"object\") {\n return { callMetadata: {}, requestOptions: undefined };\n }\n const obj = value as Record<string, unknown>;\n const callMetadata = extractCallMetadata(obj);\n\n // Pure AI bag — do not forward as SDK RequestOptions.\n if (isAgentInspectMetadataBag(value)) {\n return { callMetadata, requestOptions: undefined };\n }\n\n if (isSdkRequestOptions(value) || Object.keys(obj).length > 0) {\n const { metadata: _ignored, ...rest } = obj;\n return {\n callMetadata,\n requestOptions: rest as McpRequestOptions,\n };\n }\n\n return { callMetadata, requestOptions: undefined };\n}\n\n/**\n * Resolve SDK callTool arity:\n * callTool(params, resultSchema?, requestOptions?)\n * plus AgentInspect overloads that peel `{ metadata }` without dropping RequestOptions.\n * Composed `{ timeout, metadata: { operationId, attemptId } }` keeps both sides.\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 const peeled = peelOptionsObject(maybeOptions);\n return {\n resultSchema: resultSchemaOrOptions,\n requestOptions: peeled.requestOptions,\n callMetadata: peeled.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 const peeled = peelOptionsObject(resultSchemaOrOptions);\n return {\n resultSchema: undefined,\n requestOptions: peeled.requestOptions,\n callMetadata: peeled.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,15 +15,39 @@ 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
+ * Method syntax (not property function types) so real SDK `Client` remains
40
+ * assignable under `strictFunctionTypes` (bivariant method parameters).
41
+ * `callTool` returns `Promise<unknown>` to accept both normal tool results and
42
+ * the SDK compatibility `{ toolResult }` branch.
43
+ *
44
+ * Matches SDK arity: `callTool(params, resultSchema?, requestOptions?)` and
45
+ * `listTools(params?, requestOptions?)`. AgentInspect also accepts a
46
+ * `{ metadata }` bag in place of schema/options when it is not RequestOptions-shaped.
21
47
  */
22
48
  interface McpClientLike {
23
- listTools?: (params?: unknown) => Promise<McpListToolsResult>;
24
- callTool: (params: McpCallToolParams, resultSchemaOrOptions?: unknown, options?: {
25
- metadata?: Record<string, unknown>;
26
- }) => Promise<McpCallToolResult>;
49
+ listTools?(params?: unknown, options?: unknown): Promise<McpListToolsResult | unknown>;
50
+ callTool(params: McpCallToolParams, resultSchemaOrOptions?: unknown, options?: unknown): Promise<unknown>;
27
51
  }
28
52
  interface McpClientTracerOptions {
29
53
  serverName?: string;
@@ -52,6 +76,17 @@ interface McpTraceMetadata {
52
76
  declare function summarizeMcpValue(value: unknown, maxLength?: number): string;
53
77
  declare function hashServerUrl(url: string): string;
54
78
 
79
+ /**
80
+ * Resolve SDK callTool arity:
81
+ * callTool(params, resultSchema?, requestOptions?)
82
+ * plus AgentInspect overloads that peel `{ metadata }` without dropping RequestOptions.
83
+ * Composed `{ timeout, metadata: { operationId, attemptId } }` keeps both sides.
84
+ */
85
+ declare function resolveCallToolArgs(resultSchemaOrOptions?: unknown, maybeOptions?: unknown): {
86
+ resultSchema: unknown;
87
+ requestOptions: McpRequestOptions | undefined;
88
+ callMetadata: Record<string, unknown>;
89
+ };
55
90
  /**
56
91
  * Wraps an MCP client so tools/list and tools/call emit local tool steps.
57
92
  * Telemetry only — does not proxy network behavior beyond the wrapped client.
@@ -59,9 +94,13 @@ declare function hashServerUrl(url: string): string;
59
94
  * Uses a Proxy over the original client so prototype methods (`connect`,
60
95
  * `close`, `listResources`, …), private SDK state, and `instanceof` stay intact.
61
96
  * A shallow object spread would drop prototype methods and copy private fields.
97
+ *
98
+ * Forwards the real SDK argument positions, including `RequestOptions`
99
+ * (`signal`, `timeout`, progress callbacks). Does not fake cancellation while
100
+ * still dispatching the underlying request.
62
101
  */
63
102
  declare function wrapMcpClient<T extends McpClientLike>(client: T, options?: McpClientTracerOptions): T;
64
103
  /** @internal resets tool call ids for deterministic tests */
65
104
  declare function resetMcpToolCallIdsForTests(): void;
66
105
 
67
- export { type McpCallToolParams, type McpCallToolResult, type McpClientLike, type McpClientTracerOptions, type McpListToolsResult, type McpToolDescriptor, type McpTraceMetadata, hashServerUrl, resetMcpToolCallIdsForTests, summarizeMcpValue, wrapMcpClient };
106
+ 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,15 +15,39 @@ 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
+ * Method syntax (not property function types) so real SDK `Client` remains
40
+ * assignable under `strictFunctionTypes` (bivariant method parameters).
41
+ * `callTool` returns `Promise<unknown>` to accept both normal tool results and
42
+ * the SDK compatibility `{ toolResult }` branch.
43
+ *
44
+ * Matches SDK arity: `callTool(params, resultSchema?, requestOptions?)` and
45
+ * `listTools(params?, requestOptions?)`. AgentInspect also accepts a
46
+ * `{ metadata }` bag in place of schema/options when it is not RequestOptions-shaped.
21
47
  */
22
48
  interface McpClientLike {
23
- listTools?: (params?: unknown) => Promise<McpListToolsResult>;
24
- callTool: (params: McpCallToolParams, resultSchemaOrOptions?: unknown, options?: {
25
- metadata?: Record<string, unknown>;
26
- }) => Promise<McpCallToolResult>;
49
+ listTools?(params?: unknown, options?: unknown): Promise<McpListToolsResult | unknown>;
50
+ callTool(params: McpCallToolParams, resultSchemaOrOptions?: unknown, options?: unknown): Promise<unknown>;
27
51
  }
28
52
  interface McpClientTracerOptions {
29
53
  serverName?: string;
@@ -52,6 +76,17 @@ interface McpTraceMetadata {
52
76
  declare function summarizeMcpValue(value: unknown, maxLength?: number): string;
53
77
  declare function hashServerUrl(url: string): string;
54
78
 
79
+ /**
80
+ * Resolve SDK callTool arity:
81
+ * callTool(params, resultSchema?, requestOptions?)
82
+ * plus AgentInspect overloads that peel `{ metadata }` without dropping RequestOptions.
83
+ * Composed `{ timeout, metadata: { operationId, attemptId } }` keeps both sides.
84
+ */
85
+ declare function resolveCallToolArgs(resultSchemaOrOptions?: unknown, maybeOptions?: unknown): {
86
+ resultSchema: unknown;
87
+ requestOptions: McpRequestOptions | undefined;
88
+ callMetadata: Record<string, unknown>;
89
+ };
55
90
  /**
56
91
  * Wraps an MCP client so tools/list and tools/call emit local tool steps.
57
92
  * Telemetry only — does not proxy network behavior beyond the wrapped client.
@@ -59,9 +94,13 @@ declare function hashServerUrl(url: string): string;
59
94
  * Uses a Proxy over the original client so prototype methods (`connect`,
60
95
  * `close`, `listResources`, …), private SDK state, and `instanceof` stay intact.
61
96
  * A shallow object spread would drop prototype methods and copy private fields.
97
+ *
98
+ * Forwards the real SDK argument positions, including `RequestOptions`
99
+ * (`signal`, `timeout`, progress callbacks). Does not fake cancellation while
100
+ * still dispatching the underlying request.
62
101
  */
63
102
  declare function wrapMcpClient<T extends McpClientLike>(client: T, options?: McpClientTracerOptions): T;
64
103
  /** @internal resets tool call ids for deterministic tests */
65
104
  declare function resetMcpToolCallIdsForTests(): void;
66
105
 
67
- export { type McpCallToolParams, type McpCallToolResult, type McpClientLike, type McpClientTracerOptions, type McpListToolsResult, type McpToolDescriptor, type McpTraceMetadata, hashServerUrl, resetMcpToolCallIdsForTests, summarizeMcpValue, wrapMcpClient };
106
+ 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,107 @@ 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 peelOptionsObject(value) {
80
+ if (value === null || value === void 0) {
81
+ return { callMetadata: {}, requestOptions: void 0 };
82
+ }
83
+ if (typeof value !== "object") {
84
+ return { callMetadata: {}, requestOptions: void 0 };
85
+ }
86
+ const obj = value;
87
+ const callMetadata = extractCallMetadata(obj);
88
+ if (isAgentInspectMetadataBag(value)) {
89
+ return { callMetadata, requestOptions: void 0 };
90
+ }
91
+ if (isSdkRequestOptions(value) || Object.keys(obj).length > 0) {
92
+ const { metadata: _ignored, ...rest } = obj;
93
+ return {
94
+ callMetadata,
95
+ requestOptions: rest
96
+ };
97
+ }
98
+ return { callMetadata, requestOptions: void 0 };
99
+ }
100
+ function resolveCallToolArgs(resultSchemaOrOptions, maybeOptions) {
101
+ if (maybeOptions !== void 0) {
102
+ const peeled = peelOptionsObject(maybeOptions);
103
+ return {
104
+ resultSchema: resultSchemaOrOptions,
105
+ requestOptions: peeled.requestOptions,
106
+ callMetadata: peeled.callMetadata
107
+ };
108
+ }
109
+ if (isAgentInspectMetadataBag(resultSchemaOrOptions)) {
110
+ return {
111
+ resultSchema: void 0,
112
+ requestOptions: void 0,
113
+ callMetadata: extractCallMetadata(resultSchemaOrOptions)
114
+ };
115
+ }
116
+ if (isSdkRequestOptions(resultSchemaOrOptions)) {
117
+ const peeled = peelOptionsObject(resultSchemaOrOptions);
118
+ return {
119
+ resultSchema: void 0,
120
+ requestOptions: peeled.requestOptions,
121
+ callMetadata: peeled.callMetadata
122
+ };
123
+ }
124
+ return {
125
+ resultSchema: resultSchemaOrOptions,
126
+ requestOptions: void 0,
127
+ callMetadata: {}
128
+ };
129
+ }
130
+ function invokeCallTool(callToolImpl, params, resultSchema, requestOptions) {
131
+ const fn = callToolImpl;
132
+ if (requestOptions !== void 0) {
133
+ return fn(params, resultSchema, requestOptions);
134
+ }
135
+ if (resultSchema !== void 0) {
136
+ return fn(params, resultSchema);
137
+ }
138
+ return fn(params);
139
+ }
50
140
  function wrapMcpClient(client, options = {}) {
51
141
  const maxSummaryLength = options.maxSummaryLength ?? 240;
52
142
  const listToolsImpl = typeof client.listTools === "function" ? client.listTools.bind(client) : void 0;
53
143
  const callToolImpl = client.callTool.bind(client);
54
- const wrappedListTools = listToolsImpl ? async (params) => step(
144
+ const wrappedListTools = listToolsImpl ? async (params, requestOptions) => step(
55
145
  "mcp:tools/list",
56
146
  async () => {
57
- const result = await listToolsImpl(params);
58
- return result;
147
+ if (requestOptions !== void 0) {
148
+ return listToolsImpl(params, requestOptions);
149
+ }
150
+ return listToolsImpl(params);
59
151
  },
60
152
  {
61
153
  type: "tool",
@@ -66,32 +158,13 @@ function wrapMcpClient(client, options = {}) {
66
158
  }
67
159
  ) : void 0;
68
160
  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
- }
161
+ const { resultSchema, requestOptions, callMetadata } = resolveCallToolArgs(
162
+ resultSchemaOrOptions,
163
+ maybeOptions
164
+ );
84
165
  return step(
85
166
  `mcp:${params.name}`,
86
- async () => {
87
- if (resultSchema !== void 0) {
88
- return callToolImpl(
89
- params,
90
- resultSchema
91
- );
92
- }
93
- return callToolImpl(params);
94
- },
167
+ async () => invokeCallTool(callToolImpl, params, resultSchema, requestOptions),
95
168
  {
96
169
  type: "tool",
97
170
  metadata: baseMetadata(options, {
@@ -126,6 +199,6 @@ function resetMcpToolCallIdsForTests() {
126
199
  toolCallCounter = 0;
127
200
  }
128
201
 
129
- export { hashServerUrl, resetMcpToolCallIdsForTests, summarizeMcpValue, wrapMcpClient };
202
+ export { hashServerUrl, resetMcpToolCallIdsForTests, resolveCallToolArgs, summarizeMcpValue, wrapMcpClient };
130
203
  //# sourceMappingURL=index.mjs.map
131
204
  //# 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/** Peel AgentInspect `metadata` without consuming SDK RequestOptions keys. */\nfunction peelOptionsObject(value: unknown): {\n callMetadata: Record<string, unknown>;\n requestOptions: McpRequestOptions | undefined;\n} {\n if (value === null || value === undefined) {\n return { callMetadata: {}, requestOptions: undefined };\n }\n if (typeof value !== \"object\") {\n return { callMetadata: {}, requestOptions: undefined };\n }\n const obj = value as Record<string, unknown>;\n const callMetadata = extractCallMetadata(obj);\n\n // Pure AI bag — do not forward as SDK RequestOptions.\n if (isAgentInspectMetadataBag(value)) {\n return { callMetadata, requestOptions: undefined };\n }\n\n if (isSdkRequestOptions(value) || Object.keys(obj).length > 0) {\n const { metadata: _ignored, ...rest } = obj;\n return {\n callMetadata,\n requestOptions: rest as McpRequestOptions,\n };\n }\n\n return { callMetadata, requestOptions: undefined };\n}\n\n/**\n * Resolve SDK callTool arity:\n * callTool(params, resultSchema?, requestOptions?)\n * plus AgentInspect overloads that peel `{ metadata }` without dropping RequestOptions.\n * Composed `{ timeout, metadata: { operationId, attemptId } }` keeps both sides.\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 const peeled = peelOptionsObject(maybeOptions);\n return {\n resultSchema: resultSchemaOrOptions,\n requestOptions: peeled.requestOptions,\n callMetadata: peeled.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 const peeled = peelOptionsObject(resultSchemaOrOptions);\n return {\n resultSchema: undefined,\n requestOptions: peeled.requestOptions,\n callMetadata: peeled.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.21",
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.21"
39
39
  },
40
40
  "publishConfig": {
41
41
  "access": "public"