toolcraft 0.0.232 → 0.0.233

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 (180) hide show
  1. package/composition.json +3 -3
  2. package/dist/applied-default.d.ts +3 -0
  3. package/dist/applied-default.js +16 -0
  4. package/dist/cli.js +508 -204
  5. package/dist/composition.json +3 -3
  6. package/dist/discriminator.d.ts +9 -0
  7. package/dist/discriminator.js +32 -0
  8. package/dist/error-report.d.ts +2 -18
  9. package/dist/error-report.js +12 -14
  10. package/dist/http.js +8 -1
  11. package/dist/human-in-loop/gate.js +6 -0
  12. package/dist/index.compile-check.js +22 -5
  13. package/dist/index.d.ts +12 -5
  14. package/dist/index.js +50 -0
  15. package/dist/json-schema-converter.d.ts +14 -6
  16. package/dist/json-schema-converter.js +150 -20
  17. package/dist/mcp-proxy-metadata.d.ts +2 -0
  18. package/dist/mcp-proxy-metadata.js +13 -0
  19. package/dist/mcp-proxy.d.ts +1 -0
  20. package/dist/mcp-proxy.js +65 -47
  21. package/dist/mcp-result.d.ts +3 -0
  22. package/dist/mcp-result.js +10 -0
  23. package/dist/mcp.js +211 -153
  24. package/dist/redaction.js +26 -17
  25. package/dist/renderer.js +40 -29
  26. package/dist/schema-member-names.d.ts +2 -0
  27. package/dist/schema-member-names.js +39 -0
  28. package/dist/schema-scope.d.ts +1 -0
  29. package/dist/schema-scope.js +29 -16
  30. package/dist/schema.d.ts +1 -1
  31. package/dist/sdk.d.ts +2 -1
  32. package/dist/sdk.js +164 -50
  33. package/dist/stream.js +24 -23
  34. package/dist/testing/diagnostic-value.d.ts +1 -0
  35. package/dist/testing/diagnostic-value.js +57 -0
  36. package/dist/testing/fakes.js +2 -1
  37. package/dist/testing/harness.js +1 -0
  38. package/dist/testing/memory-fs.js +42 -1
  39. package/dist/testing/parity.js +50 -6
  40. package/dist/union-validation.d.ts +5 -0
  41. package/dist/union-validation.js +36 -0
  42. package/node_modules/@poe-code/process-runner/dist/types.d.ts +2 -0
  43. package/node_modules/mcp-oauth-server/dist/index.js +47 -6
  44. package/node_modules/tiny-http-mcp-server/dist/cli.js +14 -2
  45. package/node_modules/tiny-http-mcp-server/dist/composition.json +1 -1
  46. package/node_modules/tiny-http-mcp-server/dist/http-server.d.ts +7 -5
  47. package/node_modules/tiny-http-mcp-server/dist/http-server.js +3 -11
  48. package/node_modules/tiny-http-mcp-server/dist/http-transport.d.ts +6 -1
  49. package/node_modules/tiny-http-mcp-server/dist/http-transport.js +196 -15
  50. package/node_modules/tiny-http-mcp-server/dist/index.d.ts +2 -2
  51. package/node_modules/tiny-http-mcp-server/dist/modern-headers.d.ts +3 -0
  52. package/node_modules/tiny-http-mcp-server/dist/modern-headers.js +35 -0
  53. package/node_modules/tiny-http-mcp-server/dist/parse-body.d.ts +1 -0
  54. package/node_modules/tiny-http-mcp-server/dist/parse-body.js +9 -5
  55. package/node_modules/tiny-http-mcp-server/dist/test-support.js +17 -0
  56. package/node_modules/tiny-http-mcp-server/dist/testing.d.ts +1 -1
  57. package/node_modules/tiny-http-mcp-server/dist/testing.js +3 -2
  58. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/default-oauth-client-provider.js +21 -4
  59. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/token-endpoint.d.ts +1 -1
  60. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/token-endpoint.js +14 -6
  61. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/http-fetch.d.ts +1 -0
  62. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/http-fetch.js +8 -0
  63. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/http-response.d.ts +1 -0
  64. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/http-response.js +50 -0
  65. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/index.d.ts +2 -0
  66. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/index.js +2 -0
  67. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/server/jwks-token-verifier.js +21 -3
  68. package/node_modules/tiny-http-mcp-server/package.json +1 -1
  69. package/node_modules/tiny-mcp-client/README.md +1 -0
  70. package/node_modules/tiny-mcp-client/dist/index.d.ts +178 -101
  71. package/node_modules/tiny-mcp-client/dist/index.js +4696 -291
  72. package/node_modules/tiny-mcp-client/package.json +2 -1
  73. package/node_modules/tiny-stdio-mcp-server/dist/base64.d.ts +1 -0
  74. package/node_modules/tiny-stdio-mcp-server/dist/base64.js +5 -0
  75. package/node_modules/tiny-stdio-mcp-server/dist/composition.json +1 -1
  76. package/node_modules/tiny-stdio-mcp-server/dist/content/audio.d.ts +3 -0
  77. package/node_modules/tiny-stdio-mcp-server/dist/content/convert.d.ts +5 -1
  78. package/node_modules/tiny-stdio-mcp-server/dist/content/convert.js +41 -6
  79. package/node_modules/tiny-stdio-mcp-server/dist/content/file.d.ts +5 -0
  80. package/node_modules/tiny-stdio-mcp-server/dist/content/image.d.ts +3 -0
  81. package/node_modules/tiny-stdio-mcp-server/dist/headers.d.ts +10 -0
  82. package/node_modules/tiny-stdio-mcp-server/dist/headers.js +180 -0
  83. package/node_modules/tiny-stdio-mcp-server/dist/index.d.ts +5 -5
  84. package/node_modules/tiny-stdio-mcp-server/dist/index.js +1 -1
  85. package/node_modules/tiny-stdio-mcp-server/dist/input-request-schema.d.ts +220 -0
  86. package/node_modules/tiny-stdio-mcp-server/dist/input-request-schema.js +1995 -0
  87. package/node_modules/tiny-stdio-mcp-server/dist/jsonrpc.d.ts +1 -0
  88. package/node_modules/tiny-stdio-mcp-server/dist/jsonrpc.js +38 -25
  89. package/node_modules/tiny-stdio-mcp-server/dist/metadata.d.ts +2 -0
  90. package/node_modules/tiny-stdio-mcp-server/dist/metadata.js +37 -0
  91. package/node_modules/tiny-stdio-mcp-server/dist/protocol-validation.d.ts +4 -0
  92. package/node_modules/tiny-stdio-mcp-server/dist/protocol-validation.js +53 -0
  93. package/node_modules/tiny-stdio-mcp-server/dist/protocol.d.ts +17 -0
  94. package/node_modules/tiny-stdio-mcp-server/dist/protocol.js +228 -0
  95. package/node_modules/tiny-stdio-mcp-server/dist/request-cancellation.d.ts +1 -0
  96. package/node_modules/tiny-stdio-mcp-server/dist/request-cancellation.js +18 -0
  97. package/node_modules/tiny-stdio-mcp-server/dist/sampling-messages.d.ts +18 -0
  98. package/node_modules/tiny-stdio-mcp-server/dist/sampling-messages.js +34 -0
  99. package/node_modules/tiny-stdio-mcp-server/dist/schema.d.ts +4 -1
  100. package/node_modules/tiny-stdio-mcp-server/dist/server.d.ts +9 -4
  101. package/node_modules/tiny-stdio-mcp-server/dist/server.js +334 -135
  102. package/node_modules/tiny-stdio-mcp-server/dist/stdio-input.d.ts +3 -0
  103. package/node_modules/tiny-stdio-mcp-server/dist/stdio-input.js +50 -28
  104. package/node_modules/tiny-stdio-mcp-server/dist/subscriptions.d.ts +11 -0
  105. package/node_modules/tiny-stdio-mcp-server/dist/subscriptions.js +128 -0
  106. package/node_modules/tiny-stdio-mcp-server/dist/types.d.ts +58 -18
  107. package/node_modules/tiny-stdio-mcp-server/dist/types.js +2 -1
  108. package/node_modules/tiny-stdio-mcp-server/dist/uri.d.ts +1 -0
  109. package/node_modules/tiny-stdio-mcp-server/dist/uri.js +41 -0
  110. package/node_modules/tiny-stdio-mcp-server/package.json +8 -0
  111. package/node_modules/toolcraft-design/dist/command-registry.d.ts +11 -0
  112. package/node_modules/toolcraft-design/dist/command-registry.js +24 -0
  113. package/node_modules/toolcraft-design/dist/dashboard/ansi.d.ts +2 -0
  114. package/node_modules/toolcraft-design/dist/dashboard/ansi.js +81 -27
  115. package/node_modules/toolcraft-design/dist/dashboard/buffer.js +39 -25
  116. package/node_modules/toolcraft-design/dist/dashboard/components/border.js +6 -5
  117. package/node_modules/toolcraft-design/dist/dashboard/components/footer.js +26 -21
  118. package/node_modules/toolcraft-design/dist/dashboard/components/output-pane.d.ts +1 -1
  119. package/node_modules/toolcraft-design/dist/dashboard/components/output-pane.js +12 -6
  120. package/node_modules/toolcraft-design/dist/dashboard/components/stats-pane.d.ts +2 -1
  121. package/node_modules/toolcraft-design/dist/dashboard/components/stats-pane.js +51 -10
  122. package/node_modules/toolcraft-design/dist/dashboard/dashboard.d.ts +4 -0
  123. package/node_modules/toolcraft-design/dist/dashboard/dashboard.js +77 -4
  124. package/node_modules/toolcraft-design/dist/dashboard/index.d.ts +2 -0
  125. package/node_modules/toolcraft-design/dist/dashboard/index.js +2 -0
  126. package/node_modules/toolcraft-design/dist/dashboard/keymap.js +26 -6
  127. package/node_modules/toolcraft-design/dist/dashboard/layout.d.ts +1 -0
  128. package/node_modules/toolcraft-design/dist/dashboard/layout.js +19 -3
  129. package/node_modules/toolcraft-design/dist/dashboard/line-buffer.d.ts +9 -0
  130. package/node_modules/toolcraft-design/dist/dashboard/line-buffer.js +63 -0
  131. package/node_modules/toolcraft-design/dist/dashboard/output-preview.d.ts +9 -0
  132. package/node_modules/toolcraft-design/dist/dashboard/output-preview.js +70 -0
  133. package/node_modules/toolcraft-design/dist/dashboard/snapshot.js +3 -1
  134. package/node_modules/toolcraft-design/dist/dashboard/store.js +9 -3
  135. package/node_modules/toolcraft-design/dist/dashboard/terminal-strings.d.ts +6 -0
  136. package/node_modules/toolcraft-design/dist/dashboard/terminal-strings.js +108 -0
  137. package/node_modules/toolcraft-design/dist/dashboard/terminal-width.js +3 -1
  138. package/node_modules/toolcraft-design/dist/dashboard/terminal.js +11 -1
  139. package/node_modules/toolcraft-design/dist/dashboard/testing/pipeline-scenario.d.ts +1 -0
  140. package/node_modules/toolcraft-design/dist/dashboard/testing/pipeline-scenario.js +126 -0
  141. package/node_modules/toolcraft-design/dist/dashboard/types.d.ts +3 -1
  142. package/node_modules/toolcraft-design/dist/event-groups.d.ts +19 -0
  143. package/node_modules/toolcraft-design/dist/event-groups.js +49 -0
  144. package/node_modules/toolcraft-design/dist/index.d.ts +6 -1
  145. package/node_modules/toolcraft-design/dist/index.js +5 -1
  146. package/node_modules/toolcraft-design/dist/inline-notice.d.ts +14 -0
  147. package/node_modules/toolcraft-design/dist/inline-notice.js +28 -0
  148. package/node_modules/toolcraft-design/dist/metric.d.ts +8 -0
  149. package/node_modules/toolcraft-design/dist/metric.js +21 -0
  150. package/node_modules/toolcraft-design/dist/overlay-manager.d.ts +6 -0
  151. package/node_modules/toolcraft-design/dist/overlay-manager.js +10 -0
  152. package/node_modules/toolcraft-design/dist/primitives.d.ts +12 -0
  153. package/node_modules/toolcraft-design/dist/primitives.js +7 -0
  154. package/node_modules/toolcraft-design/dist/progress-group.d.ts +7 -0
  155. package/node_modules/toolcraft-design/dist/progress-group.js +10 -0
  156. package/node_modules/toolcraft-design/dist/render-performance.d.ts +33 -0
  157. package/node_modules/toolcraft-design/dist/render-performance.js +71 -0
  158. package/node_modules/toolcraft-design/dist/task-tree.d.ts +22 -0
  159. package/node_modules/toolcraft-design/dist/task-tree.js +79 -0
  160. package/node_modules/toolcraft-design/dist/viewport.d.ts +18 -0
  161. package/node_modules/toolcraft-design/dist/viewport.js +56 -0
  162. package/node_modules/toolcraft-schema/dist/clone-default.d.ts +1 -0
  163. package/node_modules/toolcraft-schema/dist/clone-default.js +26 -0
  164. package/node_modules/toolcraft-schema/dist/index.compile-check.js +1 -0
  165. package/node_modules/toolcraft-schema/dist/index.d.ts +18 -9
  166. package/node_modules/toolcraft-schema/dist/index.js +46 -8
  167. package/node_modules/toolcraft-schema/dist/json-schema/compiler.d.ts +1 -0
  168. package/node_modules/toolcraft-schema/dist/json-schema/compiler.js +6 -0
  169. package/node_modules/toolcraft-schema/dist/json-schema/evaluate.js +6 -3
  170. package/node_modules/toolcraft-schema/dist/json-schema/normalize-nullability.d.ts +1 -0
  171. package/node_modules/toolcraft-schema/dist/json-schema/normalize-nullability.js +69 -0
  172. package/node_modules/toolcraft-schema/dist/json-schema/types.d.ts +1 -0
  173. package/node_modules/toolcraft-schema/dist/json.d.ts +4 -1
  174. package/node_modules/toolcraft-schema/dist/json.js +57 -1
  175. package/node_modules/toolcraft-schema/dist/native-json-schema.d.ts +10 -0
  176. package/node_modules/toolcraft-schema/dist/native-json-schema.js +11 -0
  177. package/node_modules/toolcraft-schema/dist/validate.d.ts +5 -1
  178. package/node_modules/toolcraft-schema/dist/validate.js +61 -47
  179. package/node_modules/toolcraft-schema/package.json +1 -1
  180. package/package.json +6 -3
