@heddleagent/execution-host-client 6.0.0-next.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 (152) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +305 -0
  3. package/dist/authority/index.d.ts +3 -0
  4. package/dist/authority/index.d.ts.map +1 -0
  5. package/dist/authority/index.js +2 -0
  6. package/dist/authority/index.js.map +1 -0
  7. package/dist/authority/jose-execution-authority.d.ts +14 -0
  8. package/dist/authority/jose-execution-authority.d.ts.map +1 -0
  9. package/dist/authority/jose-execution-authority.js +266 -0
  10. package/dist/authority/jose-execution-authority.js.map +1 -0
  11. package/dist/authority/types.d.ts +63 -0
  12. package/dist/authority/types.d.ts.map +1 -0
  13. package/dist/authority/types.js +2 -0
  14. package/dist/authority/types.js.map +1 -0
  15. package/dist/contracts/index.d.ts +163 -0
  16. package/dist/contracts/index.d.ts.map +1 -0
  17. package/dist/contracts/index.js +149 -0
  18. package/dist/contracts/index.js.map +1 -0
  19. package/dist/conversation/durable-hosted-conversation-turn-service.d.ts +23 -0
  20. package/dist/conversation/durable-hosted-conversation-turn-service.d.ts.map +1 -0
  21. package/dist/conversation/durable-hosted-conversation-turn-service.js +273 -0
  22. package/dist/conversation/durable-hosted-conversation-turn-service.js.map +1 -0
  23. package/dist/conversation/hosted-conversation-turn-service.d.ts +17 -0
  24. package/dist/conversation/hosted-conversation-turn-service.d.ts.map +1 -0
  25. package/dist/conversation/hosted-conversation-turn-service.js +60 -0
  26. package/dist/conversation/hosted-conversation-turn-service.js.map +1 -0
  27. package/dist/conversation/index.d.ts +7 -0
  28. package/dist/conversation/index.d.ts.map +1 -0
  29. package/dist/conversation/index.js +5 -0
  30. package/dist/conversation/index.js.map +1 -0
  31. package/dist/conversation/lifecycle-types.d.ts +208 -0
  32. package/dist/conversation/lifecycle-types.d.ts.map +1 -0
  33. package/dist/conversation/lifecycle-types.js +92 -0
  34. package/dist/conversation/lifecycle-types.js.map +1 -0
  35. package/dist/conversation/types.d.ts +35 -0
  36. package/dist/conversation/types.d.ts.map +1 -0
  37. package/dist/conversation/types.js +11 -0
  38. package/dist/conversation/types.js.map +1 -0
  39. package/dist/http-sse/direct-http-execution-host.d.ts +12 -0
  40. package/dist/http-sse/direct-http-execution-host.d.ts.map +1 -0
  41. package/dist/http-sse/direct-http-execution-host.js +279 -0
  42. package/dist/http-sse/direct-http-execution-host.js.map +1 -0
  43. package/dist/http-sse/errors.d.ts +19 -0
  44. package/dist/http-sse/errors.d.ts.map +1 -0
  45. package/dist/http-sse/errors.js +29 -0
  46. package/dist/http-sse/errors.js.map +1 -0
  47. package/dist/http-sse/index.d.ts +4 -0
  48. package/dist/http-sse/index.d.ts.map +1 -0
  49. package/dist/http-sse/index.js +3 -0
  50. package/dist/http-sse/index.js.map +1 -0
  51. package/dist/http-sse/types.d.ts +20 -0
  52. package/dist/http-sse/types.d.ts.map +1 -0
  53. package/dist/http-sse/types.js +2 -0
  54. package/dist/http-sse/types.js.map +1 -0
  55. package/dist/index.d.ts +6 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +6 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/mcp/errors.d.ts +11 -0
  60. package/dist/mcp/errors.d.ts.map +1 -0
  61. package/dist/mcp/errors.js +15 -0
  62. package/dist/mcp/errors.js.map +1 -0
  63. package/dist/mcp/index.d.ts +5 -0
  64. package/dist/mcp/index.d.ts.map +1 -0
  65. package/dist/mcp/index.js +3 -0
  66. package/dist/mcp/index.js.map +1 -0
  67. package/dist/mcp/jwt-capability-verifier.d.ts +12 -0
  68. package/dist/mcp/jwt-capability-verifier.d.ts.map +1 -0
  69. package/dist/mcp/jwt-capability-verifier.js +136 -0
  70. package/dist/mcp/jwt-capability-verifier.js.map +1 -0
  71. package/dist/mcp/node/index.d.ts +4 -0
  72. package/dist/mcp/node/index.d.ts.map +1 -0
  73. package/dist/mcp/node/index.js +3 -0
  74. package/dist/mcp/node/index.js.map +1 -0
  75. package/dist/mcp/node/json-toolset.d.ts +23 -0
  76. package/dist/mcp/node/json-toolset.d.ts.map +1 -0
  77. package/dist/mcp/node/json-toolset.js +94 -0
  78. package/dist/mcp/node/json-toolset.js.map +1 -0
  79. package/dist/mcp/node/streamable-http-mcp-service.d.ts +18 -0
  80. package/dist/mcp/node/streamable-http-mcp-service.d.ts.map +1 -0
  81. package/dist/mcp/node/streamable-http-mcp-service.js +229 -0
  82. package/dist/mcp/node/streamable-http-mcp-service.js.map +1 -0
  83. package/dist/mcp/node/types.d.ts +53 -0
  84. package/dist/mcp/node/types.d.ts.map +1 -0
  85. package/dist/mcp/node/types.js +2 -0
  86. package/dist/mcp/node/types.js.map +1 -0
  87. package/dist/mcp/types.d.ts +37 -0
  88. package/dist/mcp/types.d.ts.map +1 -0
  89. package/dist/mcp/types.js +2 -0
  90. package/dist/mcp/types.js.map +1 -0
  91. package/dist/node/authority-key.d.ts +14 -0
  92. package/dist/node/authority-key.d.ts.map +1 -0
  93. package/dist/node/authority-key.js +89 -0
  94. package/dist/node/authority-key.js.map +1 -0
  95. package/dist/node/direct-credentials.d.ts +21 -0
  96. package/dist/node/direct-credentials.d.ts.map +1 -0
  97. package/dist/node/direct-credentials.js +47 -0
  98. package/dist/node/direct-credentials.js.map +1 -0
  99. package/dist/node/http-service.d.ts +21 -0
  100. package/dist/node/http-service.d.ts.map +1 -0
  101. package/dist/node/http-service.js +389 -0
  102. package/dist/node/http-service.js.map +1 -0
  103. package/dist/node/index.d.ts +6 -0
  104. package/dist/node/index.d.ts.map +1 -0
  105. package/dist/node/index.js +4 -0
  106. package/dist/node/index.js.map +1 -0
  107. package/dist/node/types.d.ts +52 -0
  108. package/dist/node/types.d.ts.map +1 -0
  109. package/dist/node/types.js +2 -0
  110. package/dist/node/types.js.map +1 -0
  111. package/dist/testing/event-stream.d.ts +17 -0
  112. package/dist/testing/event-stream.d.ts.map +1 -0
  113. package/dist/testing/event-stream.js +83 -0
  114. package/dist/testing/event-stream.js.map +1 -0
  115. package/dist/testing/hosted-conversation-turn-store-conformance.d.ts +17 -0
  116. package/dist/testing/hosted-conversation-turn-store-conformance.d.ts.map +1 -0
  117. package/dist/testing/hosted-conversation-turn-store-conformance.js +137 -0
  118. package/dist/testing/hosted-conversation-turn-store-conformance.js.map +1 -0
  119. package/dist/testing/index.d.ts +5 -0
  120. package/dist/testing/index.d.ts.map +1 -0
  121. package/dist/testing/index.js +3 -0
  122. package/dist/testing/index.js.map +1 -0
  123. package/dist/testing/invocation.d.ts +20 -0
  124. package/dist/testing/invocation.d.ts.map +1 -0
  125. package/dist/testing/invocation.js +39 -0
  126. package/dist/testing/invocation.js.map +1 -0
  127. package/dist/testing/local-execution-host-contract-fixture.d.ts +21 -0
  128. package/dist/testing/local-execution-host-contract-fixture.d.ts.map +1 -0
  129. package/dist/testing/local-execution-host-contract-fixture.js +197 -0
  130. package/dist/testing/local-execution-host-contract-fixture.js.map +1 -0
  131. package/dist/testing/request.d.ts +10 -0
  132. package/dist/testing/request.d.ts.map +1 -0
  133. package/dist/testing/request.js +140 -0
  134. package/dist/testing/request.js.map +1 -0
  135. package/dist/testing/types.d.ts +42 -0
  136. package/dist/testing/types.d.ts.map +1 -0
  137. package/dist/testing/types.js +2 -0
  138. package/dist/testing/types.js.map +1 -0
  139. package/package.json +92 -0
  140. package/spec/v1/README.md +101 -0
  141. package/spec/v1/durable-hosted-conversation-lifecycle.md +139 -0
  142. package/spec/v1/fixtures/ambiguous-eof.sse +9 -0
  143. package/spec/v1/fixtures/authority.json +70 -0
  144. package/spec/v1/fixtures/cancelled.sse +9 -0
  145. package/spec/v1/fixtures/durable-conversation-lifecycle.json +890 -0
  146. package/spec/v1/fixtures/invalid-request-extra-field.json +8 -0
  147. package/spec/v1/fixtures/invalid-sequence-gap.sse +9 -0
  148. package/spec/v1/fixtures/manifest.json +53 -0
  149. package/spec/v1/fixtures/valid-request.json +7 -0
  150. package/spec/v1/fixtures/valid-result.sse +13 -0
  151. package/spec/v1/openapi.json +896 -0
  152. package/spec/v1/schema-bundle.json +1286 -0
