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,14 +1,46 @@
1
1
  import * as readline from "readline";
2
- import { compileJsonSchema, formatIssues } from "toolcraft-schema";
2
+ import { compileJsonSchema, formatIssues, normalizeLegacyNullability } from "toolcraft-schema";
3
3
  import { JSON_RPC_ERROR_CODES, ToolError } from "./types.js";
4
- import { parseMessage, formatSuccessResponse, formatErrorResponse } from "./jsonrpc.js";
4
+ import { parseMessage, formatSuccessResponse, formatErrorResponse, isRequestId } from "./jsonrpc.js";
5
5
  import { parseUriTemplate } from "./uri-template.js";
6
6
  import { toContentBlocks } from "./content/convert.js";
7
7
  import { ToolCallAdmission } from "./tool-call-admission.js";
8
8
  import { StdioOutput } from "./stdio-output.js";
9
9
  import { StdioInput } from "./stdio-input.js";
10
+ import { isBase64 } from "./base64.js";
11
+ import { selectRequestProtocol, decorateModernResult, MODERN_PROTOCOL_VERSION } from "./protocol.js";
12
+ import { SubscriptionRegistry } from "./subscriptions.js";
13
+ import { waitForRequest } from "./request-cancellation.js";
14
+ import { isJsonValue } from "toolcraft-schema";
15
+ import { isValidUri } from "./uri.js";
16
+ import { getParameterHeaders, validateParameterHeaders } from "./headers.js";
10
17
  const PROTOCOL_VERSION = "2025-11-25";
