@graphorin/mcp 0.6.0 → 0.7.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.
Files changed (70) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +73 -5
  3. package/dist/client/adapt-result.d.ts +9 -1
  4. package/dist/client/adapt-result.d.ts.map +1 -1
  5. package/dist/client/adapt-result.js +28 -10
  6. package/dist/client/adapt-result.js.map +1 -1
  7. package/dist/client/client-handlers.js +7 -1
  8. package/dist/client/client-handlers.js.map +1 -1
  9. package/dist/client/client.d.ts.map +1 -1
  10. package/dist/client/client.js +47 -71
  11. package/dist/client/client.js.map +1 -1
  12. package/dist/client/inbound-filters.js +101 -1
  13. package/dist/client/inbound-filters.js.map +1 -1
  14. package/dist/client/index.d.ts +2 -1
  15. package/dist/client/index.js +2 -1
  16. package/dist/client/managed.d.ts +35 -0
  17. package/dist/client/managed.d.ts.map +1 -0
  18. package/dist/client/managed.js +136 -0
  19. package/dist/client/managed.js.map +1 -0
  20. package/dist/client/mcp-resource-reader.js +1 -1
  21. package/dist/client/mcp-resource-reader.js.map +1 -1
  22. package/dist/client/to-tools-run.js +119 -0
  23. package/dist/client/to-tools-run.js.map +1 -0
  24. package/dist/client/to-tools.d.ts +8 -0
  25. package/dist/client/to-tools.d.ts.map +1 -1
  26. package/dist/client/to-tools.js +27 -4
  27. package/dist/client/to-tools.js.map +1 -1
  28. package/dist/client/types.d.ts +12 -3
  29. package/dist/client/types.d.ts.map +1 -1
  30. package/dist/errors/index.d.ts +3 -3
  31. package/dist/errors/index.js +1 -1
  32. package/dist/errors/index.js.map +1 -1
  33. package/dist/helpers/identity.d.ts +11 -0
  34. package/dist/helpers/identity.d.ts.map +1 -1
  35. package/dist/helpers/identity.js +13 -2
  36. package/dist/helpers/identity.js.map +1 -1
  37. package/dist/index.d.ts +4 -4
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +6 -6
  40. package/dist/index.js.map +1 -1
  41. package/dist/package.js +6 -0
  42. package/dist/package.js.map +1 -0
  43. package/dist/registry/json-schema.js +26 -8
  44. package/dist/registry/json-schema.js.map +1 -1
  45. package/dist/transport/types.d.ts +9 -0
  46. package/package.json +13 -12
  47. package/src/client/adapt-result.ts +302 -0
  48. package/src/client/client-handlers.ts +215 -0
  49. package/src/client/client.ts +725 -0
  50. package/src/client/defer-loading.ts +108 -0
  51. package/src/client/inbound-filters.ts +246 -0
  52. package/src/client/index.ts +42 -0
  53. package/src/client/managed.ts +222 -0
  54. package/src/client/mcp-resource-reader.ts +183 -0
  55. package/src/client/pinning.ts +48 -0
  56. package/src/client/to-tools-run.ts +178 -0
  57. package/src/client/to-tools.ts +294 -0
  58. package/src/client/transport-factory.ts +117 -0
  59. package/src/client/types.ts +422 -0
  60. package/src/errors/index.ts +170 -0
  61. package/src/helpers/identity.ts +128 -0
  62. package/src/helpers/index.ts +8 -0
  63. package/src/helpers/validate-config.ts +95 -0
  64. package/src/index.ts +49 -0
  65. package/src/oauth/bridge.ts +143 -0
  66. package/src/oauth/index.ts +18 -0
  67. package/src/oauth/library.ts +61 -0
  68. package/src/registry/json-schema.ts +402 -0
  69. package/src/transport/index.ts +15 -0
  70. package/src/transport/types.ts +108 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/errors/index.ts"],"sourcesContent":["/**\n * Typed error union for the `@graphorin/mcp` package.\n *\n * Every error carries a stable lowercase {@link MCPErrorKind}\n * discriminator, an actionable {@link MCPError.hint} field where\n * applicable, and an optional structured `metadata` bag the audit\n * emitter persists alongside the standard `runId` / `sessionId`\n * context.\n *\n * @packageDocumentation\n */\n\n/**\n * Discriminator union for every error class produced by\n * `@graphorin/mcp`. New kinds extend this union; never throw plain\n * `Error` from framework code.\n *\n * @stable\n */\nexport type MCPErrorKind =\n | 'connection-failed'\n | 'protocol-error'\n | 'auth-error'\n | 'tool-not-found'\n | 'tool-execution'\n | 'pin-mismatch'\n | 'call-timeout'\n | 'cancelled'\n | 'invalid-config'\n | 'session-lost'\n | 'transport-not-supported'\n | 'transport-resumable-not-supported';\n\n/** Common metadata bag attached to every {@link MCPError}. */\nexport interface MCPErrorMetadata {\n readonly server?: string;\n readonly tool?: string;\n readonly transport?: 'stdio' | 'streamable-http' | 'sse';\n readonly cause?: unknown;\n readonly httpStatus?: number;\n readonly sessionId?: string;\n readonly lastEventId?: string;\n}\n\n/**\n * Base class for every typed error produced by `@graphorin/mcp`.\n *\n * @stable\n */\nexport abstract class GraphorinMCPError extends Error {\n /** Lowercase discriminator. */\n public abstract readonly kind: MCPErrorKind;\n /** Optional remediation hint surfaced in CLI output. */\n public readonly hint?: string;\n /** Sanitized metadata; never carries secret material. */\n public readonly metadata: Readonly<MCPErrorMetadata>;\n /** Underlying cause (chained errors). */\n public override readonly cause?: unknown;\n\n public constructor(\n message: string,\n opts: {\n readonly hint?: string;\n readonly metadata?: MCPErrorMetadata;\n readonly cause?: unknown;\n } = {},\n ) {\n super(message);\n this.name = new.target.name;\n if (opts.hint !== undefined) this.hint = opts.hint;\n this.metadata = Object.freeze({ ...(opts.metadata ?? {}) });\n if (opts.cause !== undefined) this.cause = opts.cause;\n }\n}\n\n/** Raised when a transport fails to connect or is dropped unexpectedly. */\nexport class MCPConnectionError extends GraphorinMCPError {\n public readonly kind = 'connection-failed' as const;\n}\n\n/** Raised on JSON-RPC / MCP protocol-level errors. */\nexport class MCPProtocolError extends GraphorinMCPError {\n public readonly kind = 'protocol-error' as const;\n}\n\n/** Raised when an authentication / authorization step fails. */\nexport class MCPAuthError extends GraphorinMCPError {\n public readonly kind = 'auth-error' as const;\n}\n\n/** Raised when {@link MCPClient.callTool} is invoked for an unknown tool. */\nexport class MCPToolNotFoundError extends GraphorinMCPError {\n public readonly kind = 'tool-not-found' as const;\n}\n\n/**\n * Raised when a pinned tool-definition fingerprint does not match the\n * server's current definition and `onPinMismatch: 'reject'` is set\n * (MC-6) - the approve-then-swap rug-pull posture.\n */\nexport class MCPToolPinningError extends GraphorinMCPError {\n public readonly kind = 'pin-mismatch' as const;\n}\n\n/**\n * Raised when the MCP server reports a tool-level failure\n * (`CallToolResult.isError === true`, MC-4). The server's content text\n * rides in the message so the model keeps its self-correction signal -\n * while the executor records a real tool FAILURE (audit, retry and\n * error policies all engage) instead of a fake success.\n */\nexport class MCPToolExecutionError extends GraphorinMCPError {\n public readonly kind = 'tool-execution' as const;\n}\n\n/** Raised when a tool call exceeds its configured timeout / aborts. */\nexport class MCPCallTimeoutError extends GraphorinMCPError {\n public readonly kind: 'call-timeout' | 'session-lost' = 'call-timeout';\n\n public constructor(\n message: string,\n opts: {\n readonly hint?: string;\n readonly metadata?: MCPErrorMetadata;\n readonly cause?: unknown;\n readonly variant?: 'call-timeout' | 'session-lost';\n },\n ) {\n super(message, opts);\n if (opts.variant !== undefined) {\n this.kind = opts.variant;\n }\n }\n}\n\n/** Raised when an in-flight call is cancelled by an `AbortSignal`. */\nexport class MCPCancelledError extends GraphorinMCPError {\n public readonly kind = 'cancelled' as const;\n}\n\n/** Raised on invalid `createMCPClient(...)` configuration. */\nexport class MCPInvalidConfigError extends GraphorinMCPError {\n public readonly kind = 'invalid-config' as const;\n}\n\n/**\n * Raised when an operator requests a transport / capability that the\n * runtime does not support (e.g. `resumable: true` on `stdio`).\n *\n * @stable\n */\nexport class MCPTransportNotSupportedError extends GraphorinMCPError {\n public readonly kind: 'transport-not-supported' | 'transport-resumable-not-supported' =\n 'transport-not-supported';\n\n public constructor(\n message: string,\n opts: {\n readonly hint?: string;\n readonly metadata?: MCPErrorMetadata;\n readonly cause?: unknown;\n readonly variant?: 'transport-not-supported' | 'transport-resumable-not-supported';\n },\n ) {\n super(message, opts);\n if (opts.variant !== undefined) {\n this.kind = opts.variant;\n }\n }\n}\n"],"mappings":";;;;;;AAiDA,IAAsB,oBAAtB,cAAgD,MAAM;;CAIpD,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAyB;CAEzB,AAAO,YACL,SACA,OAII,EAAE,EACN;AACA,QAAM,QAAQ;AACd,OAAK,OAAO,IAAI,OAAO;AACvB,MAAI,KAAK,SAAS,OAAW,MAAK,OAAO,KAAK;AAC9C,OAAK,WAAW,OAAO,OAAO,EAAE,GAAI,KAAK,YAAY,EAAE,EAAG,CAAC;AAC3D,MAAI,KAAK,UAAU,OAAW,MAAK,QAAQ,KAAK;;;;AAKpD,IAAa,qBAAb,cAAwC,kBAAkB;CACxD,AAAgB,OAAO;;;AAIzB,IAAa,mBAAb,cAAsC,kBAAkB;CACtD,AAAgB,OAAO;;;AAIzB,IAAa,eAAb,cAAkC,kBAAkB;CAClD,AAAgB,OAAO;;;AAIzB,IAAa,uBAAb,cAA0C,kBAAkB;CAC1D,AAAgB,OAAO;;;;;;;AAQzB,IAAa,sBAAb,cAAyC,kBAAkB;CACzD,AAAgB,OAAO;;;;;;;;;AAUzB,IAAa,wBAAb,cAA2C,kBAAkB;CAC3D,AAAgB,OAAO;;;AAIzB,IAAa,sBAAb,cAAyC,kBAAkB;CACzD,AAAgB,OAAwC;CAExD,AAAO,YACL,SACA,MAMA;AACA,QAAM,SAAS,KAAK;AACpB,MAAI,KAAK,YAAY,OACnB,MAAK,OAAO,KAAK;;;;AAMvB,IAAa,oBAAb,cAAuC,kBAAkB;CACvD,AAAgB,OAAO;;;AAIzB,IAAa,wBAAb,cAA2C,kBAAkB;CAC3D,AAAgB,OAAO;;;;;;;;AASzB,IAAa,gCAAb,cAAmD,kBAAkB;CACnE,AAAgB,OACd;CAEF,AAAO,YACL,SACA,MAMA;AACA,QAAM,SAAS,KAAK;AACpB,MAAI,KAAK,YAAY,OACnB,MAAK,OAAO,KAAK"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/errors/index.ts"],"sourcesContent":["/**\n * Typed error union for the `@graphorin/mcp` package.\n *\n * Every error carries a stable lowercase {@link MCPErrorKind}\n * discriminator, an actionable {@link GraphorinMCPError.hint} field where\n * applicable, and an optional structured `metadata` bag the audit\n * emitter persists alongside the standard `runId` / `sessionId`\n * context.\n *\n * @packageDocumentation\n */\n\n/**\n * Discriminator union for every error class produced by\n * `@graphorin/mcp`. New kinds extend this union; never throw plain\n * `Error` from framework code.\n *\n * @stable\n */\nexport type MCPErrorKind =\n | 'connection-failed'\n | 'protocol-error'\n | 'auth-error'\n | 'tool-not-found'\n | 'tool-execution'\n | 'pin-mismatch'\n | 'call-timeout'\n | 'cancelled'\n | 'invalid-config'\n | 'session-lost'\n | 'transport-not-supported'\n | 'transport-resumable-not-supported';\n\n/** Common metadata bag attached to every {@link GraphorinMCPError}. */\nexport interface MCPErrorMetadata {\n readonly server?: string;\n readonly tool?: string;\n readonly transport?: 'stdio' | 'streamable-http' | 'sse';\n readonly cause?: unknown;\n readonly httpStatus?: number;\n readonly sessionId?: string;\n readonly lastEventId?: string;\n}\n\n/**\n * Base class for every typed error produced by `@graphorin/mcp`.\n *\n * @stable\n */\nexport abstract class GraphorinMCPError extends Error {\n /** Lowercase discriminator. */\n public abstract readonly kind: MCPErrorKind;\n /** Optional remediation hint surfaced in CLI output. */\n public readonly hint?: string;\n /** Sanitized metadata; never carries secret material. */\n public readonly metadata: Readonly<MCPErrorMetadata>;\n /** Underlying cause (chained errors). */\n public override readonly cause?: unknown;\n\n public constructor(\n message: string,\n opts: {\n readonly hint?: string;\n readonly metadata?: MCPErrorMetadata;\n readonly cause?: unknown;\n } = {},\n ) {\n super(message);\n this.name = new.target.name;\n if (opts.hint !== undefined) this.hint = opts.hint;\n this.metadata = Object.freeze({ ...(opts.metadata ?? {}) });\n if (opts.cause !== undefined) this.cause = opts.cause;\n }\n}\n\n/** Raised when a transport fails to connect or is dropped unexpectedly. */\nexport class MCPConnectionError extends GraphorinMCPError {\n public readonly kind = 'connection-failed' as const;\n}\n\n/** Raised on JSON-RPC / MCP protocol-level errors. */\nexport class MCPProtocolError extends GraphorinMCPError {\n public readonly kind = 'protocol-error' as const;\n}\n\n/** Raised when an authentication / authorization step fails. */\nexport class MCPAuthError extends GraphorinMCPError {\n public readonly kind = 'auth-error' as const;\n}\n\n/** Raised when `MCPClient.callTool` is invoked for an unknown tool. */\nexport class MCPToolNotFoundError extends GraphorinMCPError {\n public readonly kind = 'tool-not-found' as const;\n}\n\n/**\n * Raised when a pinned tool-definition fingerprint does not match the\n * server's current definition and `onPinMismatch: 'reject'` is set\n * (MC-6) - the approve-then-swap rug-pull posture.\n */\nexport class MCPToolPinningError extends GraphorinMCPError {\n public readonly kind = 'pin-mismatch' as const;\n}\n\n/**\n * Raised when the MCP server reports a tool-level failure\n * (`CallToolResult.isError === true`, MC-4). The server's content text\n * rides in the message so the model keeps its self-correction signal -\n * while the executor records a real tool FAILURE (audit, retry and\n * error policies all engage) instead of a fake success.\n */\nexport class MCPToolExecutionError extends GraphorinMCPError {\n public readonly kind = 'tool-execution' as const;\n}\n\n/** Raised when a tool call exceeds its configured timeout / aborts. */\nexport class MCPCallTimeoutError extends GraphorinMCPError {\n public readonly kind: 'call-timeout' | 'session-lost' = 'call-timeout';\n\n public constructor(\n message: string,\n opts: {\n readonly hint?: string;\n readonly metadata?: MCPErrorMetadata;\n readonly cause?: unknown;\n readonly variant?: 'call-timeout' | 'session-lost';\n },\n ) {\n super(message, opts);\n if (opts.variant !== undefined) {\n this.kind = opts.variant;\n }\n }\n}\n\n/** Raised when an in-flight call is cancelled by an `AbortSignal`. */\nexport class MCPCancelledError extends GraphorinMCPError {\n public readonly kind = 'cancelled' as const;\n}\n\n/** Raised on invalid `createMCPClient(...)` configuration. */\nexport class MCPInvalidConfigError extends GraphorinMCPError {\n public readonly kind = 'invalid-config' as const;\n}\n\n/**\n * Raised when an operator requests a transport / capability that the\n * runtime does not support (e.g. `resumable: true` on `stdio`).\n *\n * @stable\n */\nexport class MCPTransportNotSupportedError extends GraphorinMCPError {\n public readonly kind: 'transport-not-supported' | 'transport-resumable-not-supported' =\n 'transport-not-supported';\n\n public constructor(\n message: string,\n opts: {\n readonly hint?: string;\n readonly metadata?: MCPErrorMetadata;\n readonly cause?: unknown;\n readonly variant?: 'transport-not-supported' | 'transport-resumable-not-supported';\n },\n ) {\n super(message, opts);\n if (opts.variant !== undefined) {\n this.kind = opts.variant;\n }\n }\n}\n"],"mappings":";;;;;;AAiDA,IAAsB,oBAAtB,cAAgD,MAAM;;CAIpD,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAyB;CAEzB,AAAO,YACL,SACA,OAII,EAAE,EACN;AACA,QAAM,QAAQ;AACd,OAAK,OAAO,IAAI,OAAO;AACvB,MAAI,KAAK,SAAS,OAAW,MAAK,OAAO,KAAK;AAC9C,OAAK,WAAW,OAAO,OAAO,EAAE,GAAI,KAAK,YAAY,EAAE,EAAG,CAAC;AAC3D,MAAI,KAAK,UAAU,OAAW,MAAK,QAAQ,KAAK;;;;AAKpD,IAAa,qBAAb,cAAwC,kBAAkB;CACxD,AAAgB,OAAO;;;AAIzB,IAAa,mBAAb,cAAsC,kBAAkB;CACtD,AAAgB,OAAO;;;AAIzB,IAAa,eAAb,cAAkC,kBAAkB;CAClD,AAAgB,OAAO;;;AAIzB,IAAa,uBAAb,cAA0C,kBAAkB;CAC1D,AAAgB,OAAO;;;;;;;AAQzB,IAAa,sBAAb,cAAyC,kBAAkB;CACzD,AAAgB,OAAO;;;;;;;;;AAUzB,IAAa,wBAAb,cAA2C,kBAAkB;CAC3D,AAAgB,OAAO;;;AAIzB,IAAa,sBAAb,cAAyC,kBAAkB;CACzD,AAAgB,OAAwC;CAExD,AAAO,YACL,SACA,MAMA;AACA,QAAM,SAAS,KAAK;AACpB,MAAI,KAAK,YAAY,OACnB,MAAK,OAAO,KAAK;;;;AAMvB,IAAa,oBAAb,cAAuC,kBAAkB;CACvD,AAAgB,OAAO;;;AAIzB,IAAa,wBAAb,cAA2C,kBAAkB;CAC3D,AAAgB,OAAO;;;;;;;;AASzB,IAAa,gCAAb,cAAmD,kBAAkB;CACnE,AAAgB,OACd;CAEF,AAAO,YACL,SACA,MAMA;AACA,QAAM,SAAS,KAAK;AACpB,MAAI,KAAK,YAAY,OACnB,MAAK,OAAO,KAAK"}
