toolcraft 0.0.430 → 0.0.432

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 (45) hide show
  1. package/composition.json +3 -3
  2. package/dist/composition.json +3 -3
  3. package/dist/index.d.ts +2 -2
  4. package/dist/index.js +1 -1
  5. package/dist/schema-standard.compile-check.d.ts +1 -0
  6. package/dist/schema-standard.compile-check.js +4 -0
  7. package/dist/schema.d.ts +2 -2
  8. package/dist/schema.js +1 -1
  9. package/node_modules/tiny-http-mcp-server/README.md +7 -0
  10. package/node_modules/tiny-http-mcp-server/dist/composition.json +2 -2
  11. package/node_modules/tiny-http-mcp-server/dist/fetch.d.ts +3 -3
  12. package/node_modules/tiny-http-mcp-server/dist/http-server.d.ts +2 -2
  13. package/node_modules/tiny-http-mcp-server/dist/index.d.ts +1 -1
  14. package/node_modules/tiny-http-mcp-server/package.json +1 -1
  15. package/node_modules/tiny-stdio-mcp-server/README.md +41 -3
  16. package/node_modules/tiny-stdio-mcp-server/dist/composition.json +1 -1
  17. package/node_modules/tiny-stdio-mcp-server/dist/core.d.ts +1 -1
  18. package/node_modules/tiny-stdio-mcp-server/dist/index.d.ts +1 -1
  19. package/node_modules/tiny-stdio-mcp-server/dist/protocol-server.d.ts +2 -2
  20. package/node_modules/tiny-stdio-mcp-server/dist/protocol-server.js +58 -45
  21. package/node_modules/tiny-stdio-mcp-server/dist/schema.d.ts +3 -0
  22. package/node_modules/tiny-stdio-mcp-server/dist/standard-schema.compile-check.d.ts +1 -0
  23. package/node_modules/tiny-stdio-mcp-server/dist/standard-schema.compile-check.js +15 -0
  24. package/node_modules/tiny-stdio-mcp-server/dist/tool-schema.d.ts +13 -0
  25. package/node_modules/tiny-stdio-mcp-server/dist/tool-schema.js +53 -0
  26. package/node_modules/tiny-stdio-mcp-server/dist/types.d.ts +3 -2
  27. package/node_modules/toolcraft-schema/README.md +51 -10
  28. package/node_modules/toolcraft-schema/dist/index.d.ts +35 -11
  29. package/node_modules/toolcraft-schema/dist/index.js +40 -20
  30. package/node_modules/toolcraft-schema/dist/json.d.ts +7 -1
  31. package/node_modules/toolcraft-schema/dist/json.js +3 -2
  32. package/node_modules/toolcraft-schema/dist/native-json-schema.d.ts +4 -1
  33. package/node_modules/toolcraft-schema/dist/native-json-schema.js +2 -1
  34. package/node_modules/toolcraft-schema/dist/oneof.d.ts +2 -1
  35. package/node_modules/toolcraft-schema/dist/oneof.js +3 -2
  36. package/node_modules/toolcraft-schema/dist/record.d.ts +2 -1
  37. package/node_modules/toolcraft-schema/dist/record.js +3 -2
  38. package/node_modules/toolcraft-schema/dist/standard.compile-check.d.ts +1 -0
  39. package/node_modules/toolcraft-schema/dist/standard.compile-check.js +20 -0
  40. package/node_modules/toolcraft-schema/dist/standard.d.ts +92 -0
  41. package/node_modules/toolcraft-schema/dist/standard.js +38 -0
  42. package/node_modules/toolcraft-schema/dist/union.d.ts +2 -1
  43. package/node_modules/toolcraft-schema/dist/union.js +3 -2
  44. package/node_modules/toolcraft-schema/package.json +1 -1
  45. package/package.json +2 -2
package/composition.json CHANGED
@@ -98,7 +98,7 @@
98
98
  },
99
99
  {
100
100
  "name": "tiny-http-mcp-server",
101
- "version": "0.1.93",
101
+ "version": "0.1.94",
102
102
  "license": "MIT"
103
103
  },
104
104
  {
@@ -113,7 +113,7 @@
113
113
  },
114
114
  {
115
115
  "name": "toolcraft",
116
- "version": "0.0.430",
116
+ "version": "0.0.432",
117
117
  "license": "MIT"
118
118
  },
119
119
  {
@@ -123,7 +123,7 @@
123
123
  },
124
124
  {
125
125
  "name": "toolcraft-schema",
126
- "version": "0.0.430",
126
+ "version": "0.0.432",
127
127
  "license": "MIT"
128
128
  },
129
129
  {
@@ -98,7 +98,7 @@
98
98
  },
99
99
  {
100
100
  "name": "tiny-http-mcp-server",
101
- "version": "0.1.93",
101
+ "version": "0.1.94",
102
102
  "license": "MIT"
103
103
  },
104
104
  {
@@ -113,7 +113,7 @@
113
113
  },
114
114
  {
115
115
  "name": "toolcraft",
116
- "version": "0.0.430",
116
+ "version": "0.0.432",
117
117
  "license": "MIT"
118
118
  },
119
119
  {
@@ -123,7 +123,7 @@
123
123
  },
124
124
  {
125
125
  "name": "toolcraft-schema",
126
- "version": "0.0.430",
126
+ "version": "0.0.432",
127
127
  "license": "MIT"
128
128
  },