@@ -0,0 +1,6 @@
1
+ export * from './contracts/index.js';
2
+ export * from './authority/index.js';
3
+ export * from './conversation/index.js';
4
+ export * from './mcp/index.js';
5
+ export * from './http-sse/index.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from './contracts/index.js';
2
+ export * from './authority/index.js';
3
+ export * from './conversation/index.js';
4
+ export * from './mcp/index.js';
5
+ export * from './http-sse/index.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC","sourcesContent":["export * from './contracts/index.js';\nexport * from './authority/index.js';\nexport * from './conversation/index.js';\nexport * from './mcp/index.js';\nexport * from './http-sse/index.js';\n"]}
@@ -0,0 +1,11 @@
1
+ export declare class McpCapabilityVerificationError extends Error {
2
+ readonly name = "McpCapabilityVerificationError";
3
+ constructor();
4
+ }
5
+ export type McpCapabilityUnavailableCategory = 'network' | 'jwks';
6
+ export declare class McpCapabilityUnavailableError extends Error {
7
+ readonly category: McpCapabilityUnavailableCategory;
8
+ readonly name = "McpCapabilityUnavailableError";
9
+ constructor(category: McpCapabilityUnavailableCategory);
10
+ }
11
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/mcp/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,8BAA+B,SAAQ,KAAK;IACvD,QAAQ,CAAC,IAAI,oCAAoC;;CAKlD;AAED,MAAM,MAAM,gCAAgC,GAAG,SAAS,GAAG,MAAM,CAAC;AAElE,qBAAa,6BAA8B,SAAQ,KAAK;IAG1C,QAAQ,CAAC,QAAQ,EAAE,gCAAgC;IAF/D,QAAQ,CAAC,IAAI,mCAAmC;gBAE3B,QAAQ,EAAE,gCAAgC;CAGhE"}
@@ -0,0 +1,15 @@
1
+ export class McpCapabilityVerificationError extends Error {
2
+ name = 'McpCapabilityVerificationError';
3
+ constructor() {
4
+ super('MCP capability verification failed.');
5
+ }
6
+ }
7
+ export class McpCapabilityUnavailableError extends Error {
8
+ category;
9
+ name = 'McpCapabilityUnavailableError';
10
+ constructor(category) {
11
+ super('MCP capability verification is temporarily unavailable.');
12
+ this.category = category;
13
+ }
14
+ }
15
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/mcp/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,8BAA+B,SAAQ,KAAK;IAC9C,IAAI,GAAG,gCAAgC,CAAC;IAEjD;QACE,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAC/C,CAAC;CACF;AAID,MAAM,OAAO,6BAA8B,SAAQ,KAAK;IAGjC;IAFZ,IAAI,GAAG,+BAA+B,CAAC;IAEhD,YAAqB,QAA0C;QAC7D,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAD9C,aAAQ,GAAR,QAAQ,CAAkC;IAE/D,CAAC;CACF","sourcesContent":["export class McpCapabilityVerificationError extends Error {\n readonly name = 'McpCapabilityVerificationError';\n\n constructor() {\n super('MCP capability verification failed.');\n }\n}\n\nexport type McpCapabilityUnavailableCategory = 'network' | 'jwks';\n\nexport class McpCapabilityUnavailableError extends Error {\n readonly name = 'McpCapabilityUnavailableError';\n\n constructor(readonly category: McpCapabilityUnavailableCategory) {\n super('MCP capability verification is temporarily unavailable.');\n }\n}\n"]}
@@ -0,0 +1,5 @@
1
+ export { JwtMcpCapabilityVerifier, assertMcpCapabilityActive, } from './jwt-capability-verifier.js';
2
+ export { McpCapabilityUnavailableError, McpCapabilityVerificationError, } from './errors.js';
3
+ export type { McpCapabilityUnavailableCategory } from './errors.js';
4
+ export type { JwtMcpCapabilityVerifierConfig, JwtMcpCapabilityVerifierOptions, McpCapabilityVerifier, McpInvocationScope, VerifiedMcpCapability, } from './types.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,6BAA6B,EAC7B,8BAA8B,GAC/B,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,gCAAgC,EAAE,MAAM,aAAa,CAAC;AACpE,YAAY,EACV,8BAA8B,EAC9B,+BAA+B,EAC/B,qBAAqB,EACrB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { JwtMcpCapabilityVerifier, assertMcpCapabilityActive, } from './jwt-capability-verifier.js';
2
+ export { McpCapabilityUnavailableError, McpCapabilityVerificationError, } from './errors.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,6BAA6B,EAC7B,8BAA8B,GAC/B,MAAM,aAAa,CAAC","sourcesContent":["export {\n JwtMcpCapabilityVerifier,\n assertMcpCapabilityActive,\n} from './jwt-capability-verifier.js';\nexport {\n McpCapabilityUnavailableError,\n McpCapabilityVerificationError,\n} from './errors.js';\nexport type { McpCapabilityUnavailableCategory } from './errors.js';\nexport type {\n JwtMcpCapabilityVerifierConfig,\n JwtMcpCapabilityVerifierOptions,\n McpCapabilityVerifier,\n McpInvocationScope,\n VerifiedMcpCapability,\n} from './types.js';\n"]}
@@ -0,0 +1,12 @@
1
+ import type { JwtMcpCapabilityVerifierConfig, JwtMcpCapabilityVerifierOptions, McpCapabilityVerifier, VerifiedMcpCapability } from './types.js';
2
+ /**
3
+ * Independently verifies an adopter-signed capability at the adopter's MCP
4
+ * edge. Execution Host verification is defense in depth, not forwarded trust.
5
+ */
6
+ export declare class JwtMcpCapabilityVerifier<TToolName extends string> implements McpCapabilityVerifier<TToolName> {
7
+ #private;
8
+ constructor(config: JwtMcpCapabilityVerifierConfig<TToolName>, options?: JwtMcpCapabilityVerifierOptions);
9
+ verify(assertion: string): Promise<VerifiedMcpCapability<TToolName>>;
10
+ }
11
+ export declare function assertMcpCapabilityActive(capability: VerifiedMcpCapability, now?: Date): void;
12
+ //# sourceMappingURL=jwt-capability-verifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt-capability-verifier.d.ts","sourceRoot":"","sources":["../../src/mcp/jwt-capability-verifier.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EACV,8BAA8B,EAC9B,+BAA+B,EAC/B,qBAAqB,EACrB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAqBpB;;;GAGG;AACH,qBAAa,wBAAwB,CAAC,SAAS,SAAS,MAAM,CAC9D,YAAW,qBAAqB,CAAC,SAAS,CAAC;;gBAOvC,MAAM,EAAE,8BAA8B,CAAC,SAAS,CAAC,EACjD,OAAO,GAAE,+BAAoC;IAoBzC,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;CA8E3E;AAED,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,qBAAqB,EACjC,GAAG,OAAa,GACf,IAAI,CAKN"}
@@ -0,0 +1,136 @@
1
+ import { createRemoteJWKSet, errors, jwtVerify, } from 'jose';
2
+ import { z } from 'zod';
3
+ import { JwtAudienceSchema, JwtIssuerSchema, MCP_CAPABILITY_TYPE, McpAllowedToolsSchema, McpCapabilityClaimsSchema, McpServerIdSchema, OpaqueIdSchema, isSafeWebUrl, } from '../contracts/index.js';
4
+ import { McpCapabilityUnavailableError, McpCapabilityVerificationError, } from './errors.js';
5
+ const CapabilityAssertionSchema = z.string().min(32).max(4_096);
6
+ const ConfigSchema = z.object({
7
+ issuer: JwtIssuerSchema,
8
+ audience: JwtAudienceSchema,
9
+ jwksUrl: z.instanceof(URL).refine(isSafeWebUrl, 'must use HTTPS or loopback HTTP and contain no credentials, query, or fragment'),
10
+ trustedAdopterId: OpaqueIdSchema,
11
+ serverId: McpServerIdSchema,
12
+ supportedTools: McpAllowedToolsSchema,
13
+ maxCapabilityAgeSeconds: z.number().int().min(1).max(15 * 60),
14
+ clockToleranceSeconds: z.number().int().min(0).max(60).default(5),
15
+ }).strict();
16
+ /**
17
+ * Independently verifies an adopter-signed capability at the adopter's MCP
18
+ * edge. Execution Host verification is defense in depth, not forwarded trust.
19
+ */
20
+ export class JwtMcpCapabilityVerifier {
21
+ #config;
22
+ #supportedTools;
23
+ #keyResolver;
24
+ #now;
25
+ constructor(config, options = {}) {
26
+ const parsed = ConfigSchema.parse(config);
27
+ this.#config = Object.freeze({
28
+ ...parsed,
29
+ jwksUrl: new URL(parsed.jwksUrl),
30
+ supportedTools: Object.freeze([...parsed.supportedTools]),
31
+ });
32
+ this.#supportedTools = new Set(this.#config.supportedTools);
33
+ this.#keyResolver = options.keyResolver ?? createRemoteJWKSet(this.#config.jwksUrl, {
34
+ cacheMaxAge: 10 * 60_000,
35
+ cooldownDuration: 30_000,
36
+ timeoutDuration: 3_000,
37
+ });
38
+ this.#now = options.now ?? (() => new Date());
39
+ }
40
+ async verify(assertion) {
41
+ try {
42
+ const compactJwt = CapabilityAssertionSchema.parse(assertion);
43
+ const { payload } = await jwtVerify(compactJwt, this.#keyResolver, {
44
+ algorithms: ['ES256'],
45
+ audience: this.#config.audience,
46
+ clockTolerance: this.#config.clockToleranceSeconds,
47
+ currentDate: this.#now(),
48
+ issuer: this.#config.issuer,
49
+ maxTokenAge: this.#config.maxCapabilityAgeSeconds,
50
+ requiredClaims: ['exp', 'iat', 'jti', 'sub'],
51
+ typ: MCP_CAPABILITY_TYPE,
52
+ });
53
+ const claims = McpCapabilityClaimsSchema.parse(payload);
54
+ this.#assertDeploymentBinding(claims);
55
+ this.#assertBoundedLifetime(claims);
56
+ this.#assertSupportedTools(claims.allowedTools);
57
+ return freezeVerifiedCapability({
58
+ capabilityId: claims.jti,
59
+ serverId: claims.serverId,
60
+ allowedTools: claims.allowedTools,
61
+ scope: {
62
+ adopterId: claims.adopterId,
63
+ tenantId: claims.tenantId,
64
+ subjectId: claims.sub,
65
+ productSessionId: claims.productSessionId,
66
+ runtimeSessionId: claims.runtimeSessionId,
67
+ invocationId: claims.invocationId,
68
+ workflow: claims.workflow,
69
+ },
70
+ issuedAt: new Date(claims.iat * 1_000).toISOString(),
71
+ expiresAt: new Date(claims.exp * 1_000).toISOString(),
72
+ });
73
+ }
74
+ catch (error) {
75
+ if (error instanceof McpCapabilityVerificationError
76
+ || error instanceof McpCapabilityUnavailableError) {
77
+ throw error;
78
+ }
79
+ const unavailableCategory = resolveUnavailableCategory(error);
80
+ if (unavailableCategory) {
81
+ throw new McpCapabilityUnavailableError(unavailableCategory);
82
+ }
83
+ throw new McpCapabilityVerificationError();
84
+ }
85
+ }
86
+ #assertDeploymentBinding(claims) {
87
+ if (claims.adopterId !== this.#config.trustedAdopterId
88
+ || claims.serverId !== this.#config.serverId
89
+ || claims.jti === claims.invocationId) {
90
+ throw new McpCapabilityVerificationError();
91
+ }
92
+ }
93
+ #assertBoundedLifetime(claims) {
94
+ const lifetimeSeconds = claims.exp - claims.iat;
95
+ if (lifetimeSeconds <= 0
96
+ || lifetimeSeconds > this.#config.maxCapabilityAgeSeconds) {
97
+ throw new McpCapabilityVerificationError();
98
+ }
99
+ }
100
+ #assertSupportedTools(tools) {
101
+ if (!tools.every((tool) => this.#supportedTools.has(tool))) {
102
+ throw new McpCapabilityVerificationError();
103
+ }
104
+ }
105
+ }
106
+ export function assertMcpCapabilityActive(capability, now = new Date()) {
107
+ const expiresAt = Date.parse(capability.expiresAt);
108
+ if (!Number.isFinite(expiresAt) || now.getTime() >= expiresAt) {
109
+ throw new McpCapabilityVerificationError();
110
+ }
111
+ }
112
+ function freezeVerifiedCapability(capability) {
113
+ return Object.freeze({
114
+ ...capability,
115
+ allowedTools: Object.freeze([...capability.allowedTools]),
116
+ scope: Object.freeze({ ...capability.scope }),
117
+ });
118
+ }
119
+ const UNAVAILABLE_JOSE_CODES = new Set([
120
+ 'ERR_JOSE_GENERIC',
121
+ 'ERR_JWK_INVALID',
122
+ 'ERR_JWKS_INVALID',
123
+ 'ERR_JWKS_MULTIPLE_MATCHING_KEYS',
124
+ 'ERR_JWKS_TIMEOUT',
125
+ ]);
126
+ function resolveUnavailableCategory(error) {
127
+ if (error instanceof TypeError) {
128
+ return 'network';
129
+ }
130
+ if (error instanceof errors.JOSEError
131
+ && UNAVAILABLE_JOSE_CODES.has(error.code)) {
132
+ return 'jwks';
133
+ }
134
+ return undefined;
135
+ }
136
+ //# sourceMappingURL=jwt-capability-verifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt-capability-verifier.js","sourceRoot":"","sources":["../../src/mcp/jwt-capability-verifier.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createRemoteJWKSet,\n errors,\n jwtVerify,\n} from 'jose';\nimport { z } from 'zod';\nimport {\n JwtAudienceSchema,\n JwtIssuerSchema,\n MCP_CAPABILITY_TYPE,\n McpAllowedToolsSchema,\n McpCapabilityClaimsSchema,\n McpServerIdSchema,\n OpaqueIdSchema,\n isSafeWebUrl,\n} from '../contracts/index.js';\nimport {\n McpCapabilityUnavailableError,\n McpCapabilityVerificationError,\n} from './errors.js';\nimport type {\n JwtMcpCapabilityVerifierConfig,\n JwtMcpCapabilityVerifierOptions,\n McpCapabilityVerifier,\n VerifiedMcpCapability,\n} from './types.js';\n\nconst CapabilityAssertionSchema = z.string().min(32).max(4_096);\nconst ConfigSchema = z.object({\n issuer: JwtIssuerSchema,\n audience: JwtAudienceSchema,\n jwksUrl: z.instanceof(URL).refine(\n isSafeWebUrl,\n 'must use HTTPS or loopback HTTP and contain no credentials, query, or fragment',\n ),\n trustedAdopterId: OpaqueIdSchema,\n serverId: McpServerIdSchema,\n supportedTools: McpAllowedToolsSchema,\n maxCapabilityAgeSeconds: z.number().int().min(1).max(15 * 60),\n clockToleranceSeconds: z.number().int().min(0).max(60).default(5),\n}).strict();\n\ntype ParsedConfig = Omit<z.infer<typeof ConfigSchema>, 'supportedTools'> & {\n supportedTools: readonly string[];\n};\n\n/**\n * Independently verifies an adopter-signed capability at the adopter's MCP\n * edge. Execution Host verification is defense in depth, not forwarded trust.\n */\nexport class JwtMcpCapabilityVerifier<TToolName extends string>\nimplements McpCapabilityVerifier<TToolName> {\n readonly #config: Readonly<ParsedConfig>;\n readonly #supportedTools: ReadonlySet<string>;\n readonly #keyResolver: NonNullable<JwtMcpCapabilityVerifierOptions['keyResolver']>;\n readonly #now: () => Date;\n\n constructor(\n config: JwtMcpCapabilityVerifierConfig<TToolName>,\n options: JwtMcpCapabilityVerifierOptions = {},\n ) {\n const parsed = ConfigSchema.parse(config);\n this.#config = Object.freeze({\n ...parsed,\n jwksUrl: new URL(parsed.jwksUrl),\n supportedTools: Object.freeze([...parsed.supportedTools]),\n });\n this.#supportedTools = new Set(this.#config.supportedTools);\n this.#keyResolver = options.keyResolver ?? createRemoteJWKSet(\n this.#config.jwksUrl,\n {\n cacheMaxAge: 10 * 60_000,\n cooldownDuration: 30_000,\n timeoutDuration: 3_000,\n },\n );\n this.#now = options.now ?? (() => new Date());\n }\n\n async verify(assertion: string): Promise<VerifiedMcpCapability<TToolName>> {\n try {\n const compactJwt = CapabilityAssertionSchema.parse(assertion);\n const { payload } = await jwtVerify(compactJwt, this.#keyResolver, {\n algorithms: ['ES256'],\n audience: this.#config.audience,\n clockTolerance: this.#config.clockToleranceSeconds,\n currentDate: this.#now(),\n issuer: this.#config.issuer,\n maxTokenAge: this.#config.maxCapabilityAgeSeconds,\n requiredClaims: ['exp', 'iat', 'jti', 'sub'],\n typ: MCP_CAPABILITY_TYPE,\n });\n const claims = McpCapabilityClaimsSchema.parse(payload);\n this.#assertDeploymentBinding(claims);\n this.#assertBoundedLifetime(claims);\n this.#assertSupportedTools(claims.allowedTools);\n\n return freezeVerifiedCapability({\n capabilityId: claims.jti,\n serverId: claims.serverId,\n allowedTools: claims.allowedTools as TToolName[],\n scope: {\n adopterId: claims.adopterId,\n tenantId: claims.tenantId,\n subjectId: claims.sub,\n productSessionId: claims.productSessionId,\n runtimeSessionId: claims.runtimeSessionId,\n invocationId: claims.invocationId,\n workflow: claims.workflow,\n },\n issuedAt: new Date(claims.iat * 1_000).toISOString(),\n expiresAt: new Date(claims.exp * 1_000).toISOString(),\n });\n } catch (error) {\n if (\n error instanceof McpCapabilityVerificationError\n || error instanceof McpCapabilityUnavailableError\n ) {\n throw error;\n }\n const unavailableCategory = resolveUnavailableCategory(error);\n if (unavailableCategory) {\n throw new McpCapabilityUnavailableError(unavailableCategory);\n }\n throw new McpCapabilityVerificationError();\n }\n }\n\n #assertDeploymentBinding(\n claims: z.infer<typeof McpCapabilityClaimsSchema>,\n ): void {\n if (\n claims.adopterId !== this.#config.trustedAdopterId\n || claims.serverId !== this.#config.serverId\n || claims.jti === claims.invocationId\n ) {\n throw new McpCapabilityVerificationError();\n }\n }\n\n #assertBoundedLifetime(\n claims: z.infer<typeof McpCapabilityClaimsSchema>,\n ): void {\n const lifetimeSeconds = claims.exp - claims.iat;\n if (\n lifetimeSeconds <= 0\n || lifetimeSeconds > this.#config.maxCapabilityAgeSeconds\n ) {\n throw new McpCapabilityVerificationError();\n }\n }\n\n #assertSupportedTools(tools: readonly string[]): void {\n if (!tools.every((tool) => this.#supportedTools.has(tool))) {\n throw new McpCapabilityVerificationError();\n }\n }\n}\n\nexport function assertMcpCapabilityActive(\n capability: VerifiedMcpCapability,\n now = new Date(),\n): void {\n const expiresAt = Date.parse(capability.expiresAt);\n if (!Number.isFinite(expiresAt) || now.getTime() >= expiresAt) {\n throw new McpCapabilityVerificationError();\n }\n}\n\nfunction freezeVerifiedCapability<TToolName extends string>(\n capability: VerifiedMcpCapability<TToolName>,\n): VerifiedMcpCapability<TToolName> {\n return Object.freeze({\n ...capability,\n allowedTools: Object.freeze([...capability.allowedTools]),\n scope: Object.freeze({ ...capability.scope }),\n });\n}\n\nconst UNAVAILABLE_JOSE_CODES = new Set([\n 'ERR_JOSE_GENERIC',\n 'ERR_JWK_INVALID',\n 'ERR_JWKS_INVALID',\n 'ERR_JWKS_MULTIPLE_MATCHING_KEYS',\n 'ERR_JWKS_TIMEOUT',\n]);\n\nfunction resolveUnavailableCategory(\n error: unknown,\n): 'network' | 'jwks' | undefined {\n if (error instanceof TypeError) {\n return 'network';\n }\n if (\n error instanceof errors.JOSEError\n && UNAVAILABLE_JOSE_CODES.has(error.code)\n ) {\n return 'jwks';\n }\n return undefined;\n}\n"]}
@@ -0,0 +1,4 @@
1
+ export { NodeStreamableHttpMcpService } from './streamable-http-mcp-service.js';
2
+ export { defineNodeMcpJsonTool, NodeMcpJsonToolset, NodeMcpJsonToolsetConfigurationError, } from './json-toolset.js';
3
+ export type { AnyNodeMcpJsonToolDefinition, NodeMcpJsonToolDefinition, NodeMcpJsonToolExecutionContext, NodeMcpJsonToolsetConfig, NodeMcpToolRegistrationContext, NodeMcpToolset, NodeStreamableHttpMcpServiceConfig, } from './types.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/mcp/node/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAChF,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,oCAAoC,GACrC,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,4BAA4B,EAC5B,yBAAyB,EACzB,+BAA+B,EAC/B,wBAAwB,EACxB,8BAA8B,EAC9B,cAAc,EACd,kCAAkC,GACnC,MAAM,YAAY,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { NodeStreamableHttpMcpService } from './streamable-http-mcp-service.js';
2
+ export { defineNodeMcpJsonTool, NodeMcpJsonToolset, NodeMcpJsonToolsetConfigurationError, } from './json-toolset.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mcp/node/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAChF,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,oCAAoC,GACrC,MAAM,mBAAmB,CAAC","sourcesContent":["export { NodeStreamableHttpMcpService } from './streamable-http-mcp-service.js';\nexport {\n defineNodeMcpJsonTool,\n NodeMcpJsonToolset,\n NodeMcpJsonToolsetConfigurationError,\n} from './json-toolset.js';\nexport type {\n AnyNodeMcpJsonToolDefinition,\n NodeMcpJsonToolDefinition,\n NodeMcpJsonToolExecutionContext,\n NodeMcpJsonToolsetConfig,\n NodeMcpToolRegistrationContext,\n NodeMcpToolset,\n NodeStreamableHttpMcpServiceConfig,\n} from './types.js';\n"]}
@@ -0,0 +1,23 @@
1
+ import type { NodeMcpJsonToolDefinition, NodeMcpJsonToolsetConfig, NodeMcpToolRegistrationContext, NodeMcpToolset } from './types.js';
2
+ export declare class NodeMcpJsonToolsetConfigurationError extends Error {
3
+ readonly name = "NodeMcpJsonToolsetConfigurationError";
4
+ }
5
+ /** Preserves a definition's inferred input type without adding runtime work. */
6
+ export declare function defineNodeMcpJsonTool<TTool extends string, TInput extends Record<string, unknown>>(definition: NodeMcpJsonToolDefinition<TTool, TInput>): NodeMcpJsonToolDefinition<TTool, TInput>;
7
+ /**
8
+ * Capability-aware declarative tool registry for the common JSON-tool path.
9
+ *
10
+ * The signed capability is the only source of exposed tool names. Every call
11
+ * checks authority before and after product work and converts unknown failures
12
+ * into the definition's static public message.
13
+ */
14
+ export declare class NodeMcpJsonToolset<TTool extends string> implements NodeMcpToolset<TTool> {
15
+ #private;
16
+ readonly serverInfo: Readonly<{
17
+ name: string;
18
+ version: string;
19
+ }>;
20
+ constructor(config: NodeMcpJsonToolsetConfig<TTool>);
21
+ registerAllowedTools(context: NodeMcpToolRegistrationContext<TTool>): void;
22
+ }
23
+ //# sourceMappingURL=json-toolset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-toolset.d.ts","sourceRoot":"","sources":["../../../src/mcp/node/json-toolset.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,yBAAyB,EACzB,wBAAwB,EACxB,8BAA8B,EAC9B,cAAc,EACf,MAAM,YAAY,CAAC;AAQpB,qBAAa,oCAAqC,SAAQ,KAAK;IAC7D,QAAQ,CAAC,IAAI,0CAA0C;CACxD;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,CACnC,KAAK,SAAS,MAAM,EACpB,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAEtC,UAAU,EAAE,yBAAyB,CAAC,KAAK,EAAE,MAAM,CAAC,GACnD,yBAAyB,CAAC,KAAK,EAAE,MAAM,CAAC,CAE1C;AAED;;;;;;GAMG;AACH,qBAAa,kBAAkB,CAAC,KAAK,SAAS,MAAM,CACpD,YAAW,cAAc,CAAC,KAAK,CAAC;;IAC9B,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;gBAIrD,MAAM,EAAE,wBAAwB,CAAC,KAAK,CAAC;IAsBnD,oBAAoB,CAClB,OAAO,EAAE,8BAA8B,CAAC,KAAK,CAAC,GAC7C,IAAI;CAgER"}
@@ -0,0 +1,94 @@
1
+ import { z } from 'zod';
2
+ import { assertMcpCapabilityActive, McpCapabilityVerificationError, } from '../index.js';
3
+ const ToolDefinitionSchema = z.object({
4
+ name: z.string().min(1).max(64).regex(/^[A-Za-z][A-Za-z0-9_]*$/),
5
+ description: z.string().trim().min(1).max(4_096),
6
+ failureMessage: z.string().trim().min(1).max(1_600),
7
+ }).passthrough();
8
+ export class NodeMcpJsonToolsetConfigurationError extends Error {
9
+ name = 'NodeMcpJsonToolsetConfigurationError';
10
+ }
11
+ /** Preserves a definition's inferred input type without adding runtime work. */
12
+ export function defineNodeMcpJsonTool(definition) {
13
+ return definition;
14
+ }
15
+ /**
16
+ * Capability-aware declarative tool registry for the common JSON-tool path.
17
+ *
18
+ * The signed capability is the only source of exposed tool names. Every call
19
+ * checks authority before and after product work and converts unknown failures
20
+ * into the definition's static public message.
21
+ */
22
+ export class NodeMcpJsonToolset {
23
+ serverInfo;
24
+ #tools;
25
+ #now;
26
+ constructor(config) {
27
+ this.serverInfo = Object.freeze({
28
+ name: z.string().trim().min(1).max(128).parse(config.serverInfo.name),
29
+ version: z.string().trim().min(1).max(128).parse(config.serverInfo.version),
30
+ });
31
+ const definitions = config.tools.map((definition) => {
32
+ ToolDefinitionSchema.parse(definition);
33
+ return definition;
34
+ });
35
+ const names = definitions.map(({ name }) => name);
36
+ if (new Set(names).size !== names.length) {
37
+ throw new NodeMcpJsonToolsetConfigurationError('Node MCP JSON tool names must be unique.');
38
+ }
39
+ this.#tools = new Map(definitions.map((definition) => [
40
+ definition.name,
41
+ definition,
42
+ ]));
43
+ this.#now = config.now ?? (() => new Date());
44
+ }
45
+ registerAllowedTools(context) {
46
+ context.capability.allowedTools.forEach((toolName) => {
47
+ const definition = this.#tools.get(toolName);
48
+ if (!definition) {
49
+ throw new NodeMcpJsonToolsetConfigurationError('The signed MCP capability names an unconfigured product tool.');
50
+ }
51
+ context.server.registerTool(definition.name, {
52
+ ...(definition.title ? { title: definition.title } : {}),
53
+ description: definition.description,
54
+ inputSchema: definition.inputSchema,
55
+ ...(definition.annotations
56
+ ? { annotations: definition.annotations }
57
+ : {}),
58
+ }, async (input, extra) => await this.#execute(definition, input, context, extra.signal));
59
+ });
60
+ }
61
+ async #execute(definition, input, context, operationSignal) {
62
+ const signal = AbortSignal.any([
63
+ context.requestSignal,
64
+ operationSignal,
65
+ ]);
66
+ try {
67
+ signal.throwIfAborted();
68
+ assertMcpCapabilityActive(context.capability, this.#now());
69
+ const result = await definition.execute(input, {
70
+ capability: context.capability,
71
+ signal,
72
+ });
73
+ signal.throwIfAborted();
74
+ assertMcpCapabilityActive(context.capability, this.#now());
75
+ const text = JSON.stringify(result);
76
+ if (text === undefined) {
77
+ throw new TypeError('MCP JSON tools must return a serializable value.');
78
+ }
79
+ return { content: [{ type: 'text', text }] };
80
+ }
81
+ catch (error) {
82
+ const message = signal.aborted
83
+ ? 'Product tool execution was cancelled.'
84
+ : error instanceof McpCapabilityVerificationError
85
+ ? 'Product tool authority expired.'
86
+ : definition.failureMessage;
87
+ return {
88
+ isError: true,
89
+ content: [{ type: 'text', text: message }],
90
+ };
91
+ }
92
+ }
93
+ }
94
+ //# sourceMappingURL=json-toolset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-toolset.js","sourceRoot":"","sources":["../../../src/mcp/node/json-toolset.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { z } from 'zod';\nimport {\n assertMcpCapabilityActive,\n McpCapabilityVerificationError,\n} from '../index.js';\nimport type {\n AnyNodeMcpJsonToolDefinition,\n NodeMcpJsonToolDefinition,\n NodeMcpJsonToolsetConfig,\n NodeMcpToolRegistrationContext,\n NodeMcpToolset,\n} from './types.js';\n\nconst ToolDefinitionSchema = z.object({\n name: z.string().min(1).max(64).regex(/^[A-Za-z][A-Za-z0-9_]*$/),\n description: z.string().trim().min(1).max(4_096),\n failureMessage: z.string().trim().min(1).max(1_600),\n}).passthrough();\n\nexport class NodeMcpJsonToolsetConfigurationError extends Error {\n readonly name = 'NodeMcpJsonToolsetConfigurationError';\n}\n\n/** Preserves a definition's inferred input type without adding runtime work. */\nexport function defineNodeMcpJsonTool<\n TTool extends string,\n TInput extends Record<string, unknown>,\n>(\n definition: NodeMcpJsonToolDefinition<TTool, TInput>,\n): NodeMcpJsonToolDefinition<TTool, TInput> {\n return definition;\n}\n\n/**\n * Capability-aware declarative tool registry for the common JSON-tool path.\n *\n * The signed capability is the only source of exposed tool names. Every call\n * checks authority before and after product work and converts unknown failures\n * into the definition's static public message.\n */\nexport class NodeMcpJsonToolset<TTool extends string>\nimplements NodeMcpToolset<TTool> {\n readonly serverInfo: Readonly<{ name: string; version: string }>;\n readonly #tools: ReadonlyMap<TTool, AnyNodeMcpJsonToolDefinition<TTool>>;\n readonly #now: () => Date;\n\n constructor(config: NodeMcpJsonToolsetConfig<TTool>) {\n this.serverInfo = Object.freeze({\n name: z.string().trim().min(1).max(128).parse(config.serverInfo.name),\n version: z.string().trim().min(1).max(128).parse(config.serverInfo.version),\n });\n const definitions = config.tools.map((definition) => {\n ToolDefinitionSchema.parse(definition);\n return definition;\n });\n const names = definitions.map(({ name }) => name);\n if (new Set(names).size !== names.length) {\n throw new NodeMcpJsonToolsetConfigurationError(\n 'Node MCP JSON tool names must be unique.',\n );\n }\n this.#tools = new Map(definitions.map((definition) => [\n definition.name,\n definition,\n ]));\n this.#now = config.now ?? (() => new Date());\n }\n\n registerAllowedTools(\n context: NodeMcpToolRegistrationContext<TTool>,\n ): void {\n context.capability.allowedTools.forEach((toolName) => {\n const definition = this.#tools.get(toolName);\n if (!definition) {\n throw new NodeMcpJsonToolsetConfigurationError(\n 'The signed MCP capability names an unconfigured product tool.',\n );\n }\n context.server.registerTool(\n definition.name,\n {\n ...(definition.title ? { title: definition.title } : {}),\n description: definition.description,\n inputSchema: definition.inputSchema,\n ...(definition.annotations\n ? { annotations: definition.annotations }\n : {}),\n },\n async (input, extra) => await this.#execute(\n definition,\n input as Record<string, unknown>,\n context,\n extra.signal,\n ),\n );\n });\n }\n\n async #execute(\n definition: AnyNodeMcpJsonToolDefinition<TTool>,\n input: Record<string, unknown>,\n context: NodeMcpToolRegistrationContext<TTool>,\n operationSignal: AbortSignal,\n ): Promise<CallToolResult> {\n const signal = AbortSignal.any([\n context.requestSignal,\n operationSignal,\n ]);\n try {\n signal.throwIfAborted();\n assertMcpCapabilityActive(context.capability, this.#now());\n const result = await definition.execute(input, {\n capability: context.capability,\n signal,\n });\n signal.throwIfAborted();\n assertMcpCapabilityActive(context.capability, this.#now());\n const text = JSON.stringify(result);\n if (text === undefined) {\n throw new TypeError('MCP JSON tools must return a serializable value.');\n }\n return { content: [{ type: 'text', text }] };\n } catch (error) {\n const message = signal.aborted\n ? 'Product tool execution was cancelled.'\n : error instanceof McpCapabilityVerificationError\n ? 'Product tool authority expired.'\n : definition.failureMessage;\n return {\n isError: true,\n content: [{ type: 'text', text: message }],\n };\n }\n }\n}\n"]}
@@ -0,0 +1,18 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import type { NodeStreamableHttpMcpServiceConfig } from './types.js';
3
+ /**
4
+ * Stateless official-SDK Streamable HTTP edge for adopter-owned MCP tools.
5
+ *
6
+ * Every request verifies the capability independently and owns fresh SDK
7
+ * resources. The injected toolset remains the sole owner of model-visible
8
+ * names, schemas, descriptions, and product operations.
9
+ */
10
+ export declare class NodeStreamableHttpMcpService<TTool extends string> {
11
+ #private;
12
+ constructor(config: NodeStreamableHttpMcpServiceConfig<TTool>);
13
+ /** Handles one authenticated stateless MCP request at an adopter-owned path. */
14
+ handle(request: IncomingMessage, response: ServerResponse): Promise<void>;
15
+ /** Aborts active tools and closes their official SDK resources. */
16
+ close(): Promise<void>;
17
+ }
18
+ //# sourceMappingURL=streamable-http-mcp-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamable-http-mcp-service.d.ts","sourceRoot":"","sources":["../../../src/mcp/node/streamable-http-mcp-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAQjE,OAAO,KAAK,EACV,kCAAkC,EACnC,MAAM,YAAY,CAAC;AAqBpB;;;;;;GAMG;AACH,qBAAa,4BAA4B,CAAC,KAAK,SAAS,MAAM;;gBAUhD,MAAM,EAAE,kCAAkC,CAAC,KAAK,CAAC;IAQ7D,gFAAgF;IAC1E,MAAM,CACV,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC;IA+EhB,mEAAmE;IACnE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAuDvB"}