@@ -7,6 +7,17 @@ import { MCPTransportConfig, ServerIdentity } from "../transport/types.js";
7
7
  * transport. The id is suitable for use as a registry key and as the
8
8
  * operator-facing label in audit rows + trace attributes.
9
9
  *
10
+ * W-016: the id derives ONLY from operator-controlled data (the
11
+ * transport config) plus the optional operator-supplied
12
+ * `serverInfoName` override. The name a server self-reports on
13
+ * `initialize` never participates: every security-relevant surface
14
+ * keys off this id (TOFU pins, `mcp:<id>:<uri>` handle scoping, taint
15
+ * labels, audit rows), and a server-controlled id let a rug-pull
16
+ * server mint a fresh TOFU record by renaming itself, or impersonate a
17
+ * trusted server's scope by claiming its name. HTTP-family ids include
18
+ * a non-default port, so localhost:3001 and localhost:3002 are
19
+ * distinct servers.
20
+ *
10
21
  * @stable
11
22
  */
12
23
  declare function deriveServerIdentity(transport: MCPTransportConfig, serverInfoName?: string): ServerIdentity;
@@ -1 +1 @@
1
- {"version":3,"file":"identity.d.ts","names":[],"sources":["../../src/helpers/identity.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;iBAyBgB,oBAAA,YACH,8CAEV;;;;;;;iBA0Ea,mBAAA,YAA+B"}
1
+ {"version":3,"file":"identity.d.ts","names":[],"sources":["../../src/helpers/identity.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;iBAoCgB,oBAAA,YACH,8CAEV;;;;;;;iBA6Ea,mBAAA,YAA+B"}
@@ -13,6 +13,17 @@ import { createHash } from "node:crypto";
13
13
  * transport. The id is suitable for use as a registry key and as the
14
14
  * operator-facing label in audit rows + trace attributes.
15
15
  *
16
+ * W-016: the id derives ONLY from operator-controlled data (the
17
+ * transport config) plus the optional operator-supplied
18
+ * `serverInfoName` override. The name a server self-reports on
19
+ * `initialize` never participates: every security-relevant surface
20
+ * keys off this id (TOFU pins, `mcp:<id>:<uri>` handle scoping, taint
21
+ * labels, audit rows), and a server-controlled id let a rug-pull
22
+ * server mint a fresh TOFU record by renaming itself, or impersonate a
23
+ * trusted server's scope by claiming its name. HTTP-family ids include
24
+ * a non-default port, so localhost:3001 and localhost:3002 are
25
+ * distinct servers.
26
+ *
16
27
  * @stable
17
28
  */
18
29
  function deriveServerIdentity(transport, serverInfoName) {
@@ -38,7 +49,7 @@ function deriveStreamableHttpIdentity(transport, serverInfoName) {
38
49
  const url = new URL(typeof transport.url === "string" ? transport.url : transport.url.toString());
39
50
  const urlHostname = url.hostname;
40
51
  const urlPath = url.pathname.length === 0 ? "/" : url.pathname;
41
- const id = serverInfoName ?? `${urlHostname}${urlPath}`;
52
+ const id = serverInfoName ?? `${url.host}${urlPath}`;
42
53
  return Object.freeze({
43
54
  kind: "mcp-streamable-http",
44
55
  id,
@@ -51,7 +62,7 @@ function deriveSseIdentity(transport, serverInfoName) {
51
62
  const url = new URL(typeof transport.url === "string" ? transport.url : transport.url.toString());
52
63
  const urlHostname = url.hostname;
53
64
  const urlPath = url.pathname.length === 0 ? "/" : url.pathname;
54
- const id = serverInfoName ?? `${urlHostname}${urlPath}`;
65
+ const id = serverInfoName ?? `${url.host}${urlPath}`;
55
66
  return Object.freeze({
56
67
  kind: "mcp-sse",
57
68
  id,
@@ -1 +1 @@
1
- {"version":3,"file":"identity.js","names":[],"sources":["../../src/helpers/identity.ts"],"sourcesContent":["/**\n * Helpers for deriving stable {@link ServerIdentity} records from the\n * supplied {@link MCPTransportConfig}, plus the operator-facing\n * formatter the audit emitter and the trace span attributes use.\n *\n * @packageDocumentation\n */\n\nimport { createHash } from 'node:crypto';\n\nimport type {\n MCPTransportConfig,\n ServerIdentity,\n SseTransportConfig,\n StdioTransportConfig,\n StreamableHttpTransportConfig,\n} from '../transport/types.js';\n\n/**\n * Compute the canonical {@link ServerIdentity} for the supplied\n * transport. The id is suitable for use as a registry key and as the\n * operator-facing label in audit rows + trace attributes.\n *\n * @stable\n */\nexport function deriveServerIdentity(\n transport: MCPTransportConfig,\n serverInfoName?: string,\n): ServerIdentity {\n switch (transport.kind) {\n case 'stdio':\n return deriveStdioIdentity(transport, serverInfoName);\n case 'streamable-http':\n return deriveStreamableHttpIdentity(transport, serverInfoName);\n case 'sse':\n return deriveSseIdentity(transport, serverInfoName);\n }\n}\n\nfunction deriveStdioIdentity(\n transport: StdioTransportConfig,\n serverInfoName?: string,\n): ServerIdentity {\n const argsHash = createHash('sha256')\n .update((transport.args ?? []).join('\\u0000'))\n .digest('hex')\n .slice(0, 16);\n const command = basenameWithoutExt(transport.command);\n const id = serverInfoName ?? `${command}-${argsHash}`;\n return Object.freeze({\n kind: 'mcp-stdio',\n id,\n command,\n argsHash,\n ...(serverInfoName === undefined ? {} : { serverInfoName }),\n });\n}\n\nfunction deriveStreamableHttpIdentity(\n transport: StreamableHttpTransportConfig,\n serverInfoName?: string,\n): ServerIdentity {\n const url = new URL(typeof transport.url === 'string' ? transport.url : transport.url.toString());\n const urlHostname = url.hostname;\n const urlPath = url.pathname.length === 0 ? '/' : url.pathname;\n const id = serverInfoName ?? `${urlHostname}${urlPath}`;\n return Object.freeze({\n kind: 'mcp-streamable-http',\n id,\n urlHostname,\n urlPath,\n ...(serverInfoName === undefined ? {} : { serverInfoName }),\n });\n}\n\nfunction deriveSseIdentity(transport: SseTransportConfig, serverInfoName?: string): ServerIdentity {\n const url = new URL(typeof transport.url === 'string' ? transport.url : transport.url.toString());\n const urlHostname = url.hostname;\n const urlPath = url.pathname.length === 0 ? '/' : url.pathname;\n const id = serverInfoName ?? `${urlHostname}${urlPath}`;\n return Object.freeze({\n kind: 'mcp-sse',\n id,\n urlHostname,\n urlPath,\n ...(serverInfoName === undefined ? {} : { serverInfoName }),\n });\n}\n\nfunction basenameWithoutExt(command: string): string {\n const slashIdx = Math.max(command.lastIndexOf('/'), command.lastIndexOf('\\\\'));\n const base = slashIdx === -1 ? command : command.slice(slashIdx + 1);\n const dotIdx = base.lastIndexOf('.');\n return dotIdx <= 0 ? base : base.slice(0, dotIdx);\n}\n\n/**\n * Operator-facing single-line label for a {@link MCPTransportConfig}.\n * Suitable for trace attributes, audit rows, and CLI output.\n *\n * @stable\n */\nexport function formatMCPServerName(transport: MCPTransportConfig): string {\n switch (transport.kind) {\n case 'stdio':\n return `stdio:${basenameWithoutExt(transport.command)}${\n (transport.args ?? []).length === 0 ? '' : ` ${(transport.args ?? []).join(' ')}`\n }`;\n case 'streamable-http':\n return `streamable-http:${typeof transport.url === 'string' ? transport.url : transport.url.toString()}`;\n case 'sse':\n return `sse:${typeof transport.url === 'string' ? transport.url : transport.url.toString()}`;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAyBA,SAAgB,qBACd,WACA,gBACgB;AAChB,SAAQ,UAAU,MAAlB;EACE,KAAK,QACH,QAAO,oBAAoB,WAAW,eAAe;EACvD,KAAK,kBACH,QAAO,6BAA6B,WAAW,eAAe;EAChE,KAAK,MACH,QAAO,kBAAkB,WAAW,eAAe;;;AAIzD,SAAS,oBACP,WACA,gBACgB;CAChB,MAAM,WAAW,WAAW,SAAS,CAClC,QAAQ,UAAU,QAAQ,EAAE,EAAE,KAAK,KAAS,CAAC,CAC7C,OAAO,MAAM,CACb,MAAM,GAAG,GAAG;CACf,MAAM,UAAU,mBAAmB,UAAU,QAAQ;CACrD,MAAM,KAAK,kBAAkB,GAAG,QAAQ,GAAG;AAC3C,QAAO,OAAO,OAAO;EACnB,MAAM;EACN;EACA;EACA;EACA,GAAI,mBAAmB,SAAY,EAAE,GAAG,EAAE,gBAAgB;EAC3D,CAAC;;AAGJ,SAAS,6BACP,WACA,gBACgB;CAChB,MAAM,MAAM,IAAI,IAAI,OAAO,UAAU,QAAQ,WAAW,UAAU,MAAM,UAAU,IAAI,UAAU,CAAC;CACjG,MAAM,cAAc,IAAI;CACxB,MAAM,UAAU,IAAI,SAAS,WAAW,IAAI,MAAM,IAAI;CACtD,MAAM,KAAK,kBAAkB,GAAG,cAAc;AAC9C,QAAO,OAAO,OAAO;EACnB,MAAM;EACN;EACA;EACA;EACA,GAAI,mBAAmB,SAAY,EAAE,GAAG,EAAE,gBAAgB;EAC3D,CAAC;;AAGJ,SAAS,kBAAkB,WAA+B,gBAAyC;CACjG,MAAM,MAAM,IAAI,IAAI,OAAO,UAAU,QAAQ,WAAW,UAAU,MAAM,UAAU,IAAI,UAAU,CAAC;CACjG,MAAM,cAAc,IAAI;CACxB,MAAM,UAAU,IAAI,SAAS,WAAW,IAAI,MAAM,IAAI;CACtD,MAAM,KAAK,kBAAkB,GAAG,cAAc;AAC9C,QAAO,OAAO,OAAO;EACnB,MAAM;EACN;EACA;EACA;EACA,GAAI,mBAAmB,SAAY,EAAE,GAAG,EAAE,gBAAgB;EAC3D,CAAC;;AAGJ,SAAS,mBAAmB,SAAyB;CACnD,MAAM,WAAW,KAAK,IAAI,QAAQ,YAAY,IAAI,EAAE,QAAQ,YAAY,KAAK,CAAC;CAC9E,MAAM,OAAO,aAAa,KAAK,UAAU,QAAQ,MAAM,WAAW,EAAE;CACpE,MAAM,SAAS,KAAK,YAAY,IAAI;AACpC,QAAO,UAAU,IAAI,OAAO,KAAK,MAAM,GAAG,OAAO;;;;;;;;AASnD,SAAgB,oBAAoB,WAAuC;AACzE,SAAQ,UAAU,MAAlB;EACE,KAAK,QACH,QAAO,SAAS,mBAAmB,UAAU,QAAQ,IAClD,UAAU,QAAQ,EAAE,EAAE,WAAW,IAAI,KAAK,KAAK,UAAU,QAAQ,EAAE,EAAE,KAAK,IAAI;EAEnF,KAAK,kBACH,QAAO,mBAAmB,OAAO,UAAU,QAAQ,WAAW,UAAU,MAAM,UAAU,IAAI,UAAU;EACxG,KAAK,MACH,QAAO,OAAO,OAAO,UAAU,QAAQ,WAAW,UAAU,MAAM,UAAU,IAAI,UAAU"}
1
+ {"version":3,"file":"identity.js","names":[],"sources":["../../src/helpers/identity.ts"],"sourcesContent":["/**\n * Helpers for deriving stable {@link ServerIdentity} records from the\n * supplied {@link MCPTransportConfig}, plus the operator-facing\n * formatter the audit emitter and the trace span attributes use.\n *\n * @packageDocumentation\n */\n\nimport { createHash } from 'node:crypto';\n\nimport type {\n MCPTransportConfig,\n ServerIdentity,\n SseTransportConfig,\n StdioTransportConfig,\n StreamableHttpTransportConfig,\n} from '../transport/types.js';\n\n/**\n * Compute the canonical {@link ServerIdentity} for the supplied\n * transport. The id is suitable for use as a registry key and as the\n * operator-facing label in audit rows + trace attributes.\n *\n * W-016: the id derives ONLY from operator-controlled data (the\n * transport config) plus the optional operator-supplied\n * `serverInfoName` override. The name a server self-reports on\n * `initialize` never participates: every security-relevant surface\n * keys off this id (TOFU pins, `mcp:<id>:<uri>` handle scoping, taint\n * labels, audit rows), and a server-controlled id let a rug-pull\n * server mint a fresh TOFU record by renaming itself, or impersonate a\n * trusted server's scope by claiming its name. HTTP-family ids include\n * a non-default port, so localhost:3001 and localhost:3002 are\n * distinct servers.\n *\n * @stable\n */\nexport function deriveServerIdentity(\n transport: MCPTransportConfig,\n serverInfoName?: string,\n): ServerIdentity {\n switch (transport.kind) {\n case 'stdio':\n return deriveStdioIdentity(transport, serverInfoName);\n case 'streamable-http':\n return deriveStreamableHttpIdentity(transport, serverInfoName);\n case 'sse':\n return deriveSseIdentity(transport, serverInfoName);\n }\n}\n\nfunction deriveStdioIdentity(\n transport: StdioTransportConfig,\n serverInfoName?: string,\n): ServerIdentity {\n const argsHash = createHash('sha256')\n .update((transport.args ?? []).join('\\u0000'))\n .digest('hex')\n .slice(0, 16);\n const command = basenameWithoutExt(transport.command);\n const id = serverInfoName ?? `${command}-${argsHash}`;\n return Object.freeze({\n kind: 'mcp-stdio',\n id,\n command,\n argsHash,\n ...(serverInfoName === undefined ? {} : { serverInfoName }),\n });\n}\n\nfunction deriveStreamableHttpIdentity(\n transport: StreamableHttpTransportConfig,\n serverInfoName?: string,\n): ServerIdentity {\n const url = new URL(typeof transport.url === 'string' ? transport.url : transport.url.toString());\n const urlHostname = url.hostname;\n const urlPath = url.pathname.length === 0 ? '/' : url.pathname;\n // W-016: `url.host` (hostname:port for non-default ports) - two local\n // servers on different ports must not collide into one identity.\n const id = serverInfoName ?? `${url.host}${urlPath}`;\n return Object.freeze({\n kind: 'mcp-streamable-http',\n id,\n urlHostname,\n urlPath,\n ...(serverInfoName === undefined ? {} : { serverInfoName }),\n });\n}\n\nfunction deriveSseIdentity(transport: SseTransportConfig, serverInfoName?: string): ServerIdentity {\n const url = new URL(typeof transport.url === 'string' ? transport.url : transport.url.toString());\n const urlHostname = url.hostname;\n const urlPath = url.pathname.length === 0 ? '/' : url.pathname;\n // W-016: see deriveStreamableHttpIdentity - port-inclusive host.\n const id = serverInfoName ?? `${url.host}${urlPath}`;\n return Object.freeze({\n kind: 'mcp-sse',\n id,\n urlHostname,\n urlPath,\n ...(serverInfoName === undefined ? {} : { serverInfoName }),\n });\n}\n\nfunction basenameWithoutExt(command: string): string {\n const slashIdx = Math.max(command.lastIndexOf('/'), command.lastIndexOf('\\\\'));\n const base = slashIdx === -1 ? command : command.slice(slashIdx + 1);\n const dotIdx = base.lastIndexOf('.');\n return dotIdx <= 0 ? base : base.slice(0, dotIdx);\n}\n\n/**\n * Operator-facing single-line label for a {@link MCPTransportConfig}.\n * Suitable for trace attributes, audit rows, and CLI output.\n *\n * @stable\n */\nexport function formatMCPServerName(transport: MCPTransportConfig): string {\n switch (transport.kind) {\n case 'stdio':\n return `stdio:${basenameWithoutExt(transport.command)}${\n (transport.args ?? []).length === 0 ? '' : ` ${(transport.args ?? []).join(' ')}`\n }`;\n case 'streamable-http':\n return `streamable-http:${typeof transport.url === 'string' ? transport.url : transport.url.toString()}`;\n case 'sse':\n return `sse:${typeof transport.url === 'string' ? transport.url : transport.url.toString()}`;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,SAAgB,qBACd,WACA,gBACgB;AAChB,SAAQ,UAAU,MAAlB;EACE,KAAK,QACH,QAAO,oBAAoB,WAAW,eAAe;EACvD,KAAK,kBACH,QAAO,6BAA6B,WAAW,eAAe;EAChE,KAAK,MACH,QAAO,kBAAkB,WAAW,eAAe;;;AAIzD,SAAS,oBACP,WACA,gBACgB;CAChB,MAAM,WAAW,WAAW,SAAS,CAClC,QAAQ,UAAU,QAAQ,EAAE,EAAE,KAAK,KAAS,CAAC,CAC7C,OAAO,MAAM,CACb,MAAM,GAAG,GAAG;CACf,MAAM,UAAU,mBAAmB,UAAU,QAAQ;CACrD,MAAM,KAAK,kBAAkB,GAAG,QAAQ,GAAG;AAC3C,QAAO,OAAO,OAAO;EACnB,MAAM;EACN;EACA;EACA;EACA,GAAI,mBAAmB,SAAY,EAAE,GAAG,EAAE,gBAAgB;EAC3D,CAAC;;AAGJ,SAAS,6BACP,WACA,gBACgB;CAChB,MAAM,MAAM,IAAI,IAAI,OAAO,UAAU,QAAQ,WAAW,UAAU,MAAM,UAAU,IAAI,UAAU,CAAC;CACjG,MAAM,cAAc,IAAI;CACxB,MAAM,UAAU,IAAI,SAAS,WAAW,IAAI,MAAM,IAAI;CAGtD,MAAM,KAAK,kBAAkB,GAAG,IAAI,OAAO;AAC3C,QAAO,OAAO,OAAO;EACnB,MAAM;EACN;EACA;EACA;EACA,GAAI,mBAAmB,SAAY,EAAE,GAAG,EAAE,gBAAgB;EAC3D,CAAC;;AAGJ,SAAS,kBAAkB,WAA+B,gBAAyC;CACjG,MAAM,MAAM,IAAI,IAAI,OAAO,UAAU,QAAQ,WAAW,UAAU,MAAM,UAAU,IAAI,UAAU,CAAC;CACjG,MAAM,cAAc,IAAI;CACxB,MAAM,UAAU,IAAI,SAAS,WAAW,IAAI,MAAM,IAAI;CAEtD,MAAM,KAAK,kBAAkB,GAAG,IAAI,OAAO;AAC3C,QAAO,OAAO,OAAO;EACnB,MAAM;EACN;EACA;EACA;EACA,GAAI,mBAAmB,SAAY,EAAE,GAAG,EAAE,gBAAgB;EAC3D,CAAC;;AAGJ,SAAS,mBAAmB,SAAyB;CACnD,MAAM,WAAW,KAAK,IAAI,QAAQ,YAAY,IAAI,EAAE,QAAQ,YAAY,KAAK,CAAC;CAC9E,MAAM,OAAO,aAAa,KAAK,UAAU,QAAQ,MAAM,WAAW,EAAE;CACpE,MAAM,SAAS,KAAK,YAAY,IAAI;AACpC,QAAO,UAAU,IAAI,OAAO,KAAK,MAAM,GAAG,OAAO;;;;;;;;AASnD,SAAgB,oBAAoB,WAAuC;AACzE,SAAQ,UAAU,MAAlB;EACE,KAAK,QACH,QAAO,SAAS,mBAAmB,UAAU,QAAQ,IAClD,UAAU,QAAQ,EAAE,EAAE,WAAW,IAAI,KAAK,KAAK,UAAU,QAAQ,EAAE,EAAE,KAAK,IAAI;EAEnF,KAAK,kBACH,QAAO,mBAAmB,OAAO,UAAU,QAAQ,WAAW,UAAU,MAAM,UAAU,IAAI,UAAU;EACxG,KAAK,MACH,QAAO,OAAO,OAAO,UAAU,QAAQ,WAAW,UAAU,MAAM,UAAU,IAAI,UAAU"}
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import { MCPTransportConfig, ServerIdentity, SseTransportConfig, StdioTransportC
2
2
  import { OAuthAuthorizationProvider, OAuthAuthorizationProviderOptions, createOAuthAuthorizationProvider } from "./oauth/bridge.js";
3
3
  import { CreateMCPClientOptions, MCPCallToolResult, MCPClient, MCPContentPart, MCPElicitationHandler, MCPElicitationRequest, MCPElicitationResult, MCPPromptDefinition, MCPPromptMessage, MCPResourceContent, MCPResourceDefinition, MCPSamplingContent, MCPSamplingHandler, MCPSamplingMessage, MCPSamplingRequest, MCPSamplingResult, MCPToToolsOptions, MCPToolDefinition } from "./client/types.js";
4
4
  import { _resetSseWarnDedupForTesting, createMCPClient } from "./client/client.js";
5
+ import { CreateManagedMCPClientOptions, ManagedReconnectOptions, createManagedMCPClient } from "./client/managed.js";
5
6
  import { McpResourceReaderOptions, createMcpResourceReader } from "./client/mcp-resource-reader.js";
6
7
  import { adaptCallResult } from "./client/adapt-result.js";
7
8
  import { DEFAULT_DEFER_LOADING_THRESHOLD } from "./client/defer-loading.js";
@@ -28,7 +29,7 @@ import "./oauth/index.js";
28
29
  * `listPrompts` / `callTool` / `readResource` / `getPrompt` /
29
30
  * `close`) plus the strategy-aware {@link MCPClient.toTools}
30
31
  * adapter that bridges MCP tool descriptors into Graphorin
31
- * {@link Tool} records.
32
+ * `Tool` records.
32
33
  * - The OAuth bridge that resolves bearer headers from the
33
34
  * {@link OAuthAuthorizationProvider} backed by
34
35
  * `@graphorin/security/oauth`.
@@ -53,8 +54,7 @@ import "./oauth/index.js";
53
54
  *
54
55
  * @packageDocumentation
55
56
  */
56
- /** Canonical version constant. Mirrors the `package.json` version. */
57
- declare const VERSION = "0.6.0";
57
+ declare const VERSION: string;
58
58
  //#endregion
59
- export { CreateMCPClientOptions, DEFAULT_DEFER_LOADING_THRESHOLD, GraphorinMCPError, MCPAuthError, MCPCallTimeoutError, MCPCallToolResult, MCPCancelledError, MCPClient, MCPConnectionError, MCPContentPart, MCPElicitationHandler, MCPElicitationRequest, MCPElicitationResult, MCPErrorKind, MCPErrorMetadata, MCPInvalidConfigError, MCPPromptDefinition, MCPPromptMessage, MCPProtocolError, MCPResourceContent, MCPResourceDefinition, MCPSamplingContent, MCPSamplingHandler, MCPSamplingMessage, MCPSamplingRequest, MCPSamplingResult, MCPToToolsOptions, MCPToolDefinition, MCPToolExecutionError, MCPToolNotFoundError, MCPToolPinningError, MCPTransportConfig, MCPTransportNotSupportedError, McpResourceReaderOptions, OAuthAuthorizationProvider, OAuthAuthorizationProviderOptions, ServerIdentity, SseTransportConfig, StdioTransportConfig, StreamableHttpTransportConfig, VERSION, _resetMcpAdapterDedupForTesting, _resetSseWarnDedupForTesting, adaptCallResult, adaptMCPTools, createMCPClient, createMcpResourceReader, createOAuthAuthorizationProvider, deriveServerIdentity, formatMCPServerName, mcpAuthListSessions, mcpAuthLogin, mcpAuthRefresh, mcpAuthRevoke, mcpAuthStatus, validateMCPServerConfig };
59
+ export { CreateMCPClientOptions, CreateManagedMCPClientOptions, DEFAULT_DEFER_LOADING_THRESHOLD, GraphorinMCPError, MCPAuthError, MCPCallTimeoutError, MCPCallToolResult, MCPCancelledError, MCPClient, MCPConnectionError, MCPContentPart, MCPElicitationHandler, MCPElicitationRequest, MCPElicitationResult, MCPErrorKind, MCPErrorMetadata, MCPInvalidConfigError, MCPPromptDefinition, MCPPromptMessage, MCPProtocolError, MCPResourceContent, MCPResourceDefinition, MCPSamplingContent, MCPSamplingHandler, MCPSamplingMessage, MCPSamplingRequest, MCPSamplingResult, MCPToToolsOptions, MCPToolDefinition, MCPToolExecutionError, MCPToolNotFoundError, MCPToolPinningError, MCPTransportConfig, MCPTransportNotSupportedError, ManagedReconnectOptions, McpResourceReaderOptions, OAuthAuthorizationProvider, OAuthAuthorizationProviderOptions, ServerIdentity, SseTransportConfig, StdioTransportConfig, StreamableHttpTransportConfig, VERSION, _resetMcpAdapterDedupForTesting, _resetSseWarnDedupForTesting, adaptCallResult, adaptMCPTools, createMCPClient, createManagedMCPClient, createMcpResourceReader, createOAuthAuthorizationProvider, deriveServerIdentity, formatMCPServerName, mcpAuthListSessions, mcpAuthLogin, mcpAuthRefresh, mcpAuthRevoke, mcpAuthStatus, validateMCPServerConfig };
60
60
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA;;;;;;;;;;;;;;;;;;;;;;;cAAa,OAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA;;;;;;;;;;;;;;;;;;;;;cAAa"}
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { version } from "./package.js";
1
2
  import { GraphorinMCPError, MCPAuthError, MCPCallTimeoutError, MCPCancelledError, MCPConnectionError, MCPInvalidConfigError, MCPProtocolError, MCPToolExecutionError, MCPToolNotFoundError, MCPToolPinningError, MCPTransportNotSupportedError } from "./errors/index.js";
2
3
  import { deriveServerIdentity, formatMCPServerName } from "./helpers/identity.js";
3
4
  import { validateMCPServerConfig } from "./helpers/validate-config.js";
@@ -5,11 +6,10 @@ import { adaptCallResult } from "./client/adapt-result.js";
5
6
  import { DEFAULT_DEFER_LOADING_THRESHOLD } from "./client/defer-loading.js";
6
7
  import { _resetMcpAdapterDedupForTesting, adaptMCPTools } from "./client/to-tools.js";
7
8
  import { _resetSseWarnDedupForTesting, createMCPClient } from "./client/client.js";
9
+ import { createManagedMCPClient } from "./client/managed.js";
8
10
  import { createMcpResourceReader } from "./client/mcp-resource-reader.js";
9
- import "./client/index.js";
10
11
  import { createOAuthAuthorizationProvider } from "./oauth/bridge.js";
11
12
  import { mcpAuthListSessions, mcpAuthLogin, mcpAuthRefresh, mcpAuthRevoke, mcpAuthStatus } from "./oauth/library.js";
12
- import "./oauth/index.js";
13
13
 
14
14
  //#region src/index.ts
15
15
  /**
@@ -25,7 +25,7 @@ import "./oauth/index.js";
25
25
  * `listPrompts` / `callTool` / `readResource` / `getPrompt` /
26
26
  * `close`) plus the strategy-aware {@link MCPClient.toTools}
27
27
  * adapter that bridges MCP tool descriptors into Graphorin
28
- * {@link Tool} records.
28
+ * `Tool` records.
29
29
  * - The OAuth bridge that resolves bearer headers from the
30
30
  * {@link OAuthAuthorizationProvider} backed by
31
31
  * `@graphorin/security/oauth`.
@@ -50,9 +50,9 @@ import "./oauth/index.js";
50
50
  *
51
51
  * @packageDocumentation
52
52
  */
53
- /** Canonical version constant. Mirrors the `package.json` version. */
54
- const VERSION = "0.6.0";
53
+ /** Canonical version constant, derived from `package.json` at build time. */
54
+ const VERSION = version;
55
55
 
56
56
  //#endregion
57
- export { DEFAULT_DEFER_LOADING_THRESHOLD, GraphorinMCPError, MCPAuthError, MCPCallTimeoutError, MCPCancelledError, MCPConnectionError, MCPInvalidConfigError, MCPProtocolError, MCPToolExecutionError, MCPToolNotFoundError, MCPToolPinningError, MCPTransportNotSupportedError, VERSION, _resetMcpAdapterDedupForTesting, _resetSseWarnDedupForTesting, adaptCallResult, adaptMCPTools, createMCPClient, createMcpResourceReader, createOAuthAuthorizationProvider, deriveServerIdentity, formatMCPServerName, mcpAuthListSessions, mcpAuthLogin, mcpAuthRefresh, mcpAuthRevoke, mcpAuthStatus, validateMCPServerConfig };
57
+ export { DEFAULT_DEFER_LOADING_THRESHOLD, GraphorinMCPError, MCPAuthError, MCPCallTimeoutError, MCPCancelledError, MCPConnectionError, MCPInvalidConfigError, MCPProtocolError, MCPToolExecutionError, MCPToolNotFoundError, MCPToolPinningError, MCPTransportNotSupportedError, VERSION, _resetMcpAdapterDedupForTesting, _resetSseWarnDedupForTesting, adaptCallResult, adaptMCPTools, createMCPClient, createManagedMCPClient, createMcpResourceReader, createOAuthAuthorizationProvider, deriveServerIdentity, formatMCPServerName, mcpAuthListSessions, mcpAuthLogin, mcpAuthRefresh, mcpAuthRevoke, mcpAuthStatus, validateMCPServerConfig };
58
58
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * `@graphorin/mcp` - Model Context Protocol client for the Graphorin\n * framework.\n *\n * The package owns:\n *\n * - The {@link createMCPClient} factory that opens a typed MCP\n * connection over stdio, Streamable HTTP, or the deprecated SSE\n * transport.\n * - The {@link MCPClient} surface (`listTools` / `listResources` /\n * `listPrompts` / `callTool` / `readResource` / `getPrompt` /\n * `close`) plus the strategy-aware {@link MCPClient.toTools}\n * adapter that bridges MCP tool descriptors into Graphorin\n * {@link Tool} records.\n * - The OAuth bridge that resolves bearer headers from the\n * {@link OAuthAuthorizationProvider} backed by\n * `@graphorin/security/oauth`.\n * - Library helpers (`mcpAuthLogin`, `mcpAuthListSessions`,\n * `mcpAuthRefresh`, `mcpAuthRevoke`, `mcpAuthStatus`) consumed by\n * the upcoming `graphorin auth` CLI surface.\n * - Typed errors ({@link MCPConnectionError},\n * {@link MCPProtocolError}, {@link MCPAuthError},\n * {@link MCPToolNotFoundError}, {@link MCPCallTimeoutError},\n * {@link MCPCancelledError}, {@link MCPInvalidConfigError},\n * {@link MCPTransportNotSupportedError}, {@link GraphorinMCPError}).\n *\n * Stable sub-paths:\n *\n * ```ts\n * import { createMCPClient } from '@graphorin/mcp/client';\n * import { createOAuthAuthorizationProvider } from '@graphorin/mcp/oauth';\n * import { formatMCPServerName, validateMCPServerConfig } from '@graphorin/mcp/helpers';\n * import { MCPConnectionError } from '@graphorin/mcp/errors';\n * import type { MCPTransportConfig, ServerIdentity } from '@graphorin/mcp/transport';\n * ```\n *\n * @packageDocumentation\n */\n\n/** Canonical version constant. Mirrors the `package.json` version. */\nexport const VERSION = '0.6.0';\n\nexport * from './client/index.js';\nexport * from './errors/index.js';\nexport * from './helpers/index.js';\nexport * from './oauth/index.js';\nexport * from './transport/index.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,MAAa,UAAU"}
1
+ {"version":3,"file":"index.js","names":["VERSION: string","pkg.version"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * `@graphorin/mcp` - Model Context Protocol client for the Graphorin\n * framework.\n *\n * The package owns:\n *\n * - The {@link createMCPClient} factory that opens a typed MCP\n * connection over stdio, Streamable HTTP, or the deprecated SSE\n * transport.\n * - The {@link MCPClient} surface (`listTools` / `listResources` /\n * `listPrompts` / `callTool` / `readResource` / `getPrompt` /\n * `close`) plus the strategy-aware {@link MCPClient.toTools}\n * adapter that bridges MCP tool descriptors into Graphorin\n * `Tool` records.\n * - The OAuth bridge that resolves bearer headers from the\n * {@link OAuthAuthorizationProvider} backed by\n * `@graphorin/security/oauth`.\n * - Library helpers (`mcpAuthLogin`, `mcpAuthListSessions`,\n * `mcpAuthRefresh`, `mcpAuthRevoke`, `mcpAuthStatus`) consumed by\n * the upcoming `graphorin auth` CLI surface.\n * - Typed errors ({@link MCPConnectionError},\n * {@link MCPProtocolError}, {@link MCPAuthError},\n * {@link MCPToolNotFoundError}, {@link MCPCallTimeoutError},\n * {@link MCPCancelledError}, {@link MCPInvalidConfigError},\n * {@link MCPTransportNotSupportedError}, {@link GraphorinMCPError}).\n *\n * Stable sub-paths:\n *\n * ```ts\n * import { createMCPClient } from '@graphorin/mcp/client';\n * import { createOAuthAuthorizationProvider } from '@graphorin/mcp/oauth';\n * import { formatMCPServerName, validateMCPServerConfig } from '@graphorin/mcp/helpers';\n * import { MCPConnectionError } from '@graphorin/mcp/errors';\n * import type { MCPTransportConfig, ServerIdentity } from '@graphorin/mcp/transport';\n * ```\n *\n * @packageDocumentation\n */\n\n/** Canonical version constant, derived from `package.json` at build time. */\nimport pkg from '../package.json' with { type: 'json' };\n\nexport const VERSION: string = pkg.version;\n\nexport * from './client/index.js';\nexport * from './errors/index.js';\nexport * from './helpers/index.js';\nexport * from './oauth/index.js';\nexport * from './transport/index.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,MAAaA,UAAkBC"}
@@ -0,0 +1,6 @@
1
+ //#region package.json
2
+ var version = "0.7.0";
3
+
4
+ //#endregion
5
+ export { version };
6
+ //# sourceMappingURL=package.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package.js","names":[],"sources":["../package.json"],"sourcesContent":["{\n \"name\": \"@graphorin/mcp\",\n \"version\": \"0.7.0\",\n \"description\": \"Model Context Protocol client for the Graphorin framework: stdio + Streamable HTTP + SSE transports, typed `MCPClient` (`listTools` / `listResources` / `listPrompts` / `callTool`), `toTools()` adapter (per-server inbound prompt-injection sanitization, deferred-loading auto-default at the 10-tool threshold, structured-content + outputSchema round-trip with backward-compatible TextContent mirror, per-server result envelope overrides, per-server call timeout, mcp provenance stamping for the dataflow policy, per-server preferredModel and side-effect class overrides), OAuth integration backed by @graphorin/security/oauth, typed errors, and library helpers consumed by the graphorin auth CLI.\",\n \"license\": \"MIT\",\n \"author\": \"Oleksiy Stepurenko\",\n \"homepage\": \"https://github.com/o-stepper/graphorin/tree/main/packages/mcp\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/o-stepper/graphorin.git\",\n \"directory\": \"packages/mcp\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/o-stepper/graphorin/issues\"\n },\n \"keywords\": [\n \"graphorin\",\n \"ai\",\n \"agents\",\n \"framework\",\n \"mcp\",\n \"model-context-protocol\",\n \"mcp-client\",\n \"stdio\",\n \"streamable-http\",\n \"sse\",\n \"oauth\",\n \"structured-content\",\n \"resumable-sessions\",\n \"tool-collision\",\n \"deferred-loading\",\n \"inbound-sanitization\"\n ],\n \"type\": \"module\",\n \"sideEffects\": false,\n \"engines\": {\n \"node\": \">=22.12.0\"\n },\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"default\": \"./dist/index.js\"\n },\n \"./client\": {\n \"types\": \"./dist/client/index.d.ts\",\n \"default\": \"./dist/client/index.js\"\n },\n \"./transport\": {\n \"types\": \"./dist/transport/index.d.ts\",\n \"default\": \"./dist/transport/index.js\"\n },\n \"./oauth\": {\n \"types\": \"./dist/oauth/index.d.ts\",\n \"default\": \"./dist/oauth/index.js\"\n },\n \"./helpers\": {\n \"types\": \"./dist/helpers/index.d.ts\",\n \"default\": \"./dist/helpers/index.js\"\n },\n \"./errors\": {\n \"types\": \"./dist/errors/index.d.ts\",\n \"default\": \"./dist/errors/index.js\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"files\": [\n \"dist\",\n \"src\",\n \"README.md\",\n \"CHANGELOG.md\",\n \"LICENSE\"\n ],\n \"scripts\": {\n \"build\": \"tsdown\",\n \"typecheck\": \"tsc --noEmit && tsc -p tsconfig.tests.json\",\n \"test\": \"vitest run\",\n \"lint\": \"biome check .\",\n \"clean\": \"rimraf dist .turbo *.tsbuildinfo\"\n },\n \"dependencies\": {\n \"@graphorin/core\": \"workspace:*\",\n \"@graphorin/security\": \"workspace:*\",\n \"@graphorin/tools\": \"workspace:*\",\n \"@modelcontextprotocol/sdk\": \"^1.29.0\"\n },\n \"peerDependencies\": {\n \"zod\": \"^3.23.0 || ^4.0.0\"\n },\n \"peerDependenciesMeta\": {\n \"zod\": {\n \"optional\": false\n }\n },\n \"publishConfig\": {\n \"access\": \"public\",\n \"provenance\": true\n },\n \"devDependencies\": {\n \"fast-check\": \"^3.23.0\",\n \"hono\": \"^4.12.21\",\n \"zod\": \"^3.25.0\"\n }\n}\n"],"mappings":";cAEa"}
@@ -153,7 +153,8 @@ function validateString(value, schema, path) {
153
153
  message: `expected at most ${schema.maxLength} characters`
154
154
  });
155
155
  if (typeof schema.pattern === "string") {
156
- if (schema.pattern.length <= MAX_PATTERN_LENGTH && value.length <= MAX_PATTERN_TEST_LENGTH && !looksCatastrophic(schema.pattern)) try {
156
+ const maxTestLength = QUANTIFIED_GROUP_RE.test(schema.pattern) ? MAX_QUANTIFIED_GROUP_TEST_LENGTH : MAX_PATTERN_TEST_LENGTH;
157
+ if (schema.pattern.length <= MAX_PATTERN_LENGTH && value.length <= maxTestLength && !looksCatastrophic(schema.pattern)) try {
157
158
  if (!new RegExp(schema.pattern).test(value)) issues.push({
158
159
  path,
159
160
  message: `did not match pattern ${schema.pattern}`
@@ -165,16 +166,33 @@ function validateString(value, schema, path) {
165
166
  /** mcp-skills-07: hard caps on server-supplied `pattern` evaluation. */
166
167
  const MAX_PATTERN_LENGTH = 1e3;
167
168
  const MAX_PATTERN_TEST_LENGTH = 1e4;
169
+ /** W-078: reduced cap applied whenever the pattern has a quantified group. */
170
+ const MAX_QUANTIFIED_GROUP_TEST_LENGTH = 1e3;
171
+ /** A group that is itself quantified: `(...)+`, `(...)*`, `(...){2,}`. */
172
+ const QUANTIFIED_GROUP_RE = /\)[*+]|\)\{\d+,(?:\d+)?\}/;
173
+ /** A group whose inner expression ends with a quantifier: `...+)`. */
174
+ const GROUP_BODY_ENDS_QUANTIFIED_RE = /[*+}]\s*\)/;
168
175
  /**
169
- * Cheap heuristic for the classic catastrophic-backtracking shape: a
170
- * group whose inner expression ends with a quantifier and which is
171
- * itself quantified (`(a+)+`, `(a*)*`, `(a+){2,}`, `(?:x+)*`). A
172
- * linear-time engine (re2) would make this exact; the heuristic errs
173
- * on the safe side for untrusted input, and a rejected pattern simply
174
- * degrades to permissive.
176
+ * Cheap heuristic for exponential-backtracking shapes in a quantified
177
+ * group (mcp-skills-07 / W-078). A pattern is rejected when a
178
+ * quantified group is present AND either:
179
+ *
180
+ * - the group body ends with a quantifier - the classic nested
181
+ * quantifier family (`(a+)+`, `(a*)*`, `(a+){2,}`, `(?:x+)*`); or
182
+ * - the pattern contains an alternation - the alternation-overlap
183
+ * family (`(a|a)+`, `^(\w|\d)*$`), where overlapping branches make
184
+ * the quantified group ambiguous.
185
+ *
186
+ * Deliberately conservative: false positives (a harmless alternation
187
+ * inside a quantified group) merely degrade that pattern to permissive
188
+ * validation, which is the already-documented semantics for guarded
189
+ * and malformed patterns. A linear-time engine (re2) remains the exact
190
+ * solution; this heuristic plus the reduced test-string cap above
191
+ * bound the damage of an untrusted server-supplied pattern.
175
192
  */
176
193
  function looksCatastrophic(pattern) {
177
- return /\)[*+]|\)\{\d+,(?:\d+)?\}/.test(pattern) && /[*+}]\s*\)/.test(pattern);
194
+ if (!QUANTIFIED_GROUP_RE.test(pattern)) return false;
195
+ return GROUP_BODY_ENDS_QUANTIFIED_RE.test(pattern) || pattern.includes("|");
178
196
  }
179
197
  function validateNumber(value, schema, path) {
180
198
  if (schema === true || schema === false) return [];
@@ -1 +1 @@
1
- {"version":3,"file":"json-schema.js","names":["issues: Issue[]","types: ReadonlyArray<string>"],"sources":["../../src/registry/json-schema.ts"],"sourcesContent":["/**\n * Lightweight JSON-Schema -> {@link ZodLikeSchema} adapter.\n *\n * The Model Context Protocol carries tool input + output schemas as\n * JSON Schema documents; the Graphorin tool registry types its\n * schemas via the `ZodLikeSchema` structural contract from\n * `@graphorin/core`. This module bridges the two without pulling\n * `zod` into the MCP boundary or relying on code generation +\n * runtime `eval` (the popular `json-schema-to-zod` package generates\n * source code that needs `new Function(...)` to execute).\n *\n * The adapter validates the canonical subset of JSON Schema the MCP\n * spec uses: `object` (with `properties`, `required`,\n * `additionalProperties`), `array` (with `items`, `minItems`,\n * `maxItems`), `string` (with `enum`, `minLength`, `maxLength`,\n * `pattern`), `number` / `integer` (with `enum`, `minimum`,\n * `maximum`), `boolean`, `null`, and the primitive composition\n * keywords `enum`, `const`, `oneOf`, `anyOf`, `allOf`. Unknown keys\n * are accepted permissively so newer MCP server schemas that ship\n * additional vocabulary do not break the adapter.\n *\n * @packageDocumentation\n */\n\nimport type { ZodLikeError, ZodLikeSafeParseResult, ZodLikeSchema } from '@graphorin/core';\n\n/** JSON Schema document subset accepted by {@link buildJsonSchemaValidator}. */\nexport type JsonSchemaLike =\n | boolean\n | (Readonly<Record<string, unknown>> & {\n readonly type?: string | ReadonlyArray<string>;\n readonly properties?: Readonly<Record<string, JsonSchemaLike>>;\n readonly required?: ReadonlyArray<string>;\n readonly additionalProperties?: boolean | JsonSchemaLike;\n readonly items?: JsonSchemaLike | ReadonlyArray<JsonSchemaLike>;\n readonly minItems?: number;\n readonly maxItems?: number;\n readonly minimum?: number;\n readonly maximum?: number;\n readonly minLength?: number;\n readonly maxLength?: number;\n readonly pattern?: string;\n readonly enum?: ReadonlyArray<unknown>;\n readonly const?: unknown;\n readonly oneOf?: ReadonlyArray<JsonSchemaLike>;\n readonly anyOf?: ReadonlyArray<JsonSchemaLike>;\n readonly allOf?: ReadonlyArray<JsonSchemaLike>;\n });\n\n/**\n * Build a {@link ZodLikeSchema} that validates `data` against\n * `schema`. The returned instance follows the structural Zod\n * contract from `@graphorin/core` (a `parse` method that throws + a\n * `safeParse` method that returns a `ZodLikeSafeParseResult`).\n *\n * The validator also retains the **source JSON Schema** and exposes it\n * via `toJSON()` (tools-01): `toolToDefinition` and the code-mode\n * signature projection honour `toJSON()`, so without it an MCP tool's\n * parameters serialise to `{}` on the provider wire body - the model\n * would see an argument-less tool. Boolean schemas normalise to their\n * record equivalents (`true` → `{}`, `false` → `{ not: {} }`).\n *\n * @stable\n */\nexport function buildJsonSchemaValidator<T = unknown>(schema: JsonSchemaLike): ZodLikeSchema<T> {\n function parse(data: unknown): T {\n const issues = validate(data, schema, []);\n if (issues.length === 0) return data as T;\n throw buildError(issues);\n }\n function safeParse(data: unknown): ZodLikeSafeParseResult<T, unknown> {\n const issues = validate(data, schema, []);\n if (issues.length === 0) {\n return { success: true, data: data as T };\n }\n return { success: false, error: buildError(issues) };\n }\n function toJSON(): Readonly<Record<string, unknown>> {\n if (schema === true) return {};\n if (schema === false) return { not: {} };\n return schema;\n }\n return Object.freeze({ parse, safeParse, toJSON });\n}\n\ninterface Issue {\n readonly path: ReadonlyArray<string | number>;\n readonly message: string;\n}\n\nfunction validate(\n value: unknown,\n schema: JsonSchemaLike,\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true) return [];\n if (schema === false) return [{ path, message: 'rejected by schema (false)' }];\n\n const issues: Issue[] = [];\n\n if ('const' in schema && schema.const !== undefined) {\n if (!equalsDeep(value, schema.const)) {\n issues.push({ path, message: `expected const ${formatValue(schema.const)}` });\n }\n }\n if (Array.isArray(schema.enum)) {\n if (!schema.enum.some((candidate) => equalsDeep(value, candidate))) {\n issues.push({ path, message: 'value does not match any enum entry' });\n }\n }\n if (Array.isArray(schema.allOf)) {\n for (const sub of schema.allOf) {\n issues.push(...validate(value, sub, path));\n }\n }\n if (Array.isArray(schema.anyOf)) {\n const anyOk = schema.anyOf.some((sub) => validate(value, sub, path).length === 0);\n if (!anyOk) issues.push({ path, message: 'value did not match any of the anyOf branches' });\n }\n if (Array.isArray(schema.oneOf)) {\n const matchCount = schema.oneOf.filter((sub) => validate(value, sub, path).length === 0).length;\n if (matchCount !== 1) {\n issues.push({\n path,\n message: `expected exactly one oneOf branch to match (got ${matchCount})`,\n });\n }\n }\n\n if (schema.type !== undefined) {\n const typeIssues = validateType(value, schema, path);\n issues.push(...typeIssues);\n }\n\n return issues;\n}\n\nfunction validateType(\n value: unknown,\n schema: JsonSchemaLike,\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true || schema === false) return [];\n const types: ReadonlyArray<string> = Array.isArray(schema.type)\n ? schema.type\n : schema.type === undefined\n ? []\n : [schema.type];\n if (types.length === 0) return [];\n if (!types.some((t) => matchesType(value, t))) {\n return [{ path, message: `expected type ${types.join(' | ')}` }];\n }\n\n if (\n matchesType(value, 'object') &&\n (schema.properties !== undefined ||\n schema.required !== undefined ||\n schema.additionalProperties !== undefined)\n ) {\n return validateObject(value as Record<string, unknown>, schema, path);\n }\n if (matchesType(value, 'array')) {\n return validateArray(value as unknown[], schema, path);\n }\n if (matchesType(value, 'string')) {\n return validateString(value as string, schema, path);\n }\n if (matchesType(value, 'number') || matchesType(value, 'integer')) {\n return validateNumber(value as number, schema, path);\n }\n return [];\n}\n\nfunction validateObject(\n value: Record<string, unknown>,\n schema: JsonSchemaLike & { readonly type?: unknown },\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true || schema === false) return [];\n const issues: Issue[] = [];\n const required = Array.isArray(schema.required) ? schema.required : [];\n for (const key of required) {\n if (!(key in value)) {\n issues.push({ path: [...path, key], message: 'is required' });\n }\n }\n const properties = schema.properties ?? {};\n for (const [key, subSchema] of Object.entries(properties)) {\n if (!(key in value)) continue;\n issues.push(...validate(value[key], subSchema, [...path, key]));\n }\n if (schema.additionalProperties === false) {\n for (const key of Object.keys(value)) {\n if (!(key in properties)) {\n issues.push({ path: [...path, key], message: 'unexpected additional property' });\n }\n }\n } else if (\n typeof schema.additionalProperties === 'object' &&\n schema.additionalProperties !== null\n ) {\n for (const key of Object.keys(value)) {\n if (key in properties) continue;\n issues.push(\n ...validate(value[key], schema.additionalProperties as JsonSchemaLike, [...path, key]),\n );\n }\n }\n return issues;\n}\n\nfunction validateArray(\n value: unknown[],\n schema: JsonSchemaLike & { readonly type?: unknown },\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true || schema === false) return [];\n const issues: Issue[] = [];\n if (typeof schema.minItems === 'number' && value.length < schema.minItems) {\n issues.push({ path, message: `expected at least ${schema.minItems} items` });\n }\n if (typeof schema.maxItems === 'number' && value.length > schema.maxItems) {\n issues.push({ path, message: `expected at most ${schema.maxItems} items` });\n }\n const items = schema.items;\n if (items === undefined) return issues;\n if (Array.isArray(items)) {\n for (let i = 0; i < items.length; i++) {\n if (i >= value.length) break;\n const sub = items[i];\n if (sub === undefined) continue;\n issues.push(...validate(value[i], sub, [...path, i]));\n }\n } else {\n for (let i = 0; i < value.length; i++) {\n issues.push(...validate(value[i], items as JsonSchemaLike, [...path, i]));\n }\n }\n return issues;\n}\n\nfunction validateString(\n value: string,\n schema: JsonSchemaLike & { readonly type?: unknown },\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true || schema === false) return [];\n const issues: Issue[] = [];\n if (typeof schema.minLength === 'number' && value.length < schema.minLength) {\n issues.push({ path, message: `expected at least ${schema.minLength} characters` });\n }\n if (typeof schema.maxLength === 'number' && value.length > schema.maxLength) {\n issues.push({ path, message: `expected at most ${schema.maxLength} characters` });\n }\n if (typeof schema.pattern === 'string') {\n // mcp-skills-07: the pattern comes VERBATIM from the (untrusted)\n // MCP server and runs on every validated input - a\n // catastrophic-backtracking pattern (`(a+)+$`) plus a long\n // model-generated string stalls the agent's event loop. Guards:\n // cap the pattern and the tested-string length, and reject the\n // classic nested-quantifier shapes heuristically. A guarded-out\n // pattern degrades to permissive (same as a malformed one).\n if (\n schema.pattern.length <= MAX_PATTERN_LENGTH &&\n value.length <= MAX_PATTERN_TEST_LENGTH &&\n !looksCatastrophic(schema.pattern)\n ) {\n try {\n const re = new RegExp(schema.pattern);\n if (!re.test(value))\n issues.push({ path, message: `did not match pattern ${schema.pattern}` });\n } catch {\n // Treat malformed patterns as permissive (mirrors Ajv default).\n }\n }\n }\n return issues;\n}\n\n/** mcp-skills-07: hard caps on server-supplied `pattern` evaluation. */\nconst MAX_PATTERN_LENGTH = 1_000;\nconst MAX_PATTERN_TEST_LENGTH = 10_000;\n\n/**\n * Cheap heuristic for the classic catastrophic-backtracking shape: a\n * group whose inner expression ends with a quantifier and which is\n * itself quantified (`(a+)+`, `(a*)*`, `(a+){2,}`, `(?:x+)*`). A\n * linear-time engine (re2) would make this exact; the heuristic errs\n * on the safe side for untrusted input, and a rejected pattern simply\n * degrades to permissive.\n */\nfunction looksCatastrophic(pattern: string): boolean {\n return /\\)[*+]|\\)\\{\\d+,(?:\\d+)?\\}/.test(pattern) && /[*+}]\\s*\\)/.test(pattern);\n}\n\nfunction validateNumber(\n value: number,\n schema: JsonSchemaLike & { readonly type?: unknown },\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true || schema === false) return [];\n const issues: Issue[] = [];\n const types: ReadonlyArray<string> = Array.isArray(schema.type)\n ? schema.type\n : schema.type === undefined\n ? []\n : [schema.type];\n if (types.includes('integer') && !Number.isInteger(value)) {\n issues.push({ path, message: 'expected an integer' });\n }\n if (typeof schema.minimum === 'number' && value < schema.minimum) {\n issues.push({ path, message: `expected >= ${schema.minimum}` });\n }\n if (typeof schema.maximum === 'number' && value > schema.maximum) {\n issues.push({ path, message: `expected <= ${schema.maximum}` });\n }\n return issues;\n}\n\nfunction matchesType(value: unknown, type: string): boolean {\n switch (type) {\n case 'string':\n return typeof value === 'string';\n case 'number':\n return typeof value === 'number' && Number.isFinite(value);\n case 'integer':\n return typeof value === 'number' && Number.isFinite(value);\n case 'boolean':\n return typeof value === 'boolean';\n case 'null':\n return value === null;\n case 'array':\n return Array.isArray(value);\n case 'object':\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n default:\n return true;\n }\n}\n\nfunction equalsDeep(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a === null || b === null) return a === b;\n if (typeof a !== typeof b) return false;\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n return a.every((item, i) => equalsDeep(item, b[i]));\n }\n if (typeof a === 'object' && typeof b === 'object') {\n const ak = Object.keys(a as Record<string, unknown>);\n const bk = Object.keys(b as Record<string, unknown>);\n if (ak.length !== bk.length) return false;\n return ak.every((key) =>\n equalsDeep((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key]),\n );\n }\n return false;\n}\n\nfunction formatValue(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch {\n return Object.prototype.toString.call(value);\n }\n}\n\nfunction buildError(issues: ReadonlyArray<Issue>): ZodLikeError {\n return {\n name: 'GraphorinMCPSchemaError',\n message: issues\n .map((i) => `${i.path.length === 0 ? '.' : i.path.join('.')}: ${i.message}`)\n .join('; '),\n issues: Object.freeze(\n issues.map((i) => ({ path: Object.freeze([...i.path]), message: i.message })),\n ),\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"json-schema.js","names":["issues: Issue[]","types: ReadonlyArray<string>"],"sources":["../../src/registry/json-schema.ts"],"sourcesContent":["/**\n * Lightweight JSON-Schema -> {@link ZodLikeSchema} adapter.\n *\n * The Model Context Protocol carries tool input + output schemas as\n * JSON Schema documents; the Graphorin tool registry types its\n * schemas via the `ZodLikeSchema` structural contract from\n * `@graphorin/core`. This module bridges the two without pulling\n * `zod` into the MCP boundary or relying on code generation +\n * runtime `eval` (the popular `json-schema-to-zod` package generates\n * source code that needs `new Function(...)` to execute).\n *\n * The adapter validates the canonical subset of JSON Schema the MCP\n * spec uses: `object` (with `properties`, `required`,\n * `additionalProperties`), `array` (with `items`, `minItems`,\n * `maxItems`), `string` (with `enum`, `minLength`, `maxLength`,\n * `pattern`), `number` / `integer` (with `enum`, `minimum`,\n * `maximum`), `boolean`, `null`, and the primitive composition\n * keywords `enum`, `const`, `oneOf`, `anyOf`, `allOf`. Unknown keys\n * are accepted permissively so newer MCP server schemas that ship\n * additional vocabulary do not break the adapter.\n *\n * @packageDocumentation\n */\n\nimport type { ZodLikeError, ZodLikeSafeParseResult, ZodLikeSchema } from '@graphorin/core';\n\n/** JSON Schema document subset accepted by {@link buildJsonSchemaValidator}. */\nexport type JsonSchemaLike =\n | boolean\n | (Readonly<Record<string, unknown>> & {\n readonly type?: string | ReadonlyArray<string>;\n readonly properties?: Readonly<Record<string, JsonSchemaLike>>;\n readonly required?: ReadonlyArray<string>;\n readonly additionalProperties?: boolean | JsonSchemaLike;\n readonly items?: JsonSchemaLike | ReadonlyArray<JsonSchemaLike>;\n readonly minItems?: number;\n readonly maxItems?: number;\n readonly minimum?: number;\n readonly maximum?: number;\n readonly minLength?: number;\n readonly maxLength?: number;\n readonly pattern?: string;\n readonly enum?: ReadonlyArray<unknown>;\n readonly const?: unknown;\n readonly oneOf?: ReadonlyArray<JsonSchemaLike>;\n readonly anyOf?: ReadonlyArray<JsonSchemaLike>;\n readonly allOf?: ReadonlyArray<JsonSchemaLike>;\n });\n\n/**\n * Build a {@link ZodLikeSchema} that validates `data` against\n * `schema`. The returned instance follows the structural Zod\n * contract from `@graphorin/core` (a `parse` method that throws + a\n * `safeParse` method that returns a `ZodLikeSafeParseResult`).\n *\n * The validator also retains the **source JSON Schema** and exposes it\n * via `toJSON()` (tools-01): `toolToDefinition` and the code-mode\n * signature projection honour `toJSON()`, so without it an MCP tool's\n * parameters serialise to `{}` on the provider wire body - the model\n * would see an argument-less tool. Boolean schemas normalise to their\n * record equivalents (`true` → `{}`, `false` → `{ not: {} }`).\n *\n * @stable\n */\nexport function buildJsonSchemaValidator<T = unknown>(schema: JsonSchemaLike): ZodLikeSchema<T> {\n function parse(data: unknown): T {\n const issues = validate(data, schema, []);\n if (issues.length === 0) return data as T;\n throw buildError(issues);\n }\n function safeParse(data: unknown): ZodLikeSafeParseResult<T, unknown> {\n const issues = validate(data, schema, []);\n if (issues.length === 0) {\n return { success: true, data: data as T };\n }\n return { success: false, error: buildError(issues) };\n }\n function toJSON(): Readonly<Record<string, unknown>> {\n if (schema === true) return {};\n if (schema === false) return { not: {} };\n return schema;\n }\n return Object.freeze({ parse, safeParse, toJSON });\n}\n\ninterface Issue {\n readonly path: ReadonlyArray<string | number>;\n readonly message: string;\n}\n\nfunction validate(\n value: unknown,\n schema: JsonSchemaLike,\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true) return [];\n if (schema === false) return [{ path, message: 'rejected by schema (false)' }];\n\n const issues: Issue[] = [];\n\n if ('const' in schema && schema.const !== undefined) {\n if (!equalsDeep(value, schema.const)) {\n issues.push({ path, message: `expected const ${formatValue(schema.const)}` });\n }\n }\n if (Array.isArray(schema.enum)) {\n if (!schema.enum.some((candidate) => equalsDeep(value, candidate))) {\n issues.push({ path, message: 'value does not match any enum entry' });\n }\n }\n if (Array.isArray(schema.allOf)) {\n for (const sub of schema.allOf) {\n issues.push(...validate(value, sub, path));\n }\n }\n if (Array.isArray(schema.anyOf)) {\n const anyOk = schema.anyOf.some((sub) => validate(value, sub, path).length === 0);\n if (!anyOk) issues.push({ path, message: 'value did not match any of the anyOf branches' });\n }\n if (Array.isArray(schema.oneOf)) {\n const matchCount = schema.oneOf.filter((sub) => validate(value, sub, path).length === 0).length;\n if (matchCount !== 1) {\n issues.push({\n path,\n message: `expected exactly one oneOf branch to match (got ${matchCount})`,\n });\n }\n }\n\n if (schema.type !== undefined) {\n const typeIssues = validateType(value, schema, path);\n issues.push(...typeIssues);\n }\n\n return issues;\n}\n\nfunction validateType(\n value: unknown,\n schema: JsonSchemaLike,\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true || schema === false) return [];\n const types: ReadonlyArray<string> = Array.isArray(schema.type)\n ? schema.type\n : schema.type === undefined\n ? []\n : [schema.type];\n if (types.length === 0) return [];\n if (!types.some((t) => matchesType(value, t))) {\n return [{ path, message: `expected type ${types.join(' | ')}` }];\n }\n\n if (\n matchesType(value, 'object') &&\n (schema.properties !== undefined ||\n schema.required !== undefined ||\n schema.additionalProperties !== undefined)\n ) {\n return validateObject(value as Record<string, unknown>, schema, path);\n }\n if (matchesType(value, 'array')) {\n return validateArray(value as unknown[], schema, path);\n }\n if (matchesType(value, 'string')) {\n return validateString(value as string, schema, path);\n }\n if (matchesType(value, 'number') || matchesType(value, 'integer')) {\n return validateNumber(value as number, schema, path);\n }\n return [];\n}\n\nfunction validateObject(\n value: Record<string, unknown>,\n schema: JsonSchemaLike & { readonly type?: unknown },\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true || schema === false) return [];\n const issues: Issue[] = [];\n const required = Array.isArray(schema.required) ? schema.required : [];\n for (const key of required) {\n if (!(key in value)) {\n issues.push({ path: [...path, key], message: 'is required' });\n }\n }\n const properties = schema.properties ?? {};\n for (const [key, subSchema] of Object.entries(properties)) {\n if (!(key in value)) continue;\n issues.push(...validate(value[key], subSchema, [...path, key]));\n }\n if (schema.additionalProperties === false) {\n for (const key of Object.keys(value)) {\n if (!(key in properties)) {\n issues.push({ path: [...path, key], message: 'unexpected additional property' });\n }\n }\n } else if (\n typeof schema.additionalProperties === 'object' &&\n schema.additionalProperties !== null\n ) {\n for (const key of Object.keys(value)) {\n if (key in properties) continue;\n issues.push(\n ...validate(value[key], schema.additionalProperties as JsonSchemaLike, [...path, key]),\n );\n }\n }\n return issues;\n}\n\nfunction validateArray(\n value: unknown[],\n schema: JsonSchemaLike & { readonly type?: unknown },\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true || schema === false) return [];\n const issues: Issue[] = [];\n if (typeof schema.minItems === 'number' && value.length < schema.minItems) {\n issues.push({ path, message: `expected at least ${schema.minItems} items` });\n }\n if (typeof schema.maxItems === 'number' && value.length > schema.maxItems) {\n issues.push({ path, message: `expected at most ${schema.maxItems} items` });\n }\n const items = schema.items;\n if (items === undefined) return issues;\n if (Array.isArray(items)) {\n for (let i = 0; i < items.length; i++) {\n if (i >= value.length) break;\n const sub = items[i];\n if (sub === undefined) continue;\n issues.push(...validate(value[i], sub, [...path, i]));\n }\n } else {\n for (let i = 0; i < value.length; i++) {\n issues.push(...validate(value[i], items as JsonSchemaLike, [...path, i]));\n }\n }\n return issues;\n}\n\nfunction validateString(\n value: string,\n schema: JsonSchemaLike & { readonly type?: unknown },\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true || schema === false) return [];\n const issues: Issue[] = [];\n if (typeof schema.minLength === 'number' && value.length < schema.minLength) {\n issues.push({ path, message: `expected at least ${schema.minLength} characters` });\n }\n if (typeof schema.maxLength === 'number' && value.length > schema.maxLength) {\n issues.push({ path, message: `expected at most ${schema.maxLength} characters` });\n }\n if (typeof schema.pattern === 'string') {\n // mcp-skills-07: the pattern comes VERBATIM from the (untrusted)\n // MCP server and runs on every validated input - a\n // catastrophic-backtracking pattern (`(a+)+$`) plus a long\n // model-generated string stalls the agent's event loop. Guards:\n // cap the pattern and the tested-string length, and reject the\n // classic nested-quantifier shapes heuristically. A guarded-out\n // pattern degrades to permissive (same as a malformed one).\n // W-078 defense-in-depth: any quantified group can still backtrack\n // polynomially even when the heuristic below admits it, so the\n // tested-string cap shrinks whenever one is present.\n const maxTestLength = QUANTIFIED_GROUP_RE.test(schema.pattern)\n ? MAX_QUANTIFIED_GROUP_TEST_LENGTH\n : MAX_PATTERN_TEST_LENGTH;\n if (\n schema.pattern.length <= MAX_PATTERN_LENGTH &&\n value.length <= maxTestLength &&\n !looksCatastrophic(schema.pattern)\n ) {\n try {\n const re = new RegExp(schema.pattern);\n if (!re.test(value))\n issues.push({ path, message: `did not match pattern ${schema.pattern}` });\n } catch {\n // Treat malformed patterns as permissive (mirrors Ajv default).\n }\n }\n }\n return issues;\n}\n\n/** mcp-skills-07: hard caps on server-supplied `pattern` evaluation. */\nconst MAX_PATTERN_LENGTH = 1_000;\nconst MAX_PATTERN_TEST_LENGTH = 10_000;\n/** W-078: reduced cap applied whenever the pattern has a quantified group. */\nconst MAX_QUANTIFIED_GROUP_TEST_LENGTH = 1_000;\n\n/** A group that is itself quantified: `(...)+`, `(...)*`, `(...){2,}`. */\nconst QUANTIFIED_GROUP_RE = /\\)[*+]|\\)\\{\\d+,(?:\\d+)?\\}/;\n/** A group whose inner expression ends with a quantifier: `...+)`. */\nconst GROUP_BODY_ENDS_QUANTIFIED_RE = /[*+}]\\s*\\)/;\n\n/**\n * Cheap heuristic for exponential-backtracking shapes in a quantified\n * group (mcp-skills-07 / W-078). A pattern is rejected when a\n * quantified group is present AND either:\n *\n * - the group body ends with a quantifier - the classic nested\n * quantifier family (`(a+)+`, `(a*)*`, `(a+){2,}`, `(?:x+)*`); or\n * - the pattern contains an alternation - the alternation-overlap\n * family (`(a|a)+`, `^(\\w|\\d)*$`), where overlapping branches make\n * the quantified group ambiguous.\n *\n * Deliberately conservative: false positives (a harmless alternation\n * inside a quantified group) merely degrade that pattern to permissive\n * validation, which is the already-documented semantics for guarded\n * and malformed patterns. A linear-time engine (re2) remains the exact\n * solution; this heuristic plus the reduced test-string cap above\n * bound the damage of an untrusted server-supplied pattern.\n */\nfunction looksCatastrophic(pattern: string): boolean {\n if (!QUANTIFIED_GROUP_RE.test(pattern)) return false;\n return GROUP_BODY_ENDS_QUANTIFIED_RE.test(pattern) || pattern.includes('|');\n}\n\nfunction validateNumber(\n value: number,\n schema: JsonSchemaLike & { readonly type?: unknown },\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true || schema === false) return [];\n const issues: Issue[] = [];\n const types: ReadonlyArray<string> = Array.isArray(schema.type)\n ? schema.type\n : schema.type === undefined\n ? []\n : [schema.type];\n if (types.includes('integer') && !Number.isInteger(value)) {\n issues.push({ path, message: 'expected an integer' });\n }\n if (typeof schema.minimum === 'number' && value < schema.minimum) {\n issues.push({ path, message: `expected >= ${schema.minimum}` });\n }\n if (typeof schema.maximum === 'number' && value > schema.maximum) {\n issues.push({ path, message: `expected <= ${schema.maximum}` });\n }\n return issues;\n}\n\nfunction matchesType(value: unknown, type: string): boolean {\n switch (type) {\n case 'string':\n return typeof value === 'string';\n case 'number':\n return typeof value === 'number' && Number.isFinite(value);\n case 'integer':\n return typeof value === 'number' && Number.isFinite(value);\n case 'boolean':\n return typeof value === 'boolean';\n case 'null':\n return value === null;\n case 'array':\n return Array.isArray(value);\n case 'object':\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n default:\n return true;\n }\n}\n\nfunction equalsDeep(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a === null || b === null) return a === b;\n if (typeof a !== typeof b) return false;\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n return a.every((item, i) => equalsDeep(item, b[i]));\n }\n if (typeof a === 'object' && typeof b === 'object') {\n const ak = Object.keys(a as Record<string, unknown>);\n const bk = Object.keys(b as Record<string, unknown>);\n if (ak.length !== bk.length) return false;\n return ak.every((key) =>\n equalsDeep((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key]),\n );\n }\n return false;\n}\n\nfunction formatValue(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch {\n return Object.prototype.toString.call(value);\n }\n}\n\nfunction buildError(issues: ReadonlyArray<Issue>): ZodLikeError {\n return {\n name: 'GraphorinMCPSchemaError',\n message: issues\n .map((i) => `${i.path.length === 0 ? '.' : i.path.join('.')}: ${i.message}`)\n .join('; '),\n issues: Object.freeze(\n issues.map((i) => ({ path: Object.freeze([...i.path]), message: i.message })),\n ),\n };\n}\n"],"mappings":"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"}
@@ -71,22 +71,31 @@ interface SseTransportConfig {
71
71
  */
72
72
  type ServerIdentity = {
73
73
  readonly kind: 'mcp-stdio';
74
+ /** Transport-derived id (W-016) - see the union TSDoc. */
74
75
  readonly id: string;
75
76
  readonly command: string;
76
77
  readonly argsHash: string;
77
78
  readonly serverInfoName?: string;
79
+ /** Self-reported `serverInfo.name` - display/logs ONLY, never identity. */
80
+ readonly reportedServerName?: string;
78
81
  } | {
79
82
  readonly kind: 'mcp-streamable-http';
83
+ /** Transport-derived id including a non-default port (W-016). */
80
84
  readonly id: string;
81
85
  readonly urlHostname: string;
82
86
  readonly urlPath: string;
83
87
  readonly serverInfoName?: string;
88
+ /** Self-reported `serverInfo.name` - display/logs ONLY, never identity. */
89
+ readonly reportedServerName?: string;
84
90
  } | {
85
91
  readonly kind: 'mcp-sse';
92
+ /** Transport-derived id including a non-default port (W-016). */
86
93
  readonly id: string;
87
94
  readonly urlHostname: string;
88
95
  readonly urlPath: string;
89
96
  readonly serverInfoName?: string;
97
+ /** Self-reported `serverInfo.name` - display/logs ONLY, never identity. */
98
+ readonly reportedServerName?: string;
90
99
  };
91
100
  //#endregion
92
101
  export { MCPTransportConfig, ServerIdentity, SseTransportConfig, StdioTransportConfig, StreamableHttpTransportConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphorin/mcp",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Model Context Protocol client for the Graphorin framework: stdio + Streamable HTTP + SSE transports, typed `MCPClient` (`listTools` / `listResources` / `listPrompts` / `callTool`), `toTools()` adapter (per-server inbound prompt-injection sanitization, deferred-loading auto-default at the 10-tool threshold, structured-content + outputSchema round-trip with backward-compatible TextContent mirror, per-server result envelope overrides, per-server call timeout, mcp provenance stamping for the dataflow policy, per-server preferredModel and side-effect class overrides), OAuth integration backed by @graphorin/security/oauth, typed errors, and library helpers consumed by the graphorin auth CLI.",
5
5
  "license": "MIT",
6
6
  "author": "Oleksiy Stepurenko",
@@ -32,8 +32,9 @@
32
32
  "inbound-sanitization"
33
33
  ],
34
34
  "type": "module",
35
+ "sideEffects": false,
35
36
  "engines": {
36
- "node": ">=22.0.0"
37
+ "node": ">=22.12.0"
37
38
  },
38
39
  "main": "./dist/index.js",
39
40
  "module": "./dist/index.js",
@@ -41,42 +42,42 @@
41
42
  "exports": {
42
43
  ".": {
43
44
  "types": "./dist/index.d.ts",
44
- "import": "./dist/index.js"
45
+ "default": "./dist/index.js"
45
46
  },
46
47
  "./client": {
47
48
  "types": "./dist/client/index.d.ts",
48
- "import": "./dist/client/index.js"
49
+ "default": "./dist/client/index.js"
49
50
  },
50
51
  "./transport": {
51
52
  "types": "./dist/transport/index.d.ts",
52
- "import": "./dist/transport/index.js"
53
+ "default": "./dist/transport/index.js"
53
54
  },
54
55
  "./oauth": {
55
56
  "types": "./dist/oauth/index.d.ts",
56
- "import": "./dist/oauth/index.js"
57
+ "default": "./dist/oauth/index.js"
57
58
  },
58
59
  "./helpers": {
59
60
  "types": "./dist/helpers/index.d.ts",
60
- "import": "./dist/helpers/index.js"
61
+ "default": "./dist/helpers/index.js"
61
62
  },
62
63
  "./errors": {
63
64
  "types": "./dist/errors/index.d.ts",
64
- "import": "./dist/errors/index.js"
65
+ "default": "./dist/errors/index.js"
65
66
  },
66
67
  "./package.json": "./package.json"
67
68
  },
68
69
  "files": [
69
70
  "dist",
71
+ "src",
70
72
  "README.md",
71
73
  "CHANGELOG.md",
72
74
  "LICENSE"
73
75
  ],
74
76
  "dependencies": {
75
77
  "@modelcontextprotocol/sdk": "^1.29.0",
76
- "@graphorin/core": "0.6.0",
77
- "@graphorin/observability": "0.6.0",
78
- "@graphorin/security": "0.6.0",
79
- "@graphorin/tools": "0.6.0"
78
+ "@graphorin/core": "0.7.0",
79
+ "@graphorin/security": "0.7.0",
80
+ "@graphorin/tools": "0.7.0"
80
81
  },
81
82
  "peerDependencies": {
82
83
  "zod": "^3.23.0 || ^4.0.0"