129
129
  {
package/dist/index.d.ts CHANGED
@@ -247,7 +247,7 @@ export declare function cloneCommandNode<TNode extends CommandNode<any>>(node: T
247
247
  export declare function cloneCommandNode<TServices extends object>(node: CommandNode<TServices>, scopeOverride: Scope[]): CommandNode<TServices>;
248
248
  export declare function getCommandSourcePath(command: Command<any, any, any, any>): string | undefined;
249
249
  export declare function hasMcpProxyConfig(group: Group<any>): boolean;
250
- export { S, toJsonSchema } from "./schema.js";
250
+ export { S, toJsonSchema, withStandardSchema } from "./schema.js";
251
251
  export { AuthenticationError, BadRequestError, ClientError, ConflictError, HttpError, InternalServerError, NotFoundError, PermissionDeniedError, RateLimitError, ServerError, ServiceUnavailableError, UnprocessableEntityError, createHttpError } from "./http-errors.js";
252
252
  export type { HttpErrorRequest, HttpErrorResponse } from "./http-errors.js";
253
253
  export { ApprovalDeclinedError, ToolcraftBugError, UserError, isUserError };
@@ -260,5 +260,5 @@ export type { PackageMetadata } from "./package-metadata.js";
260
260
  export type { FileChangeRendererOptions, FileChangeResult } from "./file-change-renderer.js";
261
261
  export type { FileChange, FileChangeDisplayMode, FileChangeKind } from "toolcraft-design";
262
262
  export type { DiagnosticLogEvent, LogLevel, RuntimeLogger, RuntimeLoggerInput } from "./runtime-logging.js";
263
- export type { AnySchema, ArraySchema, BooleanSchema, CliMissingParameterChoice, CliMissingParameterContext, CliMissingParameterResolution, CliOutputMode, CliSchemaOptions, EnumSchema, JsonSchema, JsonSchemaDocument, JsonSchemaDocumentOptions, JsonValue, JsonValueSchema, NumberSchema, ObjectSchema, OneOfSchema, OptionalSchema, RecordSchema, SchemaBase, Static, StringSchema, UnionSchema, ValidationIssue, ValidationOptions, ValidationResult } from "./schema.js";
263
+ export type { AnySchema, ArraySchema, BooleanSchema, CliMissingParameterChoice, CliMissingParameterContext, CliMissingParameterResolution, CliOutputMode, CliSchemaOptions, EnumSchema, JsonSchema, JsonSchemaDocument, JsonSchemaDocumentOptions, JsonSchemaOptions, Input, Output, StandardSchema, Standardized, StandardIssue, StandardResult, StandardJsonSchemaOptions, JsonValue, JsonValueSchema, NumberSchema, ObjectSchema, OneOfSchema, OptionalSchema, RecordSchema, SchemaBase, Static, StringSchema, UnionSchema, ValidationIssue, ValidationOptions, ValidationResult } from "./schema.js";
264
264
  export type { HumanInLoopConfig, HumanInLoopPending, HumanInLoopRuntime };
package/dist/index.js CHANGED
@@ -564,7 +564,7 @@ export function hasMcpProxyConfig(group) {
564
564
  const children = config?.children ?? group.children;
565
565
  return children.some((child) => child.kind === "group" && hasMcpProxyConfig(child));
566
566
  }
567
- export { S, toJsonSchema } from "./schema.js";
567
+ export { S, toJsonSchema, withStandardSchema } from "./schema.js";
568
568
  export { AuthenticationError, BadRequestError, ClientError, ConflictError, HttpError, InternalServerError, NotFoundError, PermissionDeniedError, RateLimitError, ServerError, ServiceUnavailableError, UnprocessableEntityError, createHttpError } from "./http-errors.js";
569
569
  export { ApprovalDeclinedError, ToolcraftBugError, UserError, isUserError };
570
570
  export { suggest } from "./suggest.js";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import { S } from "./index.js";
2
+ import { withStandardSchema } from "./schema.js";
3
+ const ignoredSchema = S.Object({ limit: S.Optional(S.Number({ default: 10 })) });
4
+ withStandardSchema(structuredClone(ignoredSchema));
package/dist/schema.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { Json, OneOf, Record, S, Union, toJsonSchema, toJsonSchemaDocument, validate } from "toolcraft-schema";
2
- export type { AnySchema, ArraySchema, BooleanSchema, CliMissingParameterChoice, CliMissingParameterContext, CliMissingParameterResolution, CliOutputMode, CliSchemaOptions, EnumSchema, JsonSchema, JsonSchemaDocument, JsonSchemaDocumentOptions, JsonValue, JsonValueSchema, NumberSchema, ObjectSchema, OneOfSchema, OptionalSchema, RecordSchema, SchemaBase, Static, StringSchema, UnionSchema, ValidationIssue, ValidationOptions, ValidationResult } from "toolcraft-schema";
1
+ export { Json, OneOf, Record, S, Union, toJsonSchema, toJsonSchemaDocument, validate, withStandardSchema } from "toolcraft-schema";
2
+ export type { AnySchema, ArraySchema, BooleanSchema, CliMissingParameterChoice, CliMissingParameterContext, CliMissingParameterResolution, CliOutputMode, CliSchemaOptions, EnumSchema, JsonSchema, JsonSchemaDocument, JsonSchemaDocumentOptions, JsonSchemaOptions, Input, Output, StandardSchema, Standardized, StandardIssue, StandardResult, StandardJsonSchemaOptions, JsonValue, JsonValueSchema, NumberSchema, ObjectSchema, OneOfSchema, OptionalSchema, RecordSchema, SchemaBase, Static, StringSchema, UnionSchema, ValidationIssue, ValidationOptions, ValidationResult } from "toolcraft-schema";
package/dist/schema.js CHANGED
@@ -1 +1 @@
1
- export { Json, OneOf, Record, S, Union, toJsonSchema, toJsonSchemaDocument, validate } from "toolcraft-schema";
1
+ export { Json, OneOf, Record, S, Union, toJsonSchema, toJsonSchemaDocument, validate, withStandardSchema } from "toolcraft-schema";
@@ -73,6 +73,13 @@ By default, programmatic `listenHttp()` uses:
73
73
 
74
74
  `path` is normalized, so `"mcp"` and `"/mcp"` serve the same endpoint.
75
75
 
76
+ The same `.tool()` and `.registerTool()` APIs accept Toolcraft schemas and
77
+ Zod 4.5.4 schemas directly through Standard Schema and Standard JSON Schema.
78
+ No adapter or Zod dependency is added by this package. Handlers receive inferred,
79
+ parsed arguments with defaults and transforms applied; asynchronous refinements
80
+ are awaited. This also works with `createFetchServer` from
81
+ `tiny-http-mcp-server/fetch`.
82
+
76
83
  ### CLI
77
84
 
78
85
  The package ships a `tiny-http-mcp-server` binary:
@@ -18,7 +18,7 @@
18
18
  },
19
19
  {
20
20
  "name": "tiny-http-mcp-server",
21
- "version": "0.1.93",
21
+ "version": "0.1.94",
22
22
  "license": "MIT"
23
23
  },
24
24
  {
@@ -28,7 +28,7 @@
28
28
  },
29
29
  {
30
30
  "name": "tiny-stdio-mcp-server",
31
- "version": "0.1.27",
31
+ "version": "0.1.29",
32
32
  "license": "MIT"
33
33
  },
34
34
  {
@@ -1,6 +1,6 @@
1
- import { type CallToolResult, type HandlerRequestContext, type InputRequiredResult, type ServerOptions, type ToolDefinition, type ToolReturn, type TypedSchema, type TypedOutputSchema } from "tiny-stdio-mcp-server/core";
1
+ import { type CallToolResult, type HandlerRequestContext, type InputRequiredResult, type ServerOptions, type ToolDefinition, type ToolReturn, type ToolInputSchema, type ToolOutputSchema } from "tiny-stdio-mcp-server/core";
2
2
  export { defineSchema, ToolError } from "tiny-stdio-mcp-server/core";
3
- export type { CallToolResult, TypedSchema, TypedOutputSchema } from "tiny-stdio-mcp-server/core";
3
+ export type { CallToolResult, TypedSchema, TypedOutputSchema, ToolInputSchema, ToolOutputSchema } from "tiny-stdio-mcp-server/core";
4
4
  export interface FetchServerOptions extends ServerOptions {
5
5
  /** Defaults to 1 MiB. Enforced while reading the stream. */
6
6
  maxRequestBytes?: number;
@@ -15,7 +15,7 @@ export interface FetchToolContext<TContext> extends HandlerRequestContext {
15
15
  }
16
16
  export type FetchToolHandler<TIn, TContext, TOut = ToolReturn> = (input: TIn, context: FetchToolContext<TContext>) => TOut | CallToolResult | InputRequiredResult | Promise<TOut | CallToolResult | InputRequiredResult>;
17
17
  export interface FetchServer<TContext = undefined> {
18
- tool<TIn, TOut = never>(name: string, description: string, schema: TypedSchema<TIn>, handler: FetchToolHandler<TIn, TContext, TOut>, outputSchema?: TypedOutputSchema<TOut>): FetchServer<TContext>;
18
+ tool<TIn, TOut = never>(name: string, description: string, schema: ToolInputSchema<TIn>, handler: FetchToolHandler<TIn, TContext, TOut>, outputSchema?: ToolOutputSchema<TOut>): FetchServer<TContext>;
19
19
  registerTool<TIn, TOut = never>(definition: Omit<ToolDefinition<TIn, TOut>, "handler">, handler: FetchToolHandler<TIn, TContext, TOut>): FetchServer<TContext>;
20
20
  fetch(request: Request, ...context: undefined extends TContext ? [context?: TContext] : [context: TContext]): Promise<Response>;
21
21
  }
@@ -1,5 +1,5 @@
1
1
  import { type IncomingMessage, type ServerResponse } from "node:http";
2
- import { type Server, type ServerOptions, type ToolDefinition, type CallToolResult, type InputRequiredResult, type HandlerRequestContext, type ToolReturn, type TypedSchema, type TypedOutputSchema } from "tiny-stdio-mcp-server";
2
+ import { type Server, type ServerOptions, type ToolDefinition, type CallToolResult, type InputRequiredResult, type HandlerRequestContext, type ToolReturn, type ToolInputSchema, type ToolOutputSchema } from "tiny-stdio-mcp-server";
3
3
  import { type AuthenticatedIncomingMessage, type TokenVerifier, type VerifiedAccessToken, type RequestAuthInfo } from "./auth.js";
4
4
  import { type HttpObservabilityEvent, type StreamableHttpTransportOptions } from "./http-transport.js";
5
5
  export interface ProtectedResourceMetadataOptions {
@@ -33,7 +33,7 @@ export interface HttpServerHandle {
33
33
  closeAllConnections(): void;
34
34
  }
35
35
  export interface HttpServer extends Omit<Server, "tool" | "registerTool"> {
36
- tool<TIn, TOut = never>(name: string, description: string, inputSchema: TypedSchema<TIn>, handler: HttpToolHandler<TIn, TOut>, outputSchema?: TypedOutputSchema<TOut>): HttpServer;
36
+ tool<TIn, TOut = never>(name: string, description: string, inputSchema: ToolInputSchema<TIn>, handler: HttpToolHandler<TIn, TOut>, outputSchema?: ToolOutputSchema<TOut>): HttpServer;
37
37
  registerTool<TIn, TOut = never>(definition: Omit<ToolDefinition<TIn, TOut>, "handler">, handler: HttpToolHandler<TIn, TOut>): HttpServer;
38
38
  listenHttp(options?: HttpListenOptions): Promise<HttpServerHandle>;
39
39
  handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void>;
@@ -1,5 +1,5 @@
1
1
  export { createServer, defineSchema, Image, Audio, File, toContentBlocks, fileTypeFromBuffer, JSON_RPC_ERROR_CODES, ToolError } from "tiny-stdio-mcp-server";
2
- export type { Server, MessageRequestContext, MessageSession, MessageSessionContext, TypedSchema, TypedOutputSchema, ImageContent, AudioContent, EmbeddedResource, TextResourceContents, BlobResourceContents, ContentBlock, TextContent, FileTypeResult, ToolReturn, ServerOptions, ToolHandler, HandlerRequestContext, InputRequiredResult, ToolDefinition, Tool, ToolAnnotations, ToolExecution, Icon, ContentAnnotations, ResourceLink, CallToolResult, PromptContentItem, PromptArgument, Prompt, PromptMessage, GetPromptResult, PromptHandler, PromptDefinition, Resource, ResourceTemplate, ResourceContents, ReadResourceResult, ResourceHandler, ResourceDefinition, ResourceTemplateDefinition, HandleResult, ContentItem, JSONSchema, OutputSchema, JSONSchemaProperty, Transport, SDKTransport, JSONRPCRequest, JSONRPCResponse, JSONRPCError, JSONRPCMessage, JSONRPCNotification, InitializeResult, DiscoverResult } from "tiny-stdio-mcp-server";
2
+ export type { Server, MessageRequestContext, MessageSession, MessageSessionContext, TypedSchema, TypedOutputSchema, ToolInputSchema, ToolOutputSchema, ImageContent, AudioContent, EmbeddedResource, TextResourceContents, BlobResourceContents, ContentBlock, TextContent, FileTypeResult, ToolReturn, ServerOptions, ToolHandler, HandlerRequestContext, InputRequiredResult, ToolDefinition, Tool, ToolAnnotations, ToolExecution, Icon, ContentAnnotations, ResourceLink, CallToolResult, PromptContentItem, PromptArgument, Prompt, PromptMessage, GetPromptResult, PromptHandler, PromptDefinition, Resource, ResourceTemplate, ResourceContents, ReadResourceResult, ResourceHandler, ResourceDefinition, ResourceTemplateDefinition, HandleResult, ContentItem, JSONSchema, OutputSchema, JSONSchemaProperty, Transport, SDKTransport, JSONRPCRequest, JSONRPCResponse, JSONRPCError, JSONRPCMessage, JSONRPCNotification, InitializeResult, DiscoverResult } from "tiny-stdio-mcp-server";
3
3
  export { createExpressMiddleware, createExpressOAuthHandlers, createProtectedResourceMetadataRouter } from "./express-middleware.js";
4
4
  export type { CreateExpressOAuthHandlersOptions } from "./express-middleware.js";
5
5
  export { createHttpServer, createProtectedResourceMetadataDocument } from "./http-server.js";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiny-http-mcp-server",
3
- "version": "0.1.93",
3
+ "version": "0.1.94",
4
4
  "description": "Minimal MCP server over HTTP built on tiny-stdio-mcp-server",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  # tiny-stdio-mcp-server
2
2
 
3
- Minimal [Model Context Protocol](https://modelcontextprotocol.io) server for Node.js. Zero runtime dependencies, type-safe tool definitions, rich content helpers for images/audio/files.
3
+ Minimal [Model Context Protocol](https://modelcontextprotocol.io) server for Node.js. Type-safe tool definitions, rich content helpers for images/audio/files.
4
4
 
5
5
  ## Install
6
6
 
@@ -89,14 +89,52 @@ server.tool(
89
89
  );
90
90
  ```
91
91
 
92
- Output schemas must have `type: "object"` at the root because MCP structured content is an object. Otherwise, any schema accepted by Ajv is supported, including composition keywords, nullable type unions, and local `$defs`/`$ref` references. Input and output schemas compile synchronously during `.tool()` or `.registerTool()` registration, so malformed schemas throw immediately instead of failing on the first tool call.
92
+ Object output schemas work across MCP versions; modern MCP also supports other JSON output types. Otherwise, supported JSON Schema keywords are accepted, including composition keywords, nullable type unions, and local `$defs`/`$ref` references. Input and output schemas compile synchronously during `.tool()` or `.registerTool()` registration, so malformed schemas throw immediately instead of failing on the first tool call.
93
93
 
94
- Successful structured results must satisfy `outputSchema`. Validation failures use JSON-RPC `-32602` for inputs and `-32603` for outputs, with Ajv's formatted error text in the message and the raw Ajv error array in `error.data`. Explicit handler results with `isError: true` are passed through unchanged and are exempt from structured-content and output-schema validation.
94
+ Successful structured results must satisfy `outputSchema`. Validation failures use JSON-RPC `-32602` for inputs and `-32603` for outputs, with formatted validation details in the message and the issue array in `error.data`. Explicit handler results with `isError: true` are passed through unchanged and are exempt from structured-content and output-schema validation.
95
95
 
96
96
  Tools whose natural result is prose, images, audio, files, or other content blocks should omit `outputSchema` and keep returning content.
97
97
 
98
98
  Handlers can throw `ToolError` to return a JSON-RPC tool error with a specific code, message, and optional structured `data` payload. The server forwards that `data` field in the JSON-RPC error response so clients can inspect machine-readable failure details.
99
99
 
100
+ ### Standard schemas, including Zod
101
+
102
+ Pass schemas implementing Standard Schema v1 and Standard JSON Schema v1
103
+ straight to `.tool()` or `.registerTool()`. Toolcraft schemas and Zod 4.5.4
104
+ support both interfaces. Existing `defineSchema` and raw JSON Schema inputs
105
+ continue to work on the same server.
106
+
107
+ ```ts
108
+ import { z } from "zod"; // Your application's existing dependency
109
+ import { createServer } from "tiny-stdio-mcp-server";
110
+
111
+ createServer({ name: "search", version: "1" }).tool(
112
+ "search",
113
+ "Search",
114
+ z.object({ query: z.string(), limit: z.number().default(10) }),
115
+ ({ query, limit }) => `${query}: ${limit}`
116
+ );
117
+ ```
118
+
119
+ Tiny MCP has no Zod dependency, peer dependency, imports, or adapter setup.
120
+ Detection uses the standard interfaces. Older libraries exposing validation
121
+ without JSON Schema conversion fail clearly during registration.
122
+
123
+ Discovery uses the schema's input JSON Schema and, when supplied, its output
124
+ JSON Schema. Runtime parsing uses the original library, preserving defaults,
125
+ coercions, transforms, refinements, and asynchronous validation. Handler arguments
126
+ are inferred from parsed output; a handler's return value is checked against the
127
+ output schema's accepted input. Output parsing runs once before structured content
128
+ and fallback text are produced. Explicit error results skip output parsing.
129
+
130
+ Input wire schemas must describe objects. Output schemas may describe any JSON
131
+ value for modern MCP; older clients receive object structured content or text
132
+ fallbacks for other values. Conversion failures occur at registration. Custom
133
+ refinements remain runtime checks and cannot always appear in discovery JSON
134
+ Schema. Async parsing shares the tool timeout and concurrency limits.
135
+ `validateToolArguments: false` disables input parsing, including defaults and
136
+ transforms; handlers then receive the original arguments.
137
+
100
138
  ### `.listen()`
101
139
 
102
140
  Start listening on stdin/stdout (standard MCP stdio transport).
@@ -8,7 +8,7 @@
8
8
  },
9
9
  {
10
10
  "name": "toolcraft-schema",
11
- "version": "0.0.430",
11
+ "version": "0.0.432",
12
12
  "license": "MIT"
13
13
  }
14
14
  ]
@@ -2,7 +2,7 @@
2
2
  export { createProtocolServer } from "./protocol-server.js";
3
3
  export type { Server, MessageRequestContext, MessageSession } from "./protocol-server.js";
4
4
  export { defineSchema } from "./schema.js";
5
- export type { TypedSchema, TypedOutputSchema } from "./schema.js";
5
+ export type { TypedSchema, TypedOutputSchema, ToolInputSchema, ToolOutputSchema } from "./schema.js";
6
6
  export { ToolError } from "./types.js";
7
7
  export type { CallToolResult, HandlerRequestContext, InputRequiredResult, ServerOptions, ToolDefinition } from "./types.js";
8
8
  export type { ToolReturn } from "./content/convert.js";
@@ -1,7 +1,7 @@
1
1
  export { createServer } from "./server.js";
2
2
  export type { CustomMethodHandler, MessageHandler, MessageRequestContext, MessageSession, MessageSessionContext, Server } from "./server.js";
3
3
  export { defineSchema } from "./schema.js";
4
- export type { TypedSchema, TypedOutputSchema } from "./schema.js";
4
+ export type { TypedSchema, TypedOutputSchema, ToolInputSchema, ToolOutputSchema } from "./schema.js";
5
5
  export { Image, Audio, File, toContentBlocks, fileTypeFromBuffer, DEFAULT_FROM_URL_MAX_BYTES } from "./content/index.js";
6
6
  export type { ImageContent, AudioContent, EmbeddedResource, TextResourceContents, BlobResourceContents, ContentBlock, TextContent, FileTypeResult, FromUrlOptions } from "./content/index.js";
7
7
  export type { ToolReturn } from "./content/index.js";
@@ -1,12 +1,12 @@
1
1
  import type { ServerOptions, ToolDefinition, ToolHandler, HandleResult, Prompt, PromptHandler, Resource, ResourceHandler, ResourceTemplate, Transport, SDKTransport, JSONRPCNotification } from "./types.js";
2
- import type { TypedSchema, TypedOutputSchema } from "./schema.js";
2
+ import type { ToolInputSchema, ToolOutputSchema } from "./schema.js";
3
3
  interface StdioRuntime {
4
4
  readline: typeof import("node:readline");
5
5
  StdioInput: typeof import("./stdio-input.js").StdioInput;
6
6
  StdioOutput: typeof import("./stdio-output.js").StdioOutput;
7
7
  }
8
8
  export interface Server {
9
- tool<TIn, TOut = never>(name: string, description: string, inputSchema: TypedSchema<TIn>, handler: ToolHandler<TIn, TOut>, outputSchema?: TypedOutputSchema<TOut>): Server;
9
+ tool<TIn, TOut = never>(name: string, description: string, inputSchema: ToolInputSchema<TIn>, handler: ToolHandler<TIn, TOut>, outputSchema?: ToolOutputSchema<TOut>): Server;
10
10
  registerTool<TIn, TOut = never>(definition: Omit<ToolDefinition<TIn, TOut>, "handler">, handler: ToolHandler<TIn, TOut>): Server;
11
11
  prompt(definition: Prompt, handler: PromptHandler): Server;
12
12
  resource(definition: Resource, handler: ResourceHandler): Server;
@@ -1,4 +1,4 @@
1
- import { compileJsonSchema, formatIssues, normalizeLegacyNullability } from "toolcraft-schema";
1
+ import { prepareToolSchema, formatToolIssues } from "./tool-schema.js";
2
2
  import { JSON_RPC_ERROR_CODES, ToolError } from "./types.js";
3
3
  import { parseMessage, formatSuccessResponse, formatErrorResponse, isRequestId } from "./jsonrpc.js";
4
4
  import { parseUriTemplate } from "./uri-template.js";
@@ -38,15 +38,6 @@ function createLifecycleState(listener, supportNotifications, supportResourceSub
38
38
  listener
39
39
  };
40
40
  }
41
- function compileToolSchema(schema) {
42
- try {
43
- return compileJsonSchema(schema);
44
- }
45
- catch (error) {
46
- const message = error instanceof Error ? error.message : String(error);
47
- throw new Error(`schema is invalid: ${message}`, { cause: error });
48
- }
49
- }
50
41
  export function createProtocolServer(options, stdio) {
51
42
  if (options.toolCallTimeoutMs !== undefined &&
52
43
  (!Number.isInteger(options.toolCallTimeoutMs) || options.toolCallTimeoutMs <= 0)) {
@@ -215,15 +206,15 @@ export function createProtocolServer(options, stdio) {
215
206
  if (headerError !== undefined)
216
207
  return { error: { code: -32020, message: headerError } };
217
208
  }
218
- const inputValidation = tool.inputValidator.validate(toolArgs);
219
- if (options.validateToolArguments !== false && !inputValidation.ok) {
220
- return {
221
- error: {
222
- code: JSON_RPC_ERROR_CODES.INVALID_PARAMS,
223
- message: `Invalid tool arguments: ${formatIssues(inputValidation.issues)}`,
224
- data: inputValidation.issues
225
- }
226
- };
209
+ // Raw JSON Schema validation is synchronous and can reject before taking a queue slot.
210
+ if (options.validateToolArguments !== false && !tool.inputValidator.standard) {
211
+ const validation = tool.inputValidator.validate(toolArgs);
212
+ if (validation.issues !== undefined)
213
+ return { error: {
214
+ code: JSON_RPC_ERROR_CODES.INVALID_PARAMS,
215
+ message: `Invalid tool arguments: ${formatToolIssues(validation.issues)}`,
216
+ data: validation.issues
217
+ } };
227
218
  }
228
219
  try {
229
220
  let handlerResult;
@@ -242,7 +233,20 @@ export function createProtocolServer(options, stdio) {
242
233
  const release = await toolAdmission.acquire(admissionSignal);
243
234
  try {
244
235
  admissionSignal.throwIfAborted();
245
- return await tool.handler(toolArgs, { ...handlerContext, signal: admissionSignal });
236
+ let parsedArgs = toolArgs;
237
+ if (options.validateToolArguments !== false && tool.inputValidator.standard) {
238
+ const inputValidation = await tool.inputValidator.validate(toolArgs);
239
+ if (inputValidation.issues !== undefined) {
240
+ throw new ToolError(JSON_RPC_ERROR_CODES.INVALID_PARAMS, `Invalid tool arguments: ${formatToolIssues(inputValidation.issues)}`, inputValidation.issues);
241
+ }
242
+ parsedArgs = inputValidation.value;
243
+ }
244
+ admissionSignal.throwIfAborted();
245
+ const returned = await tool.handler(parsedArgs, { ...handlerContext, signal: admissionSignal });
246
+ admissionSignal.throwIfAborted();
247
+ if (modern && isInputRequiredResult(returned))
248
+ return returned;
249
+ return await normalizeValidatedToolResult(returned, tool, modern);
246
250
  }
247
251
  finally {
248
252
  release();
@@ -274,15 +278,7 @@ export function createProtocolServer(options, stdio) {
274
278
  lifecycle.admissions.delete(admissionController);
275
279
  sessionSignal.removeEventListener("abort", cancelAdmission);
276
280
  }
277
- if (modern && isInputRequiredResult(handlerResult))
278
- return { result: handlerResult };
279
- const outputSchema = modern || tool.outputSchema?.type === "object" ? tool.outputSchema : undefined;
280
- const result = normalizeToolResult(handlerResult, tool.outputSchema, modern);
281
- const outputValidation = outputSchema === undefined ? undefined : tool.outputValidator?.validate(result.structuredContent);
282
- if (result.isError !== true && outputValidation !== undefined && !outputValidation.ok) {
283
- throw new ToolError(JSON_RPC_ERROR_CODES.INTERNAL_ERROR, `Invalid structured tool result: ${formatIssues(outputValidation.issues)}`, outputValidation.issues);
284
- }
285
- return { result };
281
+ return { result: handlerResult };
286
282
  }
287
283
  catch (err) {
288
284
  if (err instanceof ToolError) {
@@ -614,15 +610,13 @@ export function createProtocolServer(options, stdio) {
614
610
  if (tools.has(name)) {
615
611
  throw new Error(`Tool already registered: ${name}`);
616
612
  }
617
- const inputSchemaSnapshot = normalizeLegacyNullability(inputSchema);
618
- const outputSchemaSnapshot = outputSchema === undefined ? undefined : normalizeLegacyNullability(outputSchema);
619
- const inputValidator = compileToolSchema(inputSchemaSnapshot);
613
+ const inputValidator = prepareToolSchema(inputSchema, "input");
614
+ const inputSchemaSnapshot = inputValidator.schema;
620
615
  assertObjectRootSchema(inputSchemaSnapshot, "inputSchema");
621
- let outputValidator;
622
- if (outputSchemaSnapshot !== undefined) {
616
+ const outputValidator = outputSchema === undefined ? undefined : prepareToolSchema(outputSchema, "output");
617
+ const outputSchemaSnapshot = outputValidator?.schema;
618
+ if (outputSchemaSnapshot !== undefined)
623
619
  assertOutputSchema(outputSchemaSnapshot);
624
- outputValidator = compileToolSchema(outputSchemaSnapshot);
625
- }
626
620
  tools.set(name, {
627
621
  name,
628
622
  description,
@@ -640,19 +634,18 @@ export function createProtocolServer(options, stdio) {
640
634
  if (tools.has(definition.name)) {
641
635
  throw new Error(`Tool already registered: ${definition.name}`);
642
636
  }
643
- const descriptor = structuredClone(definition);
644
- const inputSchema = normalizeLegacyNullability(descriptor.inputSchema);
645
- const inputValidator = compileToolSchema(inputSchema);
637
+ const { inputSchema: sourceInput, outputSchema: sourceOutput, ...metadata } = definition;
638
+ const descriptor = structuredClone(metadata);
639
+ const inputValidator = prepareToolSchema(sourceInput, "input");
640
+ const inputSchema = inputValidator.schema;
646
641
  assertObjectRootSchema(inputSchema, "inputSchema");
647
- let outputValidator;
648
- if (descriptor.outputSchema !== undefined) {
649
- descriptor.outputSchema = normalizeLegacyNullability(descriptor.outputSchema);
650
- assertOutputSchema(descriptor.outputSchema);
651
- outputValidator = compileToolSchema(descriptor.outputSchema);
652
- }
642
+ const outputValidator = sourceOutput === undefined ? undefined : prepareToolSchema(sourceOutput, "output");
643
+ if (outputValidator !== undefined)
644
+ assertOutputSchema(outputValidator.schema);
653
645
  tools.set(definition.name, {
654
646
  ...descriptor,
655
647
  inputSchema,
648
+ ...(outputValidator === undefined ? {} : { outputSchema: outputValidator.schema }),
656
649
  handler: handler,
657
650
  inputValidator,
658
651
  parameterHeaders: getParameterHeaders(inputSchema),
@@ -987,6 +980,26 @@ function isCallToolResult(value, modern) {
987
980
  value.isError !== undefined &&
988
981
  typeof value.isError !== "boolean");
989
982
  }
983
+ async function normalizeValidatedToolResult(returned, tool, modern) {
984
+ const validator = tool.outputValidator;
985
+ if (validator?.standard && !(isCallToolResult(returned, modern) && returned.isError === true)) {
986
+ const envelope = isCallToolResult(returned, modern) ? returned : undefined;
987
+ const parsed = await validator.validate(envelope === undefined ? returned : envelope.structuredContent);
988
+ if (parsed.issues !== undefined) {
989
+ throw new ToolError(JSON_RPC_ERROR_CODES.INTERNAL_ERROR, `Invalid structured tool result: ${formatToolIssues(parsed.issues)}`, parsed.issues);
990
+ }
991
+ returned = envelope === undefined ? parsed.value : { ...envelope, structuredContent: parsed.value };
992
+ }
993
+ const result = normalizeToolResult(returned, tool.outputSchema, modern);
994
+ if (result.isError !== true && validator !== undefined && !validator.standard &&
995
+ (modern || tool.outputSchema?.type === "object")) {
996
+ const validation = await validator.validate(result.structuredContent);
997
+ if (validation.issues !== undefined) {
998
+ throw new ToolError(JSON_RPC_ERROR_CODES.INTERNAL_ERROR, `Invalid structured tool result: ${formatToolIssues(validation.issues)}`, validation.issues);
999
+ }
1000
+ }
1001
+ return result;
1002
+ }
990
1003
  function normalizeToolResult(handlerResult, outputSchema, modern) {
991
1004
  if (!modern && outputSchema !== undefined && outputSchema.type !== "object") {
992
1005
  const result = normalizeToolResult(handlerResult, outputSchema, true);
@@ -1,4 +1,7 @@
1
1
  import type { JSONSchema, OutputSchema } from "./types.js";
2
+ import type { StandardSchema } from "toolcraft-schema";
3
+ export type ToolInputSchema<T> = TypedSchema<T> | StandardSchema<unknown, T>;
4
+ export type ToolOutputSchema<T> = TypedOutputSchema<T> | StandardSchema<T, unknown>;
2
5
  type SchemaPropertyType = "string" | "number" | "integer" | "boolean" | "object" | "array";
3
6
  interface SchemaPropertyDef {
4
7
  type: SchemaPropertyType;
@@ -0,0 +1,15 @@
1
+ import { S } from "toolcraft-schema";
2
+ import { createServer, defineSchema } from "./index.js";
3
+ const server = createServer({ name: "inference", version: "1" });
4
+ const schema = S.Object({ count: S.Optional(S.Number({ default: 10 })) });
5
+ server.tool("count", "Count", schema, ({ count }) => {
6
+ const result = count;
7
+ // @ts-expect-error The default produces a number, not a string.
8
+ const ignoredWrong = count;
9
+ return { count: result };
10
+ }, S.Object({ count: S.Number() }));
11
+ server.registerTool({ name: "registered", inputSchema: schema }, ({ count }) => String(count + 1));
12
+ server.tool("transform", "Transform", transformed, ({ count }) => count.toFixed());
13
+ server.tool("output", "Output", defineSchema({}), () => ({ count: "1" }), transformed);
14
+ // @ts-expect-error The output parser requires a string before transformation.
15
+ server.tool("invalid", "Invalid", defineSchema({}), () => ({ count: false }), transformed);
@@ -0,0 +1,13 @@
1
+ import { type StandardIssue, type StandardResult } from "toolcraft-schema";
2
+ import { type OutputSchema } from "./types.js";
3
+ export type PreparedToolSchema = {
4
+ schema: OutputSchema;
5
+ } & ({
6
+ standard: false;
7
+ validate(value: unknown): StandardResult<unknown>;
8
+ } | {
9
+ standard: true;
10
+ validate(value: unknown): StandardResult<unknown> | Promise<StandardResult<unknown>>;
11
+ });
12
+ export declare function prepareToolSchema(source: unknown, io: "input" | "output"): PreparedToolSchema;
13
+ export declare function formatToolIssues(issues: readonly StandardIssue[]): string;
@@ -0,0 +1,53 @@
1
+ import { compileJsonSchema, normalizeLegacyNullability } from "toolcraft-schema";
2
+ import { ToolError, JSON_RPC_ERROR_CODES } from "./types.js";
3
+ export function prepareToolSchema(source, io) {
4
+ try {
5
+ let standard;
6
+ if (((typeof source === "object" && source !== null) || typeof source === "function") && "~standard" in source) {
7
+ standard = source["~standard"];
8
+ if (standard?.version !== 1 || typeof standard.validate !== "function") {
9
+ throw new Error("Expected Standard Schema v1 validation");
10
+ }
11
+ if (typeof standard.jsonSchema?.[io] !== "function") {
12
+ throw new Error("Expected Standard JSON Schema v1 conversion; upgrade the schema library or provide a JSON Schema");
13
+ }
14
+ }
15
+ const document = standard === undefined ? source : standard.jsonSchema[io]({ target: "draft-2020-12" });
16
+ if (typeof document !== "object" || document === null || Array.isArray(document)) {
17
+ throw new Error(`${io}Schema must be a JSON Schema object`);
18
+ }
19
+ const schema = normalizeLegacyNullability(document);
20
+ const compiled = compileJsonSchema(schema);
21
+ if (standard !== undefined)
22
+ return {
23
+ schema,
24
+ standard: true,
25
+ async validate(value) {
26
+ try {
27
+ return await standard.validate(value);
28
+ }
29
+ catch {
30
+ throw new ToolError(JSON_RPC_ERROR_CODES.INTERNAL_ERROR, "Tool schema validation failed");
31
+ }
32
+ }
33
+ };
34
+ return {
35
+ schema,
36
+ standard: false,
37
+ validate(value) {
38
+ const result = compiled.validate(value);
39
+ return result.ok ? { value: result.value } : { issues: result.issues };
40
+ }
41
+ };
42
+ }
43
+ catch (error) {
44
+ const message = error instanceof Error ? error.message : String(error);
45
+ throw new Error(`${io} schema is invalid: ${message}`, { cause: error });
46
+ }
47
+ }
48
+ export function formatToolIssues(issues) {
49
+ return issues.map((issue) => {
50
+ const path = issue.path?.map((segment) => String(typeof segment === "object" ? segment.key : segment)).join("/");
51
+ return `${path ? `data/${path}` : "data"} ${issue.message}`;
52
+ }).join(", ");
53
+ }
@@ -1,3 +1,4 @@
1
+ import type { ToolInputSchema, ToolOutputSchema } from "./schema.js";
1
2
  export interface JSONRPCRequest {
2
3
  jsonrpc: "2.0";
3
4
  id: string | number | null;
@@ -270,8 +271,8 @@ export interface ToolDefinition<T = Record<string, unknown>, TOut = ToolReturn>
270
271
  name: string;
271
272
  title?: string;
272
273
  description?: string;
273
- inputSchema: JSONSchema;
274
- outputSchema?: OutputSchema;
274
+ inputSchema: ToolInputSchema<T>;
275
+ outputSchema?: ToolOutputSchema<TOut>;
275
276
  annotations?: ToolAnnotations;
276
277
  execution?: ToolExecution;
277
278
  icons?: Icon[];