11
- const SUPPORTED_PROTOCOL_VERSIONS = new Set(["2025-03-26", "2025-06-18", PROTOCOL_VERSION]);
18
+ const SUPPORTED_PROTOCOL_VERSIONS = new Set(["2025-03-26", "2025-06-18", PROTOCOL_VERSION, MODERN_PROTOCOL_VERSION]);
19
+ function createLifecycleState(listener, supportNotifications, supportResourceSubscriptions) {
20
+ const abortController = new AbortController();
21
+ const admissions = new Set();
22
+ const requests = new Map();
23
+ abortController.signal.addEventListener("abort", () => {
24
+ for (const admission of admissions)
25
+ admission.abort(abortController.signal.reason);
26
+ admissions.clear();
27
+ for (const request of requests.values())
28
+ request.abort(abortController.signal.reason);
29
+ requests.clear();
30
+ }, { once: true });
31
+ return {
32
+ initialized: false,
33
+ protocolVersion: PROTOCOL_VERSION,
34
+ initializeAccepted: false,
35
+ notificationReady: false,
36
+ resourceSubscriptions: new Set(),
37
+ abortController,
38
+ admissions,
39
+ requests,
40
+ subscriptions: new SubscriptionRegistry(listener ?? (() => { }), supportNotifications, supportResourceSubscriptions),
41
+ listener
42
+ };
43
+ }
12
44
  function compileToolSchema(schema) {
13
45
  try {
14
46
  return compileJsonSchema(schema);
@@ -27,12 +59,14 @@ export function createServer(options) {
27
59
  const maxQueuedToolCalls = options.maxQueuedToolCalls ?? 64;
28
60
  const maxStdioOutputBytes = options.maxStdioOutputBytes ?? 1024 * 1024;
29
61
  const maxPendingStdioMessages = options.maxPendingStdioMessages ?? 128;
62
+ const maxActiveRequests = options.maxActiveRequests ?? 128;
30
63
  const maxStdioLineBytes = options.maxStdioLineBytes ?? 1024 * 1024;
31
64
  for (const [name, value, minimum] of [
32
65
  ["maxConcurrentToolCalls", maxConcurrentToolCalls, 1],
33
66
  ["maxQueuedToolCalls", maxQueuedToolCalls, 0],
34
67
  ["maxStdioOutputBytes", maxStdioOutputBytes, 1],
35
68
  ["maxPendingStdioMessages", maxPendingStdioMessages, 1],
69
+ ["maxActiveRequests", maxActiveRequests, 1],
36
70
  ["maxStdioLineBytes", maxStdioLineBytes, 1]
37
71
  ]) {
38
72
  if (!Number.isSafeInteger(value) || value < minimum) {
@@ -49,15 +83,50 @@ export function createServer(options) {
49
83
  const methods = new Map();
50
84
  const notificationListeners = new Set();
51
85
  const connectionNotificationListeners = new Map();
52
- const defaultLifecycle = {
53
- initialized: false,
54
- initializeAccepted: false,
55
- notificationReady: false,
56
- resourceSubscriptions: new Set(),
57
- abortController: new AbortController()
58
- };
86
+ const defaultLifecycle = createLifecycleState((notification) => {
87
+ for (const listener of notificationListeners)
88
+ listener(notification);
89
+ }, supportNotifications, supportResourceSubscriptions);
59
90
  const messageLifecycles = new Set([defaultLifecycle]);
60
- const handleMessageWithLifecycle = async (method, lifecycle, params) => {
91
+ let activeRequests = 0;
92
+ const describeCapabilities = () => ({
93
+ tools: {
94
+ ...(supportNotifications ? { listChanged: true } : {})
95
+ },
96
+ prompts: {
97
+ ...(supportNotifications ? { listChanged: true } : {})
98
+ },
99
+ resources: {
100
+ ...(supportNotifications ? { listChanged: true } : {}),
101
+ ...(supportResourceSubscriptions ? { subscribe: true } : {})
102
+ }
103
+ });
104
+ const dispatchMessage = async (method, lifecycle, params, modern = false, requestSignal = lifecycle.abortController.signal, parameterHeaders) => {
105
+ const handlerContext = {
106
+ signal: requestSignal,
107
+ ...(modern && params?.requestState !== undefined
108
+ ? { requestState: params.requestState }
109
+ : {}),
110
+ ...(modern && params?.inputResponses !== undefined
111
+ ? { inputResponses: params.inputResponses }
112
+ : {}),
113
+ clientCapabilities: modern
114
+ ? (params?._meta)["io.modelcontextprotocol/clientCapabilities"]
115
+ : {}
116
+ };
117
+ if (method === "server/discover") {
118
+ const result = {
119
+ resultType: "complete",
120
+ supportedVersions: [...SUPPORTED_PROTOCOL_VERSIONS].reverse(),
121
+ capabilities: describeCapabilities(),
122
+ _meta: {
123
+ "io.modelcontextprotocol/serverInfo": { name: options.name, version: options.version }
124
+ },
125
+ ttlMs: 0,
126
+ cacheScope: "private"
127
+ };
128
+ return { result };
129
+ }
61
130
  // Allow ping and initialize before initialization
62
131
  if (method === "ping") {
63
132
  return { result: {} };
@@ -73,26 +142,17 @@ export function createServer(options) {
73
142
  lifecycle.notificationReady = false;
74
143
  const requestedProtocol = typeof params?.protocolVersion === "string" ? params.protocolVersion : undefined;
75
144
  const result = {
76
- protocolVersion: requestedProtocol !== undefined && SUPPORTED_PROTOCOL_VERSIONS.has(requestedProtocol)
145
+ protocolVersion: requestedProtocol !== undefined && requestedProtocol !== MODERN_PROTOCOL_VERSION &&
146
+ SUPPORTED_PROTOCOL_VERSIONS.has(requestedProtocol)
77
147
  ? requestedProtocol
78
148
  : PROTOCOL_VERSION,
79
- capabilities: {
80
- tools: {
81
- ...(supportNotifications ? { listChanged: true } : {})
82
- },
83
- prompts: {
84
- ...(supportNotifications ? { listChanged: true } : {})
85
- },
86
- resources: {
87
- ...(supportNotifications ? { listChanged: true } : {}),
88
- ...(supportResourceSubscriptions ? { subscribe: true } : {})
89
- }
90
- },
149
+ capabilities: describeCapabilities(),
91
150
  serverInfo: {
92
151
  name: options.name,
93
152
  version: options.version
94
153
  }
95
154
  };
155
+ lifecycle.protocolVersion = result.protocolVersion;
96
156
  return { result };
97
157
  }
98
158
  if (method === "notifications/initialized") {
@@ -108,7 +168,7 @@ export function createServer(options) {
108
168
  return { result: undefined };
109
169
  }
110
170
  // All other methods require initialization
111
- if (!lifecycle.initialized) {
171
+ if (!modern && !lifecycle.initialized) {
112
172
  return {
113
173
  error: {
114
174
  code: JSON_RPC_ERROR_CODES.INVALID_REQUEST,
@@ -123,9 +183,10 @@ export function createServer(options) {
123
183
  delete descriptor.handler;
124
184
  delete descriptor.inputValidator;
125
185
  delete descriptor.outputValidator;
126
- toolList.push({
127
- ...descriptor
128
- });
186
+ delete descriptor.parameterHeaders;
187
+ if (!modern && descriptor.outputSchema?.type !== "object")
188
+ delete descriptor.outputSchema;
189
+ toolList.push(structuredClone(descriptor));
129
190
  }
130
191
  return { result: { tools: toolList } };
131
192
  }
@@ -149,7 +210,14 @@ export function createServer(options) {
149
210
  }
150
211
  };
151
212
  }
213
+ if (params?.arguments !== undefined && !isJsonObject(params.arguments))
214
+ return invalidParams("Tool arguments must be an object");
152
215
  const toolArgs = (params?.arguments ?? {});
216
+ if (modern && parameterHeaders !== undefined) {
217
+ const headerError = validateParameterHeaders(tool.parameterHeaders, toolArgs, parameterHeaders);
218
+ if (headerError !== undefined)
219
+ return { error: { code: -32020, message: headerError } };
220
+ }
153
221
  const inputValidation = tool.inputValidator.validate(toolArgs);
154
222
  if (options.validateToolArguments !== false && !inputValidation.ok) {
155
223
  return {
@@ -162,43 +230,58 @@ export function createServer(options) {
162
230
  }
163
231
  try {
164
232
  let handlerResult;
165
- const admissionTimeout = options.toolCallTimeoutMs === undefined ? undefined : new AbortController();
166
- const admissionSignal = AbortSignal.any([
167
- lifecycle.abortController.signal,
168
- ...(admissionTimeout === undefined ? [] : [admissionTimeout.signal])
169
- ]);
233
+ const admissionController = new AbortController();
234
+ const sessionSignal = requestSignal;
235
+ const admissionSignal = admissionController.signal;
236
+ const cancelAdmission = () => admissionController.abort(sessionSignal.reason);
237
+ if (sessionSignal.aborted)
238
+ admissionController.abort(sessionSignal.reason);
239
+ else {
240
+ lifecycle.admissions.add(admissionController);
241
+ if (sessionSignal !== lifecycle.abortController.signal)
242
+ sessionSignal.addEventListener("abort", cancelAdmission, { once: true });
243
+ }
170
244
  const handlerPromise = (async () => {
171
245
  const release = await toolAdmission.acquire(admissionSignal);
172
246
  try {
173
247
  admissionSignal.throwIfAborted();
174
- return await tool.handler(toolArgs);
248
+ return await tool.handler(toolArgs, { ...handlerContext, signal: admissionSignal });
175
249
  }
176
250
  finally {
177
251
  release();
178
252
  }
179
253
  })();
180
- if (options.toolCallTimeoutMs === undefined) {
181
- handlerResult = await handlerPromise;
254
+ try {
255
+ if (options.toolCallTimeoutMs === undefined) {
256
+ handlerResult = await handlerPromise;
257
+ }
258
+ else {
259
+ let timeout;
260
+ handlerResult = await Promise.race([
261
+ handlerPromise,
262
+ new Promise((_resolve, reject) => {
263
+ timeout = setTimeout(() => {
264
+ const error = new ToolError(JSON_RPC_ERROR_CODES.INTERNAL_ERROR, `Tool call timed out: ${toolName}`);
265
+ admissionController.abort(error);
266
+ reject(error);
267
+ }, options.toolCallTimeoutMs);
268
+ })
269
+ ]).finally(() => {
270
+ if (timeout !== undefined) {
271
+ clearTimeout(timeout);
272
+ }
273
+ });
274
+ }
182
275
  }
183
- else {
184
- let timeout;
185
- handlerResult = await Promise.race([
186
- handlerPromise,
187
- new Promise((_resolve, reject) => {
188
- timeout = setTimeout(() => {
189
- const error = new ToolError(JSON_RPC_ERROR_CODES.INTERNAL_ERROR, `Tool call timed out: ${toolName}`);
190
- admissionTimeout.abort(error);
191
- reject(error);
192
- }, options.toolCallTimeoutMs);
193
- })
194
- ]).finally(() => {
195
- if (timeout !== undefined) {
196
- clearTimeout(timeout);
197
- }
198
- });
276
+ finally {
277
+ lifecycle.admissions.delete(admissionController);
278
+ sessionSignal.removeEventListener("abort", cancelAdmission);
199
279
  }
200
- const result = normalizeToolResult(handlerResult, tool.outputSchema);
201
- const outputValidation = tool.outputValidator?.validate(result.structuredContent);
280
+ if (modern && isInputRequiredResult(handlerResult))
281
+ return { result: handlerResult };
282
+ const outputSchema = modern || tool.outputSchema?.type === "object" ? tool.outputSchema : undefined;
283
+ const result = normalizeToolResult(handlerResult, tool.outputSchema, modern);
284
+ const outputValidation = outputSchema === undefined ? undefined : tool.outputValidator?.validate(result.structuredContent);
202
285
  if (result.isError !== true && outputValidation !== undefined && !outputValidation.ok) {
203
286
  throw new ToolError(JSON_RPC_ERROR_CODES.INTERNAL_ERROR, `Invalid structured tool result: ${formatIssues(outputValidation.issues)}`, outputValidation.issues);
204
287
  }
@@ -225,7 +308,7 @@ export function createServer(options) {
225
308
  if (method === "prompts/list") {
226
309
  return {
227
310
  result: {
228
- prompts: [...prompts.values()].map(({ handler: _handler, ...prompt }) => prompt)
311
+ prompts: [...prompts.values()].map(({ handler: _handler, ...prompt }) => structuredClone(prompt))
229
312
  }
230
313
  };
231
314
  }
@@ -243,8 +326,10 @@ export function createServer(options) {
243
326
  return invalidParams("Invalid prompt arguments");
244
327
  }
245
328
  try {
246
- const result = await prompt.handler(args);
247
- if (!isGetPromptResult(result)) {
329
+ const result = await prompt.handler(args, handlerContext);
330
+ if (modern && isInputRequiredResult(result))
331
+ return { result };
332
+ if (!isGetPromptResult(result, modern || lifecycle.protocolVersion === PROTOCOL_VERSION)) {
248
333
  return internalError("Invalid prompt result");
249
334
  }
250
335
  return { result };
@@ -256,14 +341,14 @@ export function createServer(options) {
256
341
  if (method === "resources/list") {
257
342
  return {
258
343
  result: {
259
- resources: [...resources.values()].map(({ handler: _handler, ...resource }) => resource)
344
+ resources: [...resources.values()].map(({ handler: _handler, ...resource }) => structuredClone(resource))
260
345
  }
261
346
  };
262
347
  }
263
348
  if (method === "resources/templates/list") {
264
349
  return {
265
350
  result: {
266
- resourceTemplates: [...resourceTemplates.values()].map(({ handler: _handler, template: _template, ...resourceTemplate }) => resourceTemplate)
351
+ resourceTemplates: [...resourceTemplates.values()].map(({ handler: _handler, template: _template, ...resourceTemplate }) => structuredClone(resourceTemplate))
267
352
  }
268
353
  };
269
354
  }
@@ -277,7 +362,9 @@ export function createServer(options) {
277
362
  return resourceNotFound(uri);
278
363
  }
279
364
  try {
280
- const result = await resource.handler(uri);
365
+ const result = await resource.handler(uri, handlerContext);
366
+ if (modern && isInputRequiredResult(result))
367
+ return { result };
281
368
  if (!isReadResourceResult(result)) {
282
369
  return internalError("Invalid resource result");
283
370
  }
@@ -316,9 +403,11 @@ export function createServer(options) {
316
403
  if (customMethod !== undefined) {
317
404
  try {
318
405
  const result = await customMethod(params, {
319
- signal: lifecycle.abortController.signal,
406
+ signal: requestSignal,
320
407
  async notify(notificationMethod, notificationParams) {
321
- if (!lifecycle.notificationReady || lifecycle.listener === undefined) {
408
+ if (requestSignal.aborted ||
409
+ (!modern && !lifecycle.notificationReady) ||
410
+ lifecycle.listener === undefined) {
322
411
  return;
323
412
  }
324
413
  await lifecycle.listener({
@@ -331,6 +420,15 @@ export function createServer(options) {
331
420
  return { result };
332
421
  }
333
422
  catch (error) {
423
+ if (error instanceof ToolError) {
424
+ return {
425
+ error: {
426
+ code: error.code,
427
+ message: error.message,
428
+ ...(error.data === undefined ? {} : { data: error.data })
429
+ }
430
+ };
431
+ }
334
432
  return internalError(toErrorMessage(error));
335
433
  }
336
434
  }
@@ -341,21 +439,90 @@ export function createServer(options) {
341
439
  }
342
440
  };
343
441
  };
344
- const createMessageSession = (listener) => {
345
- const lifecycle = {
346
- initialized: false,
347
- initializeAccepted: false,
348
- notificationReady: false,
349
- resourceSubscriptions: new Set(),
350
- abortController: new AbortController(),
351
- listener
442
+ const handleMessageWithLifecycle = async (method, lifecycle, params, context) => {
443
+ if (method === "notifications/cancelled") {
444
+ const id = params?.requestId;
445
+ if (typeof id === "string" || typeof id === "number") {
446
+ lifecycle.requests.get(id)?.abort(new Error("Request cancelled"));
447
+ }
448
+ return { result: undefined };
449
+ }
450
+ const protocol = selectRequestProtocol(method, params, SUPPORTED_PROTOCOL_VERSIONS);
451
+ if (protocol.error !== undefined)
452
+ return { error: protocol.error };
453
+ const directLegacy = !protocol.modern && context === undefined;
454
+ if (protocol.modern &&
455
+ context !== undefined &&
456
+ context.requestId !== undefined &&
457
+ !isRequestId(context.requestId)) {
458
+ return {
459
+ error: { code: JSON_RPC_ERROR_CODES.INVALID_REQUEST, message: "Invalid Request ID" }
460
+ };
461
+ }
462
+ if (activeRequests >= maxActiveRequests) {
463
+ return { error: { code: -32000, message: "Too many active requests" } };
464
+ }
465
+ const key = context?.requestId ?? Symbol("request");
466
+ if (lifecycle.requests.has(key)) {
467
+ return {
468
+ error: {
469
+ code: JSON_RPC_ERROR_CODES.INVALID_REQUEST,
470
+ message: "Request ID is already active"
471
+ }
472
+ };
473
+ }
474
+ const controller = new AbortController();
475
+ const parents = context?.signal === undefined ? [] : [context.signal];
476
+ const signal = controller.signal;
477
+ if (lifecycle.abortController.signal.aborted)
478
+ controller.abort(lifecycle.abortController.signal.reason);
479
+ const abort = (event) => controller.abort(event.target.reason);
480
+ for (const parent of parents) {
481
+ if (parent.aborted)
482
+ controller.abort(parent.reason);
483
+ else
484
+ parent.addEventListener("abort", abort, { once: true });
485
+ }
486
+ const cleanup = () => {
487
+ for (const parent of parents)
488
+ parent.removeEventListener("abort", abort);
489
+ };
490
+ if (signal.aborted) {
491
+ cleanup();
492
+ return { result: undefined };
493
+ }
494
+ lifecycle.requests.set(key, controller);
495
+ activeRequests += 1;
496
+ const operation = protocol.modern && method === "subscriptions/listen"
497
+ ? lifecycle.subscriptions.listen(context?.requestId, params?.notifications, signal)
498
+ : dispatchMessage(method, lifecycle, params, protocol.modern, directLegacy ? lifecycle.abortController.signal : signal, context?.parameterHeaders);
499
+ const release = () => {
500
+ activeRequests -= 1;
501
+ if (lifecycle.requests.get(key) === controller)
502
+ lifecycle.requests.delete(key);
352
503
  };
504
+ void operation.then(release, release);
505
+ try {
506
+ const handled = directLegacy ? await operation : await waitForRequest(operation, signal);
507
+ if (handled === undefined || (!directLegacy && signal.aborted))
508
+ return { result: undefined };
509
+ return protocol.modern
510
+ ? decorateModernResult(method, handled, { name: options.name, version: options.version }, (params?._meta)["io.modelcontextprotocol/clientCapabilities"])
511
+ : handled;
512
+ }
513
+ finally {
514
+ cleanup();
515
+ controller.abort();
516
+ }
517
+ };
518
+ const createMessageSession = (listener) => {
519
+ const lifecycle = createLifecycleState(listener, supportNotifications, supportResourceSubscriptions);
353
520
  messageLifecycles.add(lifecycle);
354
521
  if (listener !== undefined) {
355
522
  connectionNotificationListeners.set(listener, lifecycle);
356
523
  }
357
524
  return {
358
- handleMessage: (method, params) => handleMessageWithLifecycle(method, lifecycle, params),
525
+ handleMessage: (method, params, context) => handleMessageWithLifecycle(method, lifecycle, params, context),
359
526
  close: () => {
360
527
  lifecycle.abortController.abort();
361
528
  if (listener !== undefined) {
@@ -365,14 +532,18 @@ export function createServer(options) {
365
532
  }
366
533
  };
367
534
  };
368
- const handleMessage = (method, params) => handleMessageWithLifecycle(method, defaultLifecycle, params);
369
- const processLine = async (line, write, messageHandler) => {
535
+ const handleMessage = (method, params, context) => handleMessageWithLifecycle(method, defaultLifecycle, params, context);
536
+ const processLine = async (line, write, messageHandler, subscriptionSignal) => {
370
537
  const parsed = parseMessage(line);
371
538
  if (!parsed.success) {
372
539
  await write(formatErrorResponse(parsed.id, parsed.error) + "\n");
373
540
  return;
374
541
  }
375
542
  const { request, isNotification } = parsed;
543
+ if (isNotification &&
544
+ !request.method.startsWith("notifications/") &&
545
+ selectRequestProtocol(request.method, request.params, SUPPORTED_PROTOCOL_VERSIONS).modern)
546
+ return;
376
547
  if (isNotification && request.method === "initialize") {
377
548
  return;
378
549
  }
@@ -386,7 +557,12 @@ export function createServer(options) {
386
557
  }
387
558
  let handled;
388
559
  try {
389
- handled = await messageHandler(request.method, request.params);
560
+ handled = await messageHandler(request.method, request.params, !isNotification && request.id !== null
561
+ ? {
562
+ requestId: request.id,
563
+ ...(request.method === "subscriptions/listen" ? { signal: subscriptionSignal } : {})
564
+ }
565
+ : undefined);
390
566
  }
391
567
  catch {
392
568
  if (!isNotification) {
@@ -419,6 +595,7 @@ export function createServer(options) {
419
595
  for (const listener of notificationListeners) {
420
596
  listener(notification);
421
597
  }
598
+ await Promise.all([...messageLifecycles].map((lifecycle) => lifecycle.subscriptions.emit(method, params)));
422
599
  await Promise.all([...connectionNotificationListeners].map(async ([listener, lifecycle]) => {
423
600
  if (lifecycle.notificationReady && canSend(lifecycle)) {
424
601
  await listener(notification);
@@ -431,19 +608,23 @@ export function createServer(options) {
431
608
  if (tools.has(name)) {
432
609
  throw new Error(`Tool already registered: ${name}`);
433
610
  }
434
- const inputValidator = compileToolSchema(inputSchema);
611
+ const inputSchemaSnapshot = normalizeLegacyNullability(inputSchema);
612
+ const outputSchemaSnapshot = outputSchema === undefined ? undefined : normalizeLegacyNullability(outputSchema);
613
+ const inputValidator = compileToolSchema(inputSchemaSnapshot);
614
+ assertObjectRootSchema(inputSchemaSnapshot, "inputSchema");
435
615
  let outputValidator;
436
- if (outputSchema !== undefined) {
437
- assertObjectRootSchema(outputSchema, "outputSchema");
438
- outputValidator = compileToolSchema(outputSchema);
616
+ if (outputSchemaSnapshot !== undefined) {
617
+ assertOutputSchema(outputSchemaSnapshot);
618
+ outputValidator = compileToolSchema(outputSchemaSnapshot);
439
619
  }
440
620
  tools.set(name, {
441
621
  name,
442
622
  description,
443
- inputSchema: inputSchema,
444
- ...(outputSchema === undefined ? {} : { outputSchema: outputSchema }),
623
+ inputSchema: inputSchemaSnapshot,
624
+ ...(outputSchemaSnapshot === undefined ? {} : { outputSchema: outputSchemaSnapshot }),
445
625
  handler: handler,
446
626
  inputValidator,
627
+ parameterHeaders: getParameterHeaders(inputSchemaSnapshot),
447
628
  ...(outputValidator === undefined ? {} : { outputValidator })
448
629
  });
449
630
  return server;
@@ -453,16 +634,22 @@ export function createServer(options) {
453
634
  if (tools.has(definition.name)) {
454
635
  throw new Error(`Tool already registered: ${definition.name}`);
455
636
  }
456
- const inputValidator = compileToolSchema(definition.inputSchema);
637
+ const descriptor = structuredClone(definition);
638
+ const inputSchema = normalizeLegacyNullability(descriptor.inputSchema);
639
+ const inputValidator = compileToolSchema(inputSchema);
640
+ assertObjectRootSchema(inputSchema, "inputSchema");
457
641
  let outputValidator;
458
- if (definition.outputSchema !== undefined) {
459
- assertObjectRootSchema(definition.outputSchema, "outputSchema");
460
- outputValidator = compileToolSchema(definition.outputSchema);
642
+ if (descriptor.outputSchema !== undefined) {
643
+ descriptor.outputSchema = normalizeLegacyNullability(descriptor.outputSchema);
644
+ assertOutputSchema(descriptor.outputSchema);
645
+ outputValidator = compileToolSchema(descriptor.outputSchema);
461
646
  }
462
647
  tools.set(definition.name, {
463
- ...definition,
648
+ ...descriptor,
649
+ inputSchema,
464
650
  handler: handler,
465
651
  inputValidator,
652
+ parameterHeaders: getParameterHeaders(inputSchema),
466
653
  ...(outputValidator === undefined ? {} : { outputValidator })
467
654
  });
468
655
  return server;
@@ -472,7 +659,7 @@ export function createServer(options) {
472
659
  if (prompts.has(definition.name)) {
473
660
  throw new Error(`Prompt already registered: ${definition.name}`);
474
661
  }
475
- prompts.set(definition.name, { ...definition, handler });
662
+ prompts.set(definition.name, { ...structuredClone(definition), handler });
476
663
  return server;
477
664
  },
478
665
  resource(definition, handler) {
@@ -482,7 +669,7 @@ export function createServer(options) {
482
669
  if (resources.has(definition.uri)) {
483
670
  throw new Error(`Resource already registered: ${definition.uri}`);
484
671
  }
485
- resources.set(definition.uri, { ...definition, handler });
672
+ resources.set(definition.uri, { ...structuredClone(definition), handler });
486
673
  return server;
487
674
  },
488
675
  resourceTemplate(definition, handler) {
@@ -490,7 +677,7 @@ export function createServer(options) {
490
677
  if (resourceTemplates.has(definition.uriTemplate)) {
491
678
  throw new Error(`Resource template already registered: ${definition.uriTemplate}`);
492
679
  }
493
- resourceTemplates.set(definition.uriTemplate, { ...definition, handler, template });
680
+ resourceTemplates.set(definition.uriTemplate, { ...structuredClone(definition), handler, template });
494
681
  return server;
495
682
  },
496
683
  method(name, handler) {
@@ -518,19 +705,19 @@ export function createServer(options) {
518
705
  },
519
706
  async notifyToolsChanged() {
520
707
  if (supportNotifications &&
521
- [...messageLifecycles].some((lifecycle) => lifecycle.notificationReady)) {
708
+ [...messageLifecycles].some((lifecycle) => lifecycle.notificationReady || lifecycle.subscriptions.size > 0)) {
522
709
  await broadcastNotification("notifications/tools/list_changed");
523
710
  }
524
711
  },
525
712
  async notifyPromptsChanged() {
526
713
  if (supportNotifications &&
527
- [...messageLifecycles].some((lifecycle) => lifecycle.notificationReady)) {
714
+ [...messageLifecycles].some((lifecycle) => lifecycle.notificationReady || lifecycle.subscriptions.size > 0)) {
528
715
  await broadcastNotification("notifications/prompts/list_changed");
529
716
  }
530
717
  },
531
718
  async notifyResourcesChanged() {
532
719
  if (supportNotifications &&
533
- [...messageLifecycles].some((lifecycle) => lifecycle.notificationReady)) {
720
+ [...messageLifecycles].some((lifecycle) => lifecycle.notificationReady || lifecycle.subscriptions.size > 0)) {
534
721
  await broadcastNotification("notifications/resources/list_changed");
535
722
  }
536
723
  },
@@ -553,6 +740,7 @@ export function createServer(options) {
553
740
  let inputClosed = false;
554
741
  let settled = false;
555
742
  const pendingMessages = new Set();
743
+ const subscriptions = new AbortController();
556
744
  const output = new StdioOutput(transport.writable, maxStdioOutputBytes, fail, finish);
557
745
  const listener = (notification) => output.write(`${JSON.stringify(notification)}\n`);
558
746
  const session = server.createMessageSession(listener);
@@ -596,7 +784,7 @@ export function createServer(options) {
596
784
  fail(new Error("Stdio pending message limit exceeded"));
597
785
  return;
598
786
  }
599
- const message = processLine(line, data => output.write(data), session.handleMessage);
787
+ const message = processLine(line, (data) => output.write(data), session.handleMessage, subscriptions.signal);
600
788
  if (!settled)
601
789
  pendingMessages.add(message);
602
790
  void message.then(() => {
@@ -606,6 +794,7 @@ export function createServer(options) {
606
794
  });
607
795
  rl.on("close", () => {
608
796
  inputClosed = true;
797
+ subscriptions.abort();
609
798
  finish();
610
799
  });
611
800
  transport.readable.pipe(input);
@@ -622,6 +811,10 @@ export function createServer(options) {
622
811
  }
623
812
  // Handle notifications (no id) - don't respond
624
813
  if (!("id" in message) || message.id === undefined) {
814
+ if (!message.method.startsWith("notifications/") &&
815
+ selectRequestProtocol(message.method, message.params, SUPPORTED_PROTOCOL_VERSIONS)
816
+ .modern)
817
+ return;
625
818
  if (message.method === "initialize") {
626
819
  return;
627
820
  }
@@ -645,9 +838,19 @@ export function createServer(options) {
645
838
  return;
646
839
  }
647
840
  const request = message;
841
+ if (selectRequestProtocol(request.method, request.params, SUPPORTED_PROTOCOL_VERSIONS)
842
+ .modern &&
843
+ !isRequestId(request.id)) {
844
+ await transport.send({
845
+ jsonrpc: "2.0",
846
+ id: null,
847
+ error: { code: JSON_RPC_ERROR_CODES.INVALID_REQUEST, message: "Invalid Request ID" }
848
+ });
849
+ return;
850
+ }
648
851
  let handled;
649
852
  try {
650
- handled = await session.handleMessage(request.method, request.params);
853
+ handled = await session.handleMessage(request.method, request.params, request.id === null ? undefined : { requestId: request.id });
651
854
  }
652
855
  catch {
653
856
  await transport.send({
@@ -718,15 +921,6 @@ function resourceNotFound(uri) {
718
921
  function toErrorMessage(error) {
719
922
  return error instanceof Error ? error.message : String(error);
720
923
  }
721
- function isValidUri(uri) {
722
- try {
723
- new URL(uri);
724
- return true;
725
- }
726
- catch {
727
- return false;
728
- }
729
- }
730
924
  function assertNonEmptyName(name, message) {
731
925
  if (name.length === 0) {
732
926
  throw new Error(message);
@@ -765,57 +959,81 @@ function findReadableResource(uri, resources, resourceTemplates) {
765
959
  }
766
960
  return [...resourceTemplates.values()].find((template) => template.template.match(uri) !== null);
767
961
  }
768
- function isCallToolResult(value) {
962
+ function isInputRequiredResult(value) {
963
+ return (typeof value === "object" &&
964
+ value !== null &&
965
+ !Array.isArray(value) &&
966
+ value.resultType === "input_required");
967
+ }
968
+ function isCallToolResult(value, modern) {
769
969
  if (!hasContentArray(value) || !value.content.every(isContentItem)) {
770
970
  return false;
771
971
  }
772
972
  if (hasOwnProperty(value, "structuredContent") &&
773
973
  value.structuredContent !== undefined &&
774
- !isJsonObject(value.structuredContent)) {
974
+ !(isJsonValue(value.structuredContent) && (modern || isJsonObject(value.structuredContent)))) {
775
975
  return false;
776
976
  }
777
977
  return !(hasOwnProperty(value, "isError") &&
778
978
  value.isError !== undefined &&
779
979
  typeof value.isError !== "boolean");
780
980
  }
781
- function normalizeToolResult(handlerResult, outputSchema) {
782
- if (hasContentArray(handlerResult) && !isCallToolResult(handlerResult)) {
981
+ function normalizeToolResult(handlerResult, outputSchema, modern) {
982
+ if (!modern && outputSchema !== undefined && outputSchema.type !== "object") {
983
+ const result = normalizeToolResult(handlerResult, outputSchema, true);
984
+ const { structuredContent, ...legacyResult } = result;
985
+ return {
986
+ ...legacyResult,
987
+ content: typeof handlerResult === "string"
988
+ ? [{ type: "text", text: handlerResult }]
989
+ : legacyResult.content.length > 0 || structuredContent === undefined
990
+ ? legacyResult.content
991
+ : [{ type: "text", text: JSON.stringify(structuredContent) }]
992
+ };
993
+ }
994
+ if (hasContentArray(handlerResult) && !isCallToolResult(handlerResult, modern)) {
995
+ if (outputSchema !== undefined)
996
+ throw new ToolError(JSON_RPC_ERROR_CODES.INTERNAL_ERROR, "Invalid tool result");
783
997
  throw new Error("Invalid tool result");
784
998
  }
785
999
  if (outputSchema === undefined) {
786
- const result = isCallToolResult(handlerResult)
1000
+ const result = isCallToolResult(handlerResult, modern)
787
1001
  ? handlerResult
788
1002
  : { content: toContentBlocks(handlerResult) };
789
- if (!isCallToolResult(result)) {
1003
+ if (!isCallToolResult(result, modern)) {
790
1004
  throw new Error("Invalid tool result");
791
1005
  }
792
1006
  return result;
793
1007
  }
794
- if (isCallToolResult(handlerResult) && handlerResult.isError === true) {
1008
+ if (isCallToolResult(handlerResult, modern) && handlerResult.isError === true) {
795
1009
  return handlerResult;
796
1010
  }
797
- const callToolResult = isCallToolResult(handlerResult) ? handlerResult : undefined;
1011
+ const callToolResult = isCallToolResult(handlerResult, modern) ? handlerResult : undefined;
798
1012
  const structuredContent = callToolResult ? callToolResult.structuredContent : handlerResult;
799
- if (!isJsonObject(structuredContent)) {
800
- throw new ToolError(JSON_RPC_ERROR_CODES.INTERNAL_ERROR, "Structured tool result must be an object");
1013
+ if (!(isJsonValue(structuredContent) && (modern || isJsonObject(structuredContent)))) {
1014
+ throw new ToolError(JSON_RPC_ERROR_CODES.INTERNAL_ERROR, modern ? "Structured tool result must be JSON" : "Structured tool result must be a JSON object");
801
1015
  }
802
1016
  return {
1017
+ ...callToolResult,
803
1018
  content: callToolResult !== undefined && callToolResult.content.length > 0
804
1019
  ? callToolResult.content
805
1020
  : [{ type: "text", text: JSON.stringify(structuredContent) }],
806
- ...(callToolResult?.isError !== undefined ? { isError: callToolResult.isError } : {}),
807
1021
  structuredContent
808
1022
  };
809
1023
  }
810
1024
  function assertObjectRootSchema(schema, path) {
811
- if (schema.type !== "object") {
1025
+ if (typeof schema !== "object" || schema === null || !("type" in schema) || schema.type !== "object") {
812
1026
  throw new Error(`${path} root type must be "object"`);
813
1027
  }
814
1028
  }
1029
+ function assertOutputSchema(schema) {
1030
+ if (typeof schema !== "object" || schema === null || Array.isArray(schema))
1031
+ throw new Error("outputSchema must be a JSON Schema object");
1032
+ }
815
1033
  function isJsonObject(value) {
816
1034
  return typeof value === "object" && value !== null && !Array.isArray(value);
817
1035
  }
818
- function isGetPromptResult(value) {
1036
+ function isGetPromptResult(value, modern = false) {
819
1037
  if (typeof value !== "object" || value === null || !hasOwnProperty(value, "messages")) {
820
1038
  return false;
821
1039
  }
@@ -828,7 +1046,7 @@ function isGetPromptResult(value) {
828
1046
  hasOwnProperty(message, "role") &&
829
1047
  (message.role === "user" || message.role === "assistant") &&
830
1048
  hasOwnProperty(message, "content") &&
831
- isPromptContentItem(message.content)));
1049
+ (modern ? isContentItem(message.content) : isPromptContentItem(message.content))));
832
1050
  }
833
1051
  function isReadResourceResult(value) {
834
1052
  if (typeof value !== "object" || value === null || !hasOwnProperty(value, "contents")) {
@@ -915,25 +1133,6 @@ function hasValidContentAnnotations(value) {
915
1133
  (priority === undefined || typeof priority === "number") &&
916
1134
  (lastModified === undefined || typeof lastModified === "string"));
917
1135
  }
918
- function isBase64(value) {
919
- if (value.length === 0) {
920
- return true;
921
- }
922
- if (value.length % 4 !== 0) {
923
- return false;
924
- }
925
- const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
926
- const paddingStart = value.indexOf("=");
927
- const encoded = paddingStart === -1 ? value : value.slice(0, paddingStart);
928
- const padding = paddingStart === -1 ? "" : value.slice(paddingStart);
929
- if (padding.length > 2 || [...padding].some((character) => character !== "=")) {
930
- return false;
931
- }
932
- if ([...encoded].some((character) => !alphabet.includes(character))) {
933
- return false;
934
- }
935
- return Buffer.from(value, "base64").toString("base64") === value;
936
- }
937
1136
  function isPromptContentItem(value) {
938
1137
  if (!isContentItem(value)) {
939
1138
  return false;