@@ -1,4 +1,5 @@
1
1
  import type { JSONRPCRequest, JSONRPCError, JSONRPCNotification } from "./types.js";
2
+ export declare function isRequestId(value: unknown): value is string | number;
2
3
  export interface ParseResult {
3
4
  success: true;
4
5
  request: JSONRPCRequest | JSONRPCNotification;
@@ -1,4 +1,8 @@
1
1
  import { JSON_RPC_ERROR_CODES } from "./types.js";
2
+ import { MODERN_PROTOCOL_VERSION } from "./protocol.js";
3
+ export function isRequestId(value) {
4
+ return typeof value === "string" || (typeof value === "number" && Number.isSafeInteger(value));
5
+ }
2
6
  export function parseMessage(line) {
3
7
  let parsed;
4
8
  try {
@@ -9,24 +13,35 @@ export function parseMessage(line) {
9
13
  success: false,
10
14
  error: {
11
15
  code: JSON_RPC_ERROR_CODES.PARSE_ERROR,
12
- message: "Parse error",
16
+ message: "Parse error"
13
17
  },
14
- id: null,
18
+ id: null
15
19
  };
16
20
  }
17
- if (typeof parsed !== "object" ||
18
- parsed === null ||
19
- Array.isArray(parsed)) {
21
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
20
22
  return {
21
23
  success: false,
22
24
  error: {
23
25
  code: JSON_RPC_ERROR_CODES.INVALID_REQUEST,
24
- message: "Invalid Request",
26
+ message: "Invalid Request"
25
27
  },
26
- id: null,
28
+ id: null
27
29
  };
28
30
  }
29
31
  const obj = parsed;
32
+ const metadata = obj.params?._meta;
33
+ if (typeof metadata === "object" &&
34
+ metadata !== null &&
35
+ metadata["io.modelcontextprotocol/protocolVersion"] ===
36
+ MODERN_PROTOCOL_VERSION &&
37
+ "id" in obj &&
38
+ !isRequestId(obj.id)) {
39
+ return {
40
+ success: false,
41
+ error: { code: JSON_RPC_ERROR_CODES.INVALID_REQUEST, message: "Invalid Request ID" },
42
+ id: null
43
+ };
44
+ }
30
45
  const hasId = "id" in obj;
31
46
  const id = typeof obj.id === "string"
32
47
  ? obj.id
@@ -35,17 +50,15 @@ export function parseMessage(line) {
35
50
  : obj.id === null
36
51
  ? null
37
52
  : null;
38
- if ("params" in obj
39
- && (typeof obj.params !== "object"
40
- || obj.params === null
41
- || Array.isArray(obj.params))) {
53
+ if ("params" in obj &&
54
+ (typeof obj.params !== "object" || obj.params === null || Array.isArray(obj.params))) {
42
55
  return {
43
56
  success: false,
44
57
  error: {
45
58
  code: JSON_RPC_ERROR_CODES.INVALID_REQUEST,
46
- message: "Invalid Request",
59
+ message: "Invalid Request"
47
60
  },
48
- id,
61
+ id
49
62
  };
50
63
  }
51
64
  if (obj.jsonrpc !== "2.0") {
@@ -53,9 +66,9 @@ export function parseMessage(line) {
53
66
  success: false,
54
67
  error: {
55
68
  code: JSON_RPC_ERROR_CODES.INVALID_REQUEST,
56
- message: "Invalid Request",
69
+ message: "Invalid Request"
57
70
  },
58
- id,
71
+ id
59
72
  };
60
73
  }
61
74
  if (typeof obj.method !== "string") {
@@ -63,9 +76,9 @@ export function parseMessage(line) {
63
76
  success: false,
64
77
  error: {
65
78
  code: JSON_RPC_ERROR_CODES.INVALID_REQUEST,
66
- message: "Invalid Request",
79
+ message: "Invalid Request"
67
80
  },
68
- id,
81
+ id
69
82
  };
70
83
  }
71
84
  if (!hasId) {
@@ -75,8 +88,8 @@ export function parseMessage(line) {
75
88
  request: {
76
89
  jsonrpc: "2.0",
77
90
  method: obj.method,
78
- params: obj.params,
79
- },
91
+ params: obj.params
92
+ }
80
93
  };
81
94
  }
82
95
  if (obj.id !== null && id === null) {
@@ -84,9 +97,9 @@ export function parseMessage(line) {
84
97
  success: false,
85
98
  error: {
86
99
  code: JSON_RPC_ERROR_CODES.INVALID_REQUEST,
87
- message: "Invalid Request",
100
+ message: "Invalid Request"
88
101
  },
89
- id: null,
102
+ id: null
90
103
  };
91
104
  }
92
105
  return {
@@ -96,15 +109,15 @@ export function parseMessage(line) {
96
109
  jsonrpc: "2.0",
97
110
  id,
98
111
  method: obj.method,
99
- params: obj.params,
100
- },
112
+ params: obj.params
113
+ }
101
114
  };
102
115
  }
103
116
  export function formatSuccessResponse(id, result) {
104
117
  const response = {
105
118
  jsonrpc: "2.0",
106
119
  id,
107
- result,
120
+ result
108
121
  };
109
122
  return JSON.stringify(response);
110
123
  }
@@ -112,7 +125,7 @@ export function formatErrorResponse(id, error) {
112
125
  const response = {
113
126
  jsonrpc: "2.0",
114
127
  id,
115
- error,
128
+ error
116
129
  };
117
130
  return JSON.stringify(response);
118
131
  }
@@ -0,0 +1,2 @@
1
+ export declare function isValidMetadataKey(key: string): boolean;
2
+ export declare function isValidMetadata(value: unknown): value is Record<string, unknown>;
@@ -0,0 +1,37 @@
1
+ import { isJsonValue } from "toolcraft-schema";
2
+ function isLetter(code) {
3
+ return (code >= 0x41 && code <= 0x5a) || (code >= 0x61 && code <= 0x7a);
4
+ }
5
+ function isAlphanumeric(code) {
6
+ return isLetter(code) || (code >= 0x30 && code <= 0x39);
7
+ }
8
+ export function isValidMetadataKey(key) {
9
+ const slash = key.indexOf("/");
10
+ let name = key;
11
+ if (slash !== -1) {
12
+ if (key.indexOf("/", slash + 1) !== -1)
13
+ return false;
14
+ for (const label of key.slice(0, slash).split(".")) {
15
+ if (label.length === 0 || !isLetter(label.charCodeAt(0)) || !isAlphanumeric(label.charCodeAt(label.length - 1)))
16
+ return false;
17
+ for (let index = 1; index < label.length - 1; index++) {
18
+ if (!isAlphanumeric(label.charCodeAt(index)) && label[index] !== "-")
19
+ return false;
20
+ }
21
+ }
22
+ name = key.slice(slash + 1);
23
+ }
24
+ if (name.length === 0)
25
+ return true;
26
+ if (!isAlphanumeric(name.charCodeAt(0)) || !isAlphanumeric(name.charCodeAt(name.length - 1)))
27
+ return false;
28
+ for (let index = 1; index < name.length - 1; index++) {
29
+ if (!isAlphanumeric(name.charCodeAt(index)) && name[index] !== "-" && name[index] !== "_" && name[index] !== ".")
30
+ return false;
31
+ }
32
+ return true;
33
+ }
34
+ export function isValidMetadata(value) {
35
+ return typeof value === "object" && value !== null && !Array.isArray(value)
36
+ && isJsonValue(value) && Object.keys(value).every(isValidMetadataKey);
37
+ }
@@ -0,0 +1,4 @@
1
+ type ProtocolDefinition = "InputRequest" | "InputResponses" | "ClientCapabilities" | "ElicitResult" | "CreateMessageResult" | "ListRootsResult" | "DiscoverResult" | "ListToolsResult" | "CallToolResult" | "ListPromptsResult" | "GetPromptResult" | "ListResourcesResult" | "ListResourceTemplatesResult" | "ReadResourceResult" | "CompleteResult" | "Result";
2
+ export declare function validateServerResult(method: string, value: unknown): boolean;
3
+ export declare function validateProtocolValue(definition: ProtocolDefinition, value: unknown): boolean;
4
+ export {};
@@ -0,0 +1,53 @@
1
+ import { isBase64 } from "./base64.js";
2
+ import { isValidMetadataKey } from "./metadata.js";
3
+ import { isValidUri } from "./uri.js";
4
+ import { compileJsonSchema } from "toolcraft-schema";
5
+ import { inputRequestSchema } from "./input-request-schema.js";
6
+ import { isJsonValue } from "toolcraft-schema";
7
+ const validators = new Map();
8
+ const protocolSchema = structuredClone(inputRequestSchema);
9
+ const protocolDefinitions = protocolSchema.$defs;
10
+ for (const definition of ["MetaObject", "ResultMetaObject"]) {
11
+ Object.assign(protocolDefinitions[definition], { propertyNames: { format: "mcp-metadata-key" } });
12
+ }
13
+ for (const definition of ["ClientCapabilities", "ServerCapabilities"]) {
14
+ const properties = protocolDefinitions[definition].properties;
15
+ Object.assign(properties.extensions, { propertyNames: { format: "mcp-extension-key" } });
16
+ }
17
+ const resultDefinitions = {
18
+ "server/discover": "DiscoverResult",
19
+ "tools/list": "ListToolsResult",
20
+ "tools/call": "CallToolResult",
21
+ "prompts/list": "ListPromptsResult",
22
+ "prompts/get": "GetPromptResult",
23
+ "resources/list": "ListResourcesResult",
24
+ "resources/templates/list": "ListResourceTemplatesResult",
25
+ "resources/read": "ReadResourceResult",
26
+ "completion/complete": "CompleteResult",
27
+ "ping": "Result",
28
+ "logging/setLevel": "Result"
29
+ };
30
+ export function validateServerResult(method, value) {
31
+ const definition = Object.hasOwn(resultDefinitions, method) ? resultDefinitions[method] : undefined;
32
+ return definition === undefined || validateProtocolValue(definition, value);
33
+ }
34
+ export function validateProtocolValue(definition, value) {
35
+ if (!isJsonValue(value))
36
+ return false;
37
+ if (definition === "ListRootsResult" && typeof value === "object" && value !== null &&
38
+ Array.isArray(value.roots) &&
39
+ !value.roots.every((root) => typeof root?.uri === "string" && root.uri.startsWith("file://") && isValidUri(root.uri)))
40
+ return false;
41
+ let validator = validators.get(definition);
42
+ if (validator === undefined) {
43
+ validator = compileJsonSchema({ ...protocolSchema, $ref: `#/$defs/${definition}` }, {
44
+ formats: {
45
+ "mcp-metadata-key": isValidMetadataKey,
46
+ "mcp-extension-key": (key) => key.includes("/") && isValidMetadataKey(key),
47
+ uri: isValidUri, byte: isBase64
48
+ }
49
+ });
50
+ validators.set(definition, validator);
51
+ }
52
+ return validator.validate(value).ok;
53
+ }
@@ -0,0 +1,17 @@
1
+ import { type HandleResult, type JSONRPCError } from "./types.js";
2
+ export declare const MODERN_PROTOCOL_VERSION = "2026-07-28";
3
+ export declare function selectRequestProtocol(method: string, params: Record<string, unknown> | undefined, legacyVersions: ReadonlySet<string>): {
4
+ modern: boolean;
5
+ error?: JSONRPCError;
6
+ };
7
+ export declare function validateInputRequiredResult(method: string, value: Record<string, unknown>, clientCapabilities: Record<string, unknown>): HandleResult | undefined;
8
+ export declare function validateCacheMetadata(method: string, value: Record<string, unknown>): string | undefined;
9
+ export declare function decorateModernResult(method: string, handled: HandleResult, serverInfo: {
10
+ name: string;
11
+ version: string;
12
+ }, clientCapabilities?: Record<string, unknown>): HandleResult;
13
+ export { validateProtocolValue, validateServerResult } from "./protocol-validation.js";
14
+ export { isJsonValue } from "toolcraft-schema";
15
+ export { isBase64 } from "./base64.js";
16
+ export { isValidUri } from "./uri.js";
17
+ export { isValidMetadata } from "./metadata.js";
@@ -0,0 +1,228 @@
1
+ import { isValidMetadata } from "./metadata.js";
2
+ import { JSON_RPC_ERROR_CODES } from "./types.js";
3
+ import { isJsonValue } from "toolcraft-schema";
4
+ import { validateProtocolValue } from "./protocol-validation.js";
5
+ import { inspectSamplingMessages } from "./sampling-messages.js";
6
+ export const MODERN_PROTOCOL_VERSION = "2026-07-28";
7
+ const removedMethods = new Set([
8
+ "initialize",
9
+ "notifications/initialized",
10
+ "ping",
11
+ "logging/setLevel",
12
+ "resources/subscribe",
13
+ "resources/unsubscribe",
14
+ "notifications/roots/list_changed"
15
+ ]);
16
+ const cacheableMethods = new Set([
17
+ "server/discover",
18
+ "tools/list",
19
+ "prompts/list",
20
+ "resources/list",
21
+ "resources/templates/list",
22
+ "resources/read"
23
+ ]);
24
+ const inputRequiredMethods = new Set(["tools/call", "prompts/get", "resources/read"]);
25
+ const inputRequestCapabilities = {
26
+ "roots/list": "roots",
27
+ "sampling/createMessage": "sampling",
28
+ "elicitation/create": "elicitation"
29
+ };
30
+ function isRecord(value) {
31
+ return typeof value === "object" && value !== null && !Array.isArray(value);
32
+ }
33
+ export function selectRequestProtocol(method, params, legacyVersions) {
34
+ const invalid = {
35
+ modern: false,
36
+ error: {
37
+ code: JSON_RPC_ERROR_CODES.INVALID_PARAMS,
38
+ message: "Request metadata must include protocolVersion and clientCapabilities"
39
+ }
40
+ };
41
+ const property = Object.getOwnPropertyDescriptor(params ?? {}, "_meta");
42
+ if (property === undefined || property.enumerable !== true)
43
+ return method === "server/discover" ? invalid : { modern: false };
44
+ if (!("value" in property))
45
+ return invalid;
46
+ const metadata = property.value;
47
+ if (!isRecord(metadata))
48
+ return invalid;
49
+ if (!isValidMetadata(metadata))
50
+ return { modern: false, error: {
51
+ code: JSON_RPC_ERROR_CODES.INVALID_PARAMS, message: "Invalid MCP metadata keys"
52
+ } };
53
+ const versionKey = "io.modelcontextprotocol/protocolVersion";
54
+ const capabilitiesKey = "io.modelcontextprotocol/clientCapabilities";
55
+ if (!(versionKey in metadata) && !(capabilitiesKey in metadata) && method !== "server/discover") {
56
+ return { modern: false };
57
+ }
58
+ const version = metadata[versionKey];
59
+ if (!Object.prototype.hasOwnProperty.call(metadata, versionKey) ||
60
+ typeof version !== "string" ||
61
+ !Object.prototype.hasOwnProperty.call(metadata, capabilitiesKey) ||
62
+ !isRecord(metadata[capabilitiesKey]))
63
+ return invalid;
64
+ if (version !== MODERN_PROTOCOL_VERSION && !legacyVersions.has(version)) {
65
+ return {
66
+ modern: false,
67
+ error: {
68
+ code: JSON_RPC_ERROR_CODES.UNSUPPORTED_PROTOCOL_VERSION,
69
+ message: "Unsupported protocol version",
70
+ data: { requested: version, supported: [...legacyVersions].reverse() }
71
+ }
72
+ };
73
+ }
74
+ const modern = version === MODERN_PROTOCOL_VERSION;
75
+ if (modern && !validateProtocolValue("ClientCapabilities", metadata[capabilitiesKey])) {
76
+ return { modern, error: {
77
+ code: JSON_RPC_ERROR_CODES.INVALID_PARAMS, message: "Invalid MCP clientCapabilities"
78
+ } };
79
+ }
80
+ if (modern &&
81
+ ((params?.requestState !== undefined && typeof params.requestState !== "string") ||
82
+ (params?.inputResponses !== undefined && !validateProtocolValue("InputResponses", params.inputResponses)))) {
83
+ return {
84
+ modern,
85
+ error: { code: JSON_RPC_ERROR_CODES.INVALID_PARAMS, message: "Invalid MCP retry parameters" }
86
+ };
87
+ }
88
+ if (modern && removedMethods.has(method)) {
89
+ return {
90
+ modern,
91
+ error: { code: JSON_RPC_ERROR_CODES.METHOD_NOT_FOUND, message: "Method not found" }
92
+ };
93
+ }
94
+ return { modern };
95
+ }
96
+ export function validateInputRequiredResult(method, value, clientCapabilities) {
97
+ const requests = value.inputRequests;
98
+ const requiredCapabilities = {};
99
+ const invalidRequests = requests !== undefined &&
100
+ (!isRecord(requests) || !isJsonValue(requests) ||
101
+ Object.values(requests).some((request) => {
102
+ if (!isRecord(request) || typeof request.method !== "string")
103
+ return true;
104
+ if (!validateProtocolValue("InputRequest", request))
105
+ return true;
106
+ const sampling = request.method === "sampling/createMessage"
107
+ ? inspectSamplingMessages(request.params.messages)
108
+ : undefined;
109
+ if (sampling?.valid === false)
110
+ return true;
111
+ if (request.method === "elicitation/create" &&
112
+ request.params.mode === "url") {
113
+ try {
114
+ new URL(request.params.url);
115
+ }
116
+ catch {
117
+ return true;
118
+ }
119
+ }
120
+ const capability = Object.prototype.hasOwnProperty.call(inputRequestCapabilities, request.method)
121
+ ? inputRequestCapabilities[request.method]
122
+ : undefined;
123
+ if (capability === undefined || (request.params !== undefined && !isRecord(request.params)))
124
+ return true;
125
+ const supported = Object.prototype.hasOwnProperty.call(clientCapabilities, capability)
126
+ ? clientCapabilities[capability] : undefined;
127
+ if (!isRecord(supported))
128
+ requiredCapabilities[capability] = {};
129
+ else if (capability === "elicitation") {
130
+ const mode = request.params.mode ?? "form";
131
+ const implicitForm = mode === "form" && Object.keys(supported).length === 0;
132
+ if (!implicitForm && (typeof mode !== "string" ||
133
+ !Object.prototype.hasOwnProperty.call(supported, mode) || !isRecord(supported[mode]))) {
134
+ const required = requiredCapabilities.elicitation ??= {};
135
+ required[String(mode)] = {};
136
+ }
137
+ }
138
+ else if (capability === "sampling") {
139
+ const params = request.params;
140
+ if ((params.tools !== undefined || params.toolChoice !== undefined || sampling?.usesTools === true) &&
141
+ (!Object.prototype.hasOwnProperty.call(supported, "tools") || !isRecord(supported.tools))) {
142
+ const required = requiredCapabilities.sampling ??= {};
143
+ required.tools = {};
144
+ }
145
+ }
146
+ return false;
147
+ }));
148
+ if (!inputRequiredMethods.has(method) ||
149
+ (requests === undefined && value.requestState === undefined) ||
150
+ (value.requestState !== undefined && typeof value.requestState !== "string") ||
151
+ invalidRequests) {
152
+ return {
153
+ error: {
154
+ code: JSON_RPC_ERROR_CODES.INTERNAL_ERROR,
155
+ message: "Invalid MCP input_required result"
156
+ }
157
+ };
158
+ }
159
+ if (Object.keys(requiredCapabilities).length > 0) {
160
+ return { error: {
161
+ code: -32021,
162
+ message: "Missing required client capability",
163
+ data: { requiredCapabilities }
164
+ } };
165
+ }
166
+ }
167
+ export function validateCacheMetadata(method, value) {
168
+ if (!cacheableMethods.has(method))
169
+ return undefined;
170
+ if (!Number.isSafeInteger(value.ttlMs) || value.ttlMs < 0) {
171
+ return "MCP cache ttlMs must be a nonnegative safe integer";
172
+ }
173
+ if (value.cacheScope !== "public" && value.cacheScope !== "private") {
174
+ return "MCP cacheScope must be public or private";
175
+ }
176
+ return undefined;
177
+ }
178
+ export function decorateModernResult(method, handled, serverInfo, clientCapabilities = {}) {
179
+ if (handled.error !== undefined) {
180
+ return handled.error.code === JSON_RPC_ERROR_CODES.RESOURCE_NOT_FOUND
181
+ ? { error: { ...handled.error, code: JSON_RPC_ERROR_CODES.INVALID_PARAMS } }
182
+ : handled;
183
+ }
184
+ if (handled.result === undefined && method.startsWith("notifications/"))
185
+ return handled;
186
+ const value = handled.result;
187
+ if (!isRecord(value))
188
+ return {
189
+ error: {
190
+ code: JSON_RPC_ERROR_CODES.INTERNAL_ERROR,
191
+ message: "MCP result must be an object"
192
+ }
193
+ };
194
+ if (value.resultType !== undefined &&
195
+ value.resultType !== "complete" &&
196
+ value.resultType !== "input_required") {
197
+ return {
198
+ error: { code: JSON_RPC_ERROR_CODES.INTERNAL_ERROR, message: "Unrecognized MCP resultType" }
199
+ };
200
+ }
201
+ if (value.resultType === "input_required") {
202
+ const invalid = validateInputRequiredResult(method, value, clientCapabilities);
203
+ if (invalid !== undefined)
204
+ return invalid;
205
+ }
206
+ const result = {
207
+ ...value,
208
+ resultType: value.resultType ?? "complete",
209
+ _meta: {
210
+ ...(isRecord(value._meta) ? value._meta : {}),
211
+ "io.modelcontextprotocol/serverInfo": { ...serverInfo }
212
+ }
213
+ };
214
+ if (cacheableMethods.has(method) && result.resultType === "complete") {
215
+ const cacheableResult = { ...result, ttlMs: value.ttlMs === undefined ? 0 : value.ttlMs, cacheScope: value.cacheScope === undefined ? "private" : value.cacheScope };
216
+ const cacheError = validateCacheMetadata(method, cacheableResult);
217
+ if (cacheError !== undefined) {
218
+ return { error: { code: JSON_RPC_ERROR_CODES.INTERNAL_ERROR, message: cacheError } };
219
+ }
220
+ return { result: cacheableResult };
221
+ }
222
+ return { result };
223
+ }
224
+ export { validateProtocolValue, validateServerResult } from "./protocol-validation.js";
225
+ export { isJsonValue } from "toolcraft-schema";
226
+ export { isBase64 } from "./base64.js";
227
+ export { isValidUri } from "./uri.js";
228
+ export { isValidMetadata } from "./metadata.js";
@@ -0,0 +1 @@
1
+ export declare function waitForRequest<T>(operation: Promise<T>, signal: AbortSignal): Promise<T | undefined>;
@@ -0,0 +1,18 @@
1
+ export function waitForRequest(operation, signal) {
2
+ return new Promise((resolve, reject) => {
3
+ const abort = () => {
4
+ signal.removeEventListener("abort", abort);
5
+ resolve(undefined);
6
+ };
7
+ signal.addEventListener("abort", abort, { once: true });
8
+ if (signal.aborted)
9
+ abort();
10
+ operation.then((value) => {
11
+ signal.removeEventListener("abort", abort);
12
+ resolve(value);
13
+ }, (error) => {
14
+ signal.removeEventListener("abort", abort);
15
+ reject(error);
16
+ });
17
+ });
18
+ }
@@ -0,0 +1,18 @@
1
+ type SamplingContent = {
2
+ type: "tool_use";
3
+ id: string;
4
+ } | {
5
+ type: "tool_result";
6
+ toolUseId: string;
7
+ } | {
8
+ type: "text" | "image" | "audio";
9
+ };
10
+ export interface SamplingMessage {
11
+ role: "user" | "assistant";
12
+ content: SamplingContent | SamplingContent[];
13
+ }
14
+ export declare function inspectSamplingMessages(messages: readonly SamplingMessage[]): {
15
+ valid: boolean;
16
+ usesTools: boolean;
17
+ };
18
+ export {};
@@ -0,0 +1,34 @@
1
+ // Field schemas must be validated before checking cross-message invariants.
2
+ export function inspectSamplingMessages(messages) {
3
+ let pending;
4
+ let usesTools = false;
5
+ const seenIds = new Set();
6
+ for (const message of messages) {
7
+ const content = Array.isArray(message.content) ? message.content : [message.content];
8
+ if (pending !== undefined) {
9
+ if (message.role !== "user")
10
+ return { valid: false, usesTools };
11
+ for (const block of content) {
12
+ if (block.type !== "tool_result" || !pending.delete(block.toolUseId))
13
+ return { valid: false, usesTools };
14
+ }
15
+ if (pending.size > 0)
16
+ return { valid: false, usesTools };
17
+ pending = undefined;
18
+ continue;
19
+ }
20
+ for (const block of content) {
21
+ if (block.type === "tool_result")
22
+ return { valid: false, usesTools };
23
+ if (block.type !== "tool_use")
24
+ continue;
25
+ if (message.role !== "assistant" || seenIds.has(block.id))
26
+ return { valid: false, usesTools };
27
+ seenIds.add(block.id);
28
+ pending ??= new Set();
29
+ pending.add(block.id);
30
+ usesTools = true;
31
+ }
32
+ }
33
+ return { valid: pending === undefined, usesTools };
34
+ }
@@ -1,4 +1,4 @@
1
- import type { JSONSchema } from "./types.js";
1
+ import type { JSONSchema, OutputSchema } from "./types.js";
2
2
  type SchemaPropertyType = "string" | "number" | "integer" | "boolean" | "object" | "array";
3
3
  interface SchemaPropertyDef {
4
4
  type: SchemaPropertyType;
@@ -16,5 +16,8 @@ type InferSchema<T extends SchemaDefinition> = {
16
16
  export interface TypedSchema<T> extends JSONSchema {
17
17
  __type?: T;
18
18
  }
19
+ export interface TypedOutputSchema<T> extends OutputSchema {
20
+ __type?: T;
21
+ }
19
22
  export declare function defineSchema<T extends SchemaDefinition>(definition: T): TypedSchema<InferSchema<T>>;
20
23
  export {};
@@ -1,7 +1,7 @@
1
1
  import type { ServerOptions, ToolDefinition, ToolHandler, HandleResult, Prompt, PromptHandler, Resource, ResourceHandler, ResourceTemplate, Transport, SDKTransport, JSONRPCNotification } from "./types.js";
2
- import type { TypedSchema } from "./schema.js";
2
+ import type { TypedSchema, TypedOutputSchema } from "./schema.js";
3
3
  export interface Server {
4
- tool<TIn, TOut = never>(name: string, description: string, inputSchema: TypedSchema<TIn>, handler: ToolHandler<TIn, TOut>, outputSchema?: TypedSchema<TOut>): Server;
4
+ tool<TIn, TOut = never>(name: string, description: string, inputSchema: TypedSchema<TIn>, handler: ToolHandler<TIn, TOut>, outputSchema?: TypedOutputSchema<TOut>): Server;
5
5
  registerTool<TIn, TOut = never>(definition: Omit<ToolDefinition<TIn, TOut>, "handler">, handler: ToolHandler<TIn, TOut>): Server;
6
6
  prompt(definition: Prompt, handler: PromptHandler): Server;
7
7
  resource(definition: Resource, handler: ResourceHandler): Server;
@@ -17,7 +17,7 @@ export interface Server {
17
17
  notifyResourcesChanged(): Promise<void>;
18
18
  notifyResourceUpdated(uri: string): Promise<void>;
19
19
  createMessageSession(listener?: (notification: JSONRPCNotification) => void | Promise<void>): MessageSession;
20
- handleMessage(method: string, params?: Record<string, unknown>): Promise<HandleResult>;
20
+ handleMessage(method: string, params?: Record<string, unknown>, context?: MessageRequestContext): Promise<HandleResult>;
21
21
  listen(): Promise<void>;
22
22
  connect(transport: Transport): Promise<void>;
23
23
  connectSDK(transport: SDKTransport): Promise<void>;
@@ -26,8 +26,13 @@ export interface MessageSessionContext {
26
26
  readonly signal: AbortSignal;
27
27
  notify(method: string, params?: Record<string, unknown>): Promise<void>;
28
28
  }
29
+ export interface MessageRequestContext {
30
+ requestId?: string | number;
31
+ signal?: AbortSignal;
32
+ parameterHeaders?: Record<string, string | string[] | undefined>;
33
+ }
29
34
  export type CustomMethodHandler = (params: Record<string, unknown> | undefined, session: MessageSessionContext) => unknown | Promise<unknown>;
30
- export type MessageHandler = (method: string, params?: Record<string, unknown>) => Promise<HandleResult>;
35
+ export type MessageHandler = (method: string, params?: Record<string, unknown>, context?: MessageRequestContext) => Promise<HandleResult>;
31
36
  export interface MessageSession {
32
37
  handleMessage: MessageHandler;
33
38
  close(): void;