@mattral/collector 1.1.0 → 1.2.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mattral/collector",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Health checking and traffic-observing proxy collectors for MCP servers",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -46,7 +46,7 @@
46
46
  "dependencies": {
47
47
  "@mattral/core": "^1.0.0",
48
48
  "@mattral/storage": "^1.0.0",
49
- "@modelcontextprotocol/sdk": "^1.29.0"
49
+ "@modelcontextprotocol/sdk": "^1.32.2"
50
50
  },
51
51
  "devDependencies": {
52
52
  "typescript": "^5.7.3"
@@ -1,28 +0,0 @@
1
- import type { JsonRpcMessage } from "./json-rpc-framer.js";
2
- /**
3
- * Extracts a human-readable error message from a raw MCP `tools/call`
4
- * response, for both kinds of failure the protocol allows:
5
- *
6
- * - **Protocol-level failures**: the JSON-RPC response has an `error`
7
- * object (e.g. a malformed request, a transport-level failure). Its
8
- * `.message` is already the right text — nothing to unwrap.
9
- * - **Tool-level failures**: the JSON-RPC response is a normal `result`
10
- * with `isError: true`, and the actual, tool-specific error description
11
- * lives in `result.content` as ordinary text blocks — this is the MCP
12
- * spec's convention for a tool reporting its *own* failure without it
13
- * being treated as a transport-level protocol error (this project's own
14
- * reference server's `flaky` tool does exactly this).
15
- *
16
- * Before this function existed, every tool-level failure's real error
17
- * text was discarded in favor of one generic placeholder string,
18
- * regardless of what the tool actually said — the same underlying mistake
19
- * as the pre-`extractOutputPayload` output-shape bug (see
20
- * docs/decisions/0015-statistical-drift-detection.md): treating MCP's
21
- * `content` array as opaque instead of reading what's actually inside it.
22
- * See docs/decisions/0016-error-classification.md.
23
- *
24
- * Falls back to a generic placeholder only when there's truly no error
25
- * object and no text content to describe the failure at all.
26
- */
27
- export declare function extractErrorMessage(message: JsonRpcMessage): string;
28
- //# sourceMappingURL=error-message.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"error-message.d.ts","sourceRoot":"","sources":["../src/error-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAkBnE"}
@@ -1,42 +0,0 @@
1
- /**
2
- * Extracts a human-readable error message from a raw MCP `tools/call`
3
- * response, for both kinds of failure the protocol allows:
4
- *
5
- * - **Protocol-level failures**: the JSON-RPC response has an `error`
6
- * object (e.g. a malformed request, a transport-level failure). Its
7
- * `.message` is already the right text — nothing to unwrap.
8
- * - **Tool-level failures**: the JSON-RPC response is a normal `result`
9
- * with `isError: true`, and the actual, tool-specific error description
10
- * lives in `result.content` as ordinary text blocks — this is the MCP
11
- * spec's convention for a tool reporting its *own* failure without it
12
- * being treated as a transport-level protocol error (this project's own
13
- * reference server's `flaky` tool does exactly this).
14
- *
15
- * Before this function existed, every tool-level failure's real error
16
- * text was discarded in favor of one generic placeholder string,
17
- * regardless of what the tool actually said — the same underlying mistake
18
- * as the pre-`extractOutputPayload` output-shape bug (see
19
- * docs/decisions/0015-statistical-drift-detection.md): treating MCP's
20
- * `content` array as opaque instead of reading what's actually inside it.
21
- * See docs/decisions/0016-error-classification.md.
22
- *
23
- * Falls back to a generic placeholder only when there's truly no error
24
- * object and no text content to describe the failure at all.
25
- */
26
- export function extractErrorMessage(message) {
27
- if (message.error?.message)
28
- return message.error.message;
29
- const content = message.result?.content;
30
- if (Array.isArray(content)) {
31
- const texts = content
32
- .filter((block) => typeof block === "object" &&
33
- block !== null &&
34
- block.type === "text" &&
35
- typeof block.text === "string")
36
- .map((block) => block.text);
37
- if (texts.length > 0)
38
- return texts.join(" ");
39
- }
40
- return "Tool call returned isError: true, with no error text or content to describe why.";
41
- }
42
- //# sourceMappingURL=error-message.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"error-message.js","sourceRoot":"","sources":["../src/error-message.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAuB;IACzD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO;QAAE,OAAO,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;IAEzD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC;IACxC,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,OAAO;aAClB,MAAM,CACL,CAAC,KAAK,EAA2C,EAAE,CACjD,OAAO,KAAK,KAAK,QAAQ;YACzB,KAAK,KAAK,IAAI;YACb,KAA4B,CAAC,IAAI,KAAK,MAAM;YAC7C,OAAQ,KAA4B,CAAC,IAAI,KAAK,QAAQ,CACzD;aACA,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,kFAAkF,CAAC;AAC5F,CAAC"}
@@ -1,43 +0,0 @@
1
- import { type DriftEvent, type Server } from "@mattral/core";
2
- import type { ReliabilityStore } from "@mattral/storage";
3
- export interface HealthCheckResult {
4
- serverId: string;
5
- reachable: boolean;
6
- latencyMs: number;
7
- toolCount: number;
8
- driftEvents: DriftEvent[];
9
- error?: string;
10
- }
11
- export interface HealthCheckerOptions {
12
- store: ReliabilityStore;
13
- /** Client identity advertised to monitored servers during the MCP handshake. */
14
- clientInfo?: {
15
- name: string;
16
- version: string;
17
- };
18
- /** Timeout for the initialize handshake and the tools/list round trip. Default 10s. */
19
- timeoutMs?: number;
20
- }
21
- /** Reserved pseudo tool-name under which health-check round trips are recorded. */
22
- export declare const HEALTH_CHECK_TOOL_NAME = "__health_check__";
23
- /**
24
- * Performs a single, side-effect-free health check against a server:
25
- * connects, completes the MCP `initialize` handshake, calls `tools/list`,
26
- * and disconnects.
27
- *
28
- * This deliberately never calls a tool. Per the project's operational
29
- * principles (spec section 11 / docs/architecture.md#security), a
30
- * monitoring tool must not exercise side effects on a server it doesn't
31
- * have explicit consent to invoke. Observing *real* tool calls — the ones a
32
- * live agent chose to make — is the job of {@link StdioProxyCollector}
33
- * instead, where mcp-reliable never originates the call itself.
34
- */
35
- export declare class HealthChecker {
36
- private readonly store;
37
- private readonly clientInfo;
38
- private readonly timeoutMs;
39
- constructor(options: HealthCheckerOptions);
40
- check(server: Server): Promise<HealthCheckResult>;
41
- private recordHealthCheckExecution;
42
- }
43
- //# sourceMappingURL=health-checker.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"health-checker.d.ts","sourceRoot":"","sources":["../src/health-checker.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,UAAU,EAEf,KAAK,MAAM,EAEZ,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGzD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,gBAAgB,CAAC;IACxB,gFAAgF;IAChF,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,mFAAmF;AACnF,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAEzD;;;;;;;;;;;GAWG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoC;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,OAAO,EAAE,oBAAoB;IAMnC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAwDvD,OAAO,CAAC,0BAA0B;CAmBnC"}
@@ -1,93 +0,0 @@
1
- import { randomUUID } from "node:crypto";
2
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
3
- import { computeSchemaFingerprint, detectSchemaDrift } from "@mattral/core";
4
- import { createClientTransport } from "./transport-factory.js";
5
- /** Reserved pseudo tool-name under which health-check round trips are recorded. */
6
- export const HEALTH_CHECK_TOOL_NAME = "__health_check__";
7
- /**
8
- * Performs a single, side-effect-free health check against a server:
9
- * connects, completes the MCP `initialize` handshake, calls `tools/list`,
10
- * and disconnects.
11
- *
12
- * This deliberately never calls a tool. Per the project's operational
13
- * principles (spec section 11 / docs/architecture.md#security), a
14
- * monitoring tool must not exercise side effects on a server it doesn't
15
- * have explicit consent to invoke. Observing *real* tool calls — the ones a
16
- * live agent chose to make — is the job of {@link StdioProxyCollector}
17
- * instead, where mcp-reliable never originates the call itself.
18
- */
19
- export class HealthChecker {
20
- store;
21
- clientInfo;
22
- timeoutMs;
23
- constructor(options) {
24
- this.store = options.store;
25
- this.clientInfo = options.clientInfo ?? { name: "mcp-reliable", version: "1.0.0" };
26
- this.timeoutMs = options.timeoutMs ?? 10_000;
27
- }
28
- async check(server) {
29
- const start = performance.now();
30
- const now = Date.now();
31
- const client = new Client(this.clientInfo, { capabilities: {} });
32
- const transport = createClientTransport(server.transport);
33
- const driftEvents = [];
34
- try {
35
- await client.connect(transport, { timeout: this.timeoutMs });
36
- const { tools } = await client.listTools(undefined, { timeout: this.timeoutMs });
37
- const latencyMs = performance.now() - start;
38
- for (const tool of tools) {
39
- const fingerprint = computeSchemaFingerprint(tool.inputSchema);
40
- const existing = this.store.getTool(server.id, tool.name);
41
- const drift = detectSchemaDrift({
42
- serverId: server.id,
43
- toolName: tool.name,
44
- previousFingerprint: existing?.schemaFingerprint,
45
- currentFingerprint: fingerprint,
46
- now
47
- });
48
- if (drift) {
49
- this.store.recordDriftEvent(drift);
50
- driftEvents.push(drift);
51
- }
52
- const toolRecord = {
53
- id: existing?.id ?? randomUUID(),
54
- serverId: server.id,
55
- name: tool.name,
56
- description: tool.description,
57
- schemaFingerprint: fingerprint,
58
- inputSchema: tool.inputSchema,
59
- firstSeenAt: existing?.firstSeenAt ?? now,
60
- lastSeenAt: now
61
- };
62
- this.store.upsertTool(toolRecord);
63
- }
64
- this.recordHealthCheckExecution(server.id, now, latencyMs, true);
65
- return { serverId: server.id, reachable: true, latencyMs, toolCount: tools.length, driftEvents };
66
- }
67
- catch (error) {
68
- const latencyMs = performance.now() - start;
69
- const message = error instanceof Error ? error.message : String(error);
70
- this.recordHealthCheckExecution(server.id, now, latencyMs, false, message);
71
- return { serverId: server.id, reachable: false, latencyMs, toolCount: 0, driftEvents, error: message };
72
- }
73
- finally {
74
- await client.close().catch(() => {
75
- // Best-effort: the connection may already be dead if the check failed.
76
- });
77
- }
78
- }
79
- recordHealthCheckExecution(serverId, startedAt, durationMs, success, errorMessage) {
80
- const execution = {
81
- id: randomUUID(),
82
- serverId,
83
- toolName: HEALTH_CHECK_TOOL_NAME,
84
- startedAt,
85
- durationMs,
86
- success,
87
- errorMessage,
88
- source: "health-check"
89
- };
90
- this.store.recordExecution(execution);
91
- }
92
- }
93
- //# sourceMappingURL=health-checker.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"health-checker.js","sourceRoot":"","sources":["../src/health-checker.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts DELETED
@@ -1,5 +0,0 @@
1
- export * from "./json-rpc-framer.js";
2
- export * from "./transport-factory.js";
3
- export * from "./health-checker.js";
4
- export * from "./proxy-collector.js";
5
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC"}
package/dist/index.js DELETED
@@ -1,5 +0,0 @@
1
- export * from "./json-rpc-framer.js";
2
- export * from "./transport-factory.js";
3
- export * from "./health-checker.js";
4
- export * from "./proxy-collector.js";
5
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC"}
@@ -1,51 +0,0 @@
1
- /**
2
- * A minimal JSON-RPC 2.0 message shape, loosely typed on purpose: the proxy
3
- * only needs to inspect `id`, `method`, `result`, and `error` — it forwards
4
- * every other field verbatim without validating them against the full MCP
5
- * type definitions (that validation is the target server's job).
6
- */
7
- export interface JsonRpcMessage {
8
- jsonrpc?: string;
9
- id?: string | number;
10
- method?: string;
11
- params?: {
12
- name?: string;
13
- arguments?: unknown;
14
- [key: string]: unknown;
15
- };
16
- result?: {
17
- isError?: boolean;
18
- content?: unknown;
19
- [key: string]: unknown;
20
- };
21
- error?: {
22
- code: number;
23
- message: string;
24
- [key: string]: unknown;
25
- };
26
- [key: string]: unknown;
27
- }
28
- /**
29
- * The MCP stdio transport frames JSON-RPC messages as one JSON object per
30
- * line (newline-delimited), per the MCP specification. This class buffers
31
- * partial reads from a stream and yields fully-parsed messages as they
32
- * become available — the same approach the official SDK's internal
33
- * ReadBuffer uses, reimplemented here so the proxy collector can stay a
34
- * thin, dependency-light pass-through rather than depending on SDK
35
- * internals that aren't part of its public API.
36
- *
37
- * Malformed lines are surfaced via the `onParseError` callback rather than
38
- * thrown, since a single bad line should not take down the whole proxy —
39
- * it is forwarded to the child/downstream as raw bytes regardless (the
40
- * proxy's job is to observe traffic, not to enforce protocol correctness).
41
- */
42
- export declare class JsonRpcFramer {
43
- private readonly onMessage;
44
- private readonly onParseError?;
45
- private buffer;
46
- constructor(onMessage: (message: JsonRpcMessage, raw: string) => void, onParseError?: ((raw: string, error: unknown) => void) | undefined);
47
- push(chunk: Buffer | string): void;
48
- }
49
- /** Serializes a JSON-RPC message back to the newline-delimited wire format. */
50
- export declare function serializeJsonRpc(message: JsonRpcMessage): string;
51
- //# sourceMappingURL=json-rpc-framer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"json-rpc-framer.d.ts","sourceRoot":"","sources":["../src/json-rpc-framer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IACxE,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC1E,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAClE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,aAAa;IAItB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IAJhC,OAAO,CAAC,MAAM,CAAM;gBAGD,SAAS,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,EACzD,YAAY,CAAC,GAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,aAAA;IAGvE,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;CAgBnC;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAEhE"}
@@ -1,46 +0,0 @@
1
- /**
2
- * The MCP stdio transport frames JSON-RPC messages as one JSON object per
3
- * line (newline-delimited), per the MCP specification. This class buffers
4
- * partial reads from a stream and yields fully-parsed messages as they
5
- * become available — the same approach the official SDK's internal
6
- * ReadBuffer uses, reimplemented here so the proxy collector can stay a
7
- * thin, dependency-light pass-through rather than depending on SDK
8
- * internals that aren't part of its public API.
9
- *
10
- * Malformed lines are surfaced via the `onParseError` callback rather than
11
- * thrown, since a single bad line should not take down the whole proxy —
12
- * it is forwarded to the child/downstream as raw bytes regardless (the
13
- * proxy's job is to observe traffic, not to enforce protocol correctness).
14
- */
15
- export class JsonRpcFramer {
16
- onMessage;
17
- onParseError;
18
- buffer = "";
19
- constructor(onMessage, onParseError) {
20
- this.onMessage = onMessage;
21
- this.onParseError = onParseError;
22
- }
23
- push(chunk) {
24
- this.buffer += chunk.toString("utf8");
25
- let newlineIndex;
26
- while ((newlineIndex = this.buffer.indexOf("\n")) !== -1) {
27
- const line = this.buffer.slice(0, newlineIndex);
28
- this.buffer = this.buffer.slice(newlineIndex + 1);
29
- const trimmed = line.trim();
30
- if (trimmed.length === 0)
31
- continue;
32
- try {
33
- const message = JSON.parse(trimmed);
34
- this.onMessage(message, line);
35
- }
36
- catch (error) {
37
- this.onParseError?.(line, error);
38
- }
39
- }
40
- }
41
- }
42
- /** Serializes a JSON-RPC message back to the newline-delimited wire format. */
43
- export function serializeJsonRpc(message) {
44
- return JSON.stringify(message) + "\n";
45
- }
46
- //# sourceMappingURL=json-rpc-framer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"json-rpc-framer.js","sourceRoot":"","sources":["../src/json-rpc-framer.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,aAAa;IAIL;IACA;IAJX,MAAM,GAAG,EAAE,CAAC;IAEpB,YACmB,SAAyD,EACzD,YAAoD;QADpD,cAAS,GAAT,SAAS,CAAgD;QACzD,iBAAY,GAAZ,YAAY,CAAwC;IACpE,CAAC;IAEJ,IAAI,CAAC,KAAsB;QACzB,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,YAAoB,CAAC;QACzB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YACzD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;YAChD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;YAClD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YACnC,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAmB,CAAC;gBACtD,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAChC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAED,+EAA+E;AAC/E,MAAM,UAAU,gBAAgB,CAAC,OAAuB;IACtD,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;AACxC,CAAC"}
@@ -1,32 +0,0 @@
1
- /**
2
- * Extracts the "meaningful" structured payload from a raw MCP
3
- * `tools/call` result, for output-shape drift detection to actually be
4
- * useful against it.
5
- *
6
- * Naively hashing `result.content` itself is close to useless for the
7
- * extremely common case where a tool returns its real structured data as
8
- * JSON text inside a single content block — `content: [{ type: "text",
9
- * text: "{...}" }]` has the exact same `[{type, text}]` shape whether the
10
- * embedded JSON is `{"message": "..."}` or `{"echoed": "...", "respondedAt":
11
- * "..."}`. A structural hash of the wrapper alone would never notice the
12
- * tool's actual output changed underneath it — this is exactly what this
13
- * project's own reference server does (see
14
- * `examples/reference-mcp-server/src/index.ts`), and what a great many
15
- * real-world MCP tools do too, for any tool that doesn't declare a formal
16
- * `outputSchema`. This function unwraps that, so what gets fingerprinted
17
- * is the real payload, not MCP's transport-level envelope around it.
18
- *
19
- * Precedence:
20
- * 1. `structuredContent`, if the tool declared an output schema and the
21
- * SDK populated it — already a real object, nothing to unwrap.
22
- * 2. A single text content block that parses as JSON — the common
23
- * "structured data serialized as text" convention.
24
- * 3. Otherwise, the raw `content` array as-is — still useful: catches a
25
- * tool switching between text/image/resource blocks, or adding/
26
- * removing blocks, even without parseable JSON inside them.
27
- * 4. If there's no `content` or `structuredContent` at all, the raw
28
- * result object, matching how this was computed before this function
29
- * existed (see docs/decisions/0015-statistical-drift-detection.md).
30
- */
31
- export declare function extractOutputPayload(result: unknown): unknown;
32
- //# sourceMappingURL=output-payload.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"output-payload.d.ts","sourceRoot":"","sources":["../src/output-payload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAsB7D"}
@@ -1,54 +0,0 @@
1
- /**
2
- * Extracts the "meaningful" structured payload from a raw MCP
3
- * `tools/call` result, for output-shape drift detection to actually be
4
- * useful against it.
5
- *
6
- * Naively hashing `result.content` itself is close to useless for the
7
- * extremely common case where a tool returns its real structured data as
8
- * JSON text inside a single content block — `content: [{ type: "text",
9
- * text: "{...}" }]` has the exact same `[{type, text}]` shape whether the
10
- * embedded JSON is `{"message": "..."}` or `{"echoed": "...", "respondedAt":
11
- * "..."}`. A structural hash of the wrapper alone would never notice the
12
- * tool's actual output changed underneath it — this is exactly what this
13
- * project's own reference server does (see
14
- * `examples/reference-mcp-server/src/index.ts`), and what a great many
15
- * real-world MCP tools do too, for any tool that doesn't declare a formal
16
- * `outputSchema`. This function unwraps that, so what gets fingerprinted
17
- * is the real payload, not MCP's transport-level envelope around it.
18
- *
19
- * Precedence:
20
- * 1. `structuredContent`, if the tool declared an output schema and the
21
- * SDK populated it — already a real object, nothing to unwrap.
22
- * 2. A single text content block that parses as JSON — the common
23
- * "structured data serialized as text" convention.
24
- * 3. Otherwise, the raw `content` array as-is — still useful: catches a
25
- * tool switching between text/image/resource blocks, or adding/
26
- * removing blocks, even without parseable JSON inside them.
27
- * 4. If there's no `content` or `structuredContent` at all, the raw
28
- * result object, matching how this was computed before this function
29
- * existed (see docs/decisions/0015-statistical-drift-detection.md).
30
- */
31
- export function extractOutputPayload(result) {
32
- if (result === null || typeof result !== "object")
33
- return result;
34
- const r = result;
35
- if (r.structuredContent !== undefined)
36
- return r.structuredContent;
37
- if (Array.isArray(r.content)) {
38
- if (r.content.length === 1) {
39
- const block = r.content[0];
40
- if (block?.type === "text" && typeof block.text === "string") {
41
- try {
42
- return JSON.parse(block.text);
43
- }
44
- catch {
45
- // Not JSON - a genuine plain-text result. Fall through to
46
- // hashing the content array itself.
47
- }
48
- }
49
- }
50
- return r.content;
51
- }
52
- return result;
53
- }
54
- //# sourceMappingURL=output-payload.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"output-payload.js","sourceRoot":"","sources":["../src/output-payload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAe;IAClD,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IACjE,MAAM,CAAC,GAAG,MAA4D,CAAC;IAEvE,IAAI,CAAC,CAAC,iBAAiB,KAAK,SAAS;QAAE,OAAO,CAAC,CAAC,iBAAiB,CAAC;IAElE,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7B,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAqC,CAAC;YAC/D,IAAI,KAAK,EAAE,IAAI,KAAK,MAAM,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC7D,IAAI,CAAC;oBACH,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAChC,CAAC;gBAAC,MAAM,CAAC;oBACP,0DAA0D;oBAC1D,oCAAoC;gBACtC,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,CAAC,CAAC,OAAO,CAAC;IACnB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -1,83 +0,0 @@
1
- import { type DriftEvent, type Execution } from "@mattral/core";
2
- import type { ReliabilityStore } from "@mattral/storage";
3
- export interface StdioProxyCollectorOptions {
4
- serverId: string;
5
- store: ReliabilityStore;
6
- command: string;
7
- args?: string[];
8
- env?: Record<string, string>;
9
- cwd?: string;
10
- /** Called for every recorded execution, in addition to persisting it to the store. */
11
- onExecution?: (execution: Execution) => void;
12
- /** Called whenever a drift event is detected and recorded. */
13
- onDrift?: (event: DriftEvent) => void;
14
- /** Stream carrying traffic FROM the real client (defaults to this process's stdin). */
15
- input?: NodeJS.ReadableStream;
16
- /** Stream carrying traffic TO the real client (defaults to this process's stdout). */
17
- output?: NodeJS.WritableStream;
18
- /**
19
- * How many executions of the *same tool* to accumulate between
20
- * window-based drift checks (output-shape and statistical/latency).
21
- * Unlike schema drift (an O(1) fingerprint compare, checked on every
22
- * `tools/list`), these compare whole windows of stored executions —
23
- * running that on literally every single call would mean a store query
24
- * plus a KS test per call on hot paths. Default 10: frequent enough that
25
- * drift is caught within a handful of seconds of typical traffic, cheap
26
- * enough not to matter. See docs/decisions/0015-statistical-drift-detection.md.
27
- */
28
- driftCheckIntervalCalls?: number;
29
- /**
30
- * Size of each of the two (baseline, recent) windows compared for
31
- * window-based drift. Default 20, matching `detectLatencyDrift`'s own
32
- * default `minSampleSize` — there's no point fetching a bigger window
33
- * than the detector needs.
34
- */
35
- driftWindowSize?: number;
36
- }
37
- /**
38
- * A transparent stdio proxy that sits between an MCP client (an agent) and
39
- * a real MCP server: it spawns the target server as a child process and
40
- * forwards every JSON-RPC message between the client and the child
41
- * unmodified, while recording an `Execution` for every `tools/call`
42
- * request/response pair it observes, and a `Tool` (with schema drift
43
- * detection) for every `tools/list` response.
44
- *
45
- * Because it only ever forwards traffic a real client originated, it
46
- * requires no special consent model of its own for the calls it observes —
47
- * see docs/architecture.md#collection-model. From the client's point of
48
- * view, this proxy *is* the MCP server: point your agent's server command
49
- * at `mcp-reliable proxy <server-id> -- <original command>` instead of the
50
- * original command directly.
51
- */
52
- export declare class StdioProxyCollector {
53
- private readonly options;
54
- private readonly driftCheckIntervalCalls;
55
- private readonly driftWindowSize;
56
- private child;
57
- private readonly pendingCalls;
58
- private readonly pendingListRequests;
59
- private readonly callCountByTool;
60
- constructor(options: StdioProxyCollectorOptions);
61
- /**
62
- * Starts the child process and begins forwarding traffic. Resolves with
63
- * the child's exit code once it terminates, or rejects if it could not
64
- * be started at all (e.g. command not found).
65
- */
66
- start(): Promise<number | null>;
67
- stop(): Promise<void>;
68
- private handleDownstreamMessage;
69
- private handleUpstreamMessage;
70
- private recordCallExecution;
71
- private recordDrift;
72
- /**
73
- * Every `driftCheckIntervalCalls` calls to a given tool, pulls its last
74
- * two `driftWindowSize`-execution windows and runs the window-based
75
- * drift detectors (output-shape, latency) against them. Schema drift is
76
- * handled separately in `recordToolsListResult` — it's a per-fingerprint
77
- * compare, not a window comparison, so it runs on every `tools/list`
78
- * instead of being throttled here.
79
- */
80
- private maybeCheckWindowDrift;
81
- private recordToolsListResult;
82
- }
83
- //# sourceMappingURL=proxy-collector.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"proxy-collector.d.ts","sourceRoot":"","sources":["../src/proxy-collector.ts"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,UAAU,EACf,KAAK,SAAS,EAEf,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAKzD,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,gBAAgB,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sFAAsF;IACtF,WAAW,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;IAC7C,8DAA8D;IAC9D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,uFAAuF;IACvF,KAAK,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC9B,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B;;;;;;;;;OASG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAoBD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6B;IACrD,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAS;IACjD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA2C;IACxE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAA8B;IAClE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA6B;gBAEjD,OAAO,EAAE,0BAA0B;IAM/C;;;;OAIG;IACH,KAAK,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA+CzB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,OAAO,CAAC,uBAAuB;IAW/B,OAAO,CAAC,qBAAqB;IAkB7B,OAAO,CAAC,mBAAmB;IA4B3B,OAAO,CAAC,WAAW;IAKnB;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB;IAsC7B,OAAO,CAAC,qBAAqB;CAgC9B"}
@@ -1,214 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { randomUUID } from "node:crypto";
3
- import { computeOutputSignature, computeSchemaFingerprint, detectLatencyDrift, detectOutputShapeDrift, detectSchemaDrift } from "@mattral/core";
4
- import { JsonRpcFramer } from "./json-rpc-framer.js";
5
- import { extractErrorMessage } from "./error-message.js";
6
- import { extractOutputPayload } from "./output-payload.js";
7
- function isToolsListResult(value) {
8
- return (typeof value === "object" &&
9
- value !== null &&
10
- Array.isArray(value.tools));
11
- }
12
- /**
13
- * A transparent stdio proxy that sits between an MCP client (an agent) and
14
- * a real MCP server: it spawns the target server as a child process and
15
- * forwards every JSON-RPC message between the client and the child
16
- * unmodified, while recording an `Execution` for every `tools/call`
17
- * request/response pair it observes, and a `Tool` (with schema drift
18
- * detection) for every `tools/list` response.
19
- *
20
- * Because it only ever forwards traffic a real client originated, it
21
- * requires no special consent model of its own for the calls it observes —
22
- * see docs/architecture.md#collection-model. From the client's point of
23
- * view, this proxy *is* the MCP server: point your agent's server command
24
- * at `mcp-reliable proxy <server-id> -- <original command>` instead of the
25
- * original command directly.
26
- */
27
- export class StdioProxyCollector {
28
- options;
29
- driftCheckIntervalCalls;
30
- driftWindowSize;
31
- child;
32
- pendingCalls = new Map();
33
- pendingListRequests = new Set();
34
- callCountByTool = new Map();
35
- constructor(options) {
36
- this.options = options;
37
- this.driftCheckIntervalCalls = options.driftCheckIntervalCalls ?? 10;
38
- this.driftWindowSize = options.driftWindowSize ?? 20;
39
- }
40
- /**
41
- * Starts the child process and begins forwarding traffic. Resolves with
42
- * the child's exit code once it terminates, or rejects if it could not
43
- * be started at all (e.g. command not found).
44
- */
45
- start() {
46
- const { command, args = [], env, cwd } = this.options;
47
- return new Promise((resolve, reject) => {
48
- const child = spawn(command, args, {
49
- env: env ? { ...process.env, ...env } : process.env,
50
- cwd,
51
- stdio: ["pipe", "pipe", "inherit"]
52
- });
53
- this.child = child;
54
- const childStdin = child.stdin;
55
- const childStdout = child.stdout;
56
- if (!childStdin || !childStdout) {
57
- reject(new Error("Failed to open stdio pipes for the child MCP server process"));
58
- return;
59
- }
60
- const input = this.options.input ?? process.stdin;
61
- const output = this.options.output ?? process.stdout;
62
- // Downstream: messages FROM the client TO the child (requests, notifications).
63
- const downstreamFramer = new JsonRpcFramer((message, raw) => {
64
- this.handleDownstreamMessage(message);
65
- childStdin.write(raw + "\n");
66
- }, (raw) => childStdin.write(raw + "\n") // forward unparseable lines verbatim; never drop traffic
67
- );
68
- input.on("data", (chunk) => downstreamFramer.push(chunk));
69
- input.on("end", () => child.kill());
70
- // Upstream: messages FROM the child TO the client (responses, notifications).
71
- const upstreamFramer = new JsonRpcFramer((message, raw) => {
72
- this.handleUpstreamMessage(message);
73
- output.write(raw + "\n");
74
- }, (raw) => output.write(raw + "\n"));
75
- childStdout.on("data", (chunk) => upstreamFramer.push(chunk));
76
- child.on("error", (error) => reject(error));
77
- child.on("exit", (code) => resolve(code));
78
- });
79
- }
80
- async stop() {
81
- this.child?.kill();
82
- }
83
- handleDownstreamMessage(message) {
84
- if (message.id === undefined)
85
- return;
86
- if (message.method === "tools/call") {
87
- const toolName = message.params?.name ?? "unknown";
88
- const inputBytes = Buffer.byteLength(JSON.stringify(message.params?.arguments ?? {}), "utf8");
89
- this.pendingCalls.set(message.id, { toolName, startedAt: Date.now(), inputBytes });
90
- }
91
- else if (message.method === "tools/list") {
92
- this.pendingListRequests.add(message.id);
93
- }
94
- }
95
- handleUpstreamMessage(message) {
96
- if (message.id === undefined)
97
- return;
98
- const pendingCall = this.pendingCalls.get(message.id);
99
- if (pendingCall) {
100
- this.pendingCalls.delete(message.id);
101
- this.recordCallExecution(pendingCall, message);
102
- return;
103
- }
104
- if (this.pendingListRequests.has(message.id)) {
105
- this.pendingListRequests.delete(message.id);
106
- if (isToolsListResult(message.result)) {
107
- this.recordToolsListResult(message.result);
108
- }
109
- }
110
- }
111
- recordCallExecution(pending, message) {
112
- const now = Date.now();
113
- const durationMs = now - pending.startedAt;
114
- const isError = Boolean(message.error) || Boolean(message.result?.isError);
115
- const outputBytes = message.result !== undefined ? Buffer.byteLength(JSON.stringify(message.result), "utf8") : undefined;
116
- const outputSignature = !isError && message.result !== undefined ? computeOutputSignature(extractOutputPayload(message.result)) : undefined;
117
- const execution = {
118
- id: randomUUID(),
119
- serverId: this.options.serverId,
120
- toolName: pending.toolName,
121
- startedAt: pending.startedAt,
122
- durationMs,
123
- success: !isError,
124
- errorMessage: isError ? extractErrorMessage(message) : undefined,
125
- outputSignature,
126
- inputBytes: pending.inputBytes,
127
- outputBytes,
128
- source: "proxy"
129
- };
130
- this.options.store.recordExecution(execution);
131
- this.options.onExecution?.(execution);
132
- this.maybeCheckWindowDrift(pending.toolName, now);
133
- }
134
- recordDrift(drift) {
135
- this.options.store.recordDriftEvent(drift);
136
- this.options.onDrift?.(drift);
137
- }
138
- /**
139
- * Every `driftCheckIntervalCalls` calls to a given tool, pulls its last
140
- * two `driftWindowSize`-execution windows and runs the window-based
141
- * drift detectors (output-shape, latency) against them. Schema drift is
142
- * handled separately in `recordToolsListResult` — it's a per-fingerprint
143
- * compare, not a window comparison, so it runs on every `tools/list`
144
- * instead of being throttled here.
145
- */
146
- maybeCheckWindowDrift(toolName, now) {
147
- const count = (this.callCountByTool.get(toolName) ?? 0) + 1;
148
- this.callCountByTool.set(toolName, count);
149
- if (count % this.driftCheckIntervalCalls !== 0)
150
- return;
151
- const windowSize = this.driftWindowSize;
152
- // Most-recent-first (see SqliteStore#listExecutions): the first half is
153
- // the "recent" window, the second half the "baseline" it's compared
154
- // against.
155
- const executions = this.options.store.listExecutions({
156
- serverId: this.options.serverId,
157
- toolName,
158
- limit: windowSize * 2
159
- });
160
- if (executions.length < windowSize * 2)
161
- return;
162
- const recent = executions.slice(0, windowSize);
163
- const baseline = executions.slice(windowSize, windowSize * 2);
164
- const shapeDrift = detectOutputShapeDrift({
165
- serverId: this.options.serverId,
166
- toolName,
167
- baseline,
168
- recent,
169
- now
170
- });
171
- if (shapeDrift)
172
- this.recordDrift(shapeDrift);
173
- const latencyDrift = detectLatencyDrift({
174
- serverId: this.options.serverId,
175
- toolName,
176
- baseline,
177
- recent,
178
- now
179
- });
180
- if (latencyDrift)
181
- this.recordDrift(latencyDrift);
182
- }
183
- recordToolsListResult(result) {
184
- const now = Date.now();
185
- for (const tool of result.tools) {
186
- if (typeof tool.name !== "string")
187
- continue;
188
- const fingerprint = computeSchemaFingerprint(tool.inputSchema);
189
- const existing = this.options.store.getTool(this.options.serverId, tool.name);
190
- const drift = detectSchemaDrift({
191
- serverId: this.options.serverId,
192
- toolName: tool.name,
193
- previousFingerprint: existing?.schemaFingerprint,
194
- currentFingerprint: fingerprint,
195
- now
196
- });
197
- if (drift) {
198
- this.recordDrift(drift);
199
- }
200
- const toolRecord = {
201
- id: existing?.id ?? randomUUID(),
202
- serverId: this.options.serverId,
203
- name: tool.name,
204
- description: tool.description,
205
- schemaFingerprint: fingerprint,
206
- inputSchema: tool.inputSchema,
207
- firstSeenAt: existing?.firstSeenAt ?? now,
208
- lastSeenAt: now
209
- };
210
- this.options.store.upsertTool(toolRecord);
211
- }
212
- }
213
- }
214
- //# sourceMappingURL=proxy-collector.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"proxy-collector.js","sourceRoot":"","sources":["../src/proxy-collector.ts"],"names":[],"mappings":"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"}
@@ -1,11 +0,0 @@
1
- import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
2
- import type { TransportConfig } from "@mattral/core";
3
- /**
4
- * Builds the appropriate official SDK client transport for a server's
5
- * configured transport, used by {@link HealthChecker}. The stdio proxy
6
- * collector does *not* use this — it talks to the child process directly
7
- * (see docs/architecture.md#transport-adapters for why the two collection
8
- * modes have different transport-handling needs).
9
- */
10
- export declare function createClientTransport(config: TransportConfig): Transport;
11
- //# sourceMappingURL=transport-factory.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"transport-factory.d.ts","sourceRoot":"","sources":["../src/transport-factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAI/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAsBxE"}
@@ -1,34 +0,0 @@
1
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
2
- import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
3
- import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
4
- /**
5
- * Builds the appropriate official SDK client transport for a server's
6
- * configured transport, used by {@link HealthChecker}. The stdio proxy
7
- * collector does *not* use this — it talks to the child process directly
8
- * (see docs/architecture.md#transport-adapters for why the two collection
9
- * modes have different transport-handling needs).
10
- */
11
- export function createClientTransport(config) {
12
- switch (config.type) {
13
- case "stdio":
14
- return new StdioClientTransport({
15
- command: config.command,
16
- args: config.args,
17
- env: config.env,
18
- cwd: config.cwd
19
- });
20
- case "sse":
21
- return new SSEClientTransport(new URL(config.url), {
22
- requestInit: config.headers ? { headers: config.headers } : undefined
23
- });
24
- case "http":
25
- return new StreamableHTTPClientTransport(new URL(config.url), {
26
- requestInit: config.headers ? { headers: config.headers } : undefined
27
- });
28
- default: {
29
- const exhaustiveCheck = config;
30
- throw new Error(`Unsupported transport config: ${JSON.stringify(exhaustiveCheck)}`);
31
- }
32
- }
33
- }
34
- //# sourceMappingURL=transport-factory.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"transport-factory.js","sourceRoot":"","sources":["../src/transport-factory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AAGnG;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAuB;IAC3D,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,OAAO;YACV,OAAO,IAAI,oBAAoB,CAAC;gBAC9B,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,GAAG,EAAE,MAAM,CAAC,GAAG;gBACf,GAAG,EAAE,MAAM,CAAC,GAAG;aAChB,CAAC,CAAC;QACL,KAAK,KAAK;YACR,OAAO,IAAI,kBAAkB,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;gBACjD,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS;aACtE,CAAC,CAAC;QACL,KAAK,MAAM;YACT,OAAO,IAAI,6BAA6B,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;gBAC5D,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS;aACtE,CAAC,CAAC;QACL,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,eAAe,GAAU,MAAM,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,iCAAiC,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;AACH,CAAC"}