Skip to content

v0.3.0

Latest

Choose a tag to compare

@bradburch bradburch released this 28 Sep 00:48
· 8 commits to main since this release
453c7a8

Added

  • defineTool(...) — FastMCP-style typed tools: input is inferred from inputSchema and a
    mutating tool's execute(data) is typed from preview's data, so handlers need no casts.
  • Handlers and execute may return a plain string (→ one text block) or any JSON-serializable
    value (→ JSON text block); an MCP { content: [...] } result still passes through unchanged.
  • ToolError — throw it from a handler, preview, or execute to reject with a message the
    client sees verbatim (e.g. "09:00 is already booked"). Any other error stays generic.
  • onToolError hook, fired when a handler/preview/execute throws or returns an
    unserializable value, or a storage call in the mutating flow fails (phase: "storage") —
    the real error is no longer invisible to the operator. A storage failure before
    execute releases the idempotency claim so a retry can run.
  • onToolCall now also fires for mutating-tool calls (the preview step).
  • name / version config options for the server identity reported on initialize.

Changed

  • Breaking: createMcpServer now throws at construction on duplicate tool names, a tool
    named confirm_request (reserved), a tool scope not declared in scopes, or an
    inputSchema that isn't a z.object. That includes object schemas wrapped in
    .transform() / .pipe() / .default() / .readonly(), and — under zod 3 — .refine() /
    .superRefine() / .brand(). Such tools previously started but were advertised with an
    empty input schema and received unvalidated input; move that logic into the handler.
  • Behavior: the whole z.object (not just its .shape) is passed to the SDK, so zod 4
    .refine() checks on an input schema now actually run (they were silently skipped).
    This also makes .strict() objects reject unknown keys (JSON-RPC -32602; previously
    stripped) and .passthrough() objects forward them to the handler (previously stripped),
    and tools/list now reflects both via additionalProperties plus any object-level
    .describe(). Plain z.object schemas are advertised exactly as before.
  • Behavior: onToolCall fires when a tool is invoked, concurrently with the handler
    (previously after it returned).
  • Behavior: an error thrown by a mutating tool's preview or execute no longer reaches
    the client verbatim — throw ToolError for messages meant for the client.
  • @modelcontextprotocol/sdk peer range raised from ^1 to ^1.25.0, the first release
    shipping the web-standard transport this kit imports.
  • Untyped ToolDef handler input is unknown under zod 3 too (was any).
  • Dependencies updated (vitest 5, hono 4.13, zod 4.6, SDK 1.30.1, eslint 10.11); npm run typecheck now also covers test/ and examples/.

Fixed

  • Replaying confirm_request with the same idempotencyKey returned the cached result
    JSON-stringified inside a text block instead of the original result; a corrupt cached
    entry now yields a generic error instead of a parser message.
  • A mutating tool whose side effect succeeded could be reported as failed — and its
    idempotency claim released, so a retry executed it twice — if its result couldn't be
    serialized or onMutation threw. Both now keep the claim and return success.
  • An error thrown by a handler, preview, or execute, or a handler return value that
    couldn't be serialized (BigInt, cycles), leaked its raw message to the client.
  • An object return value that merely has a content array (e.g. { id, content: [1, 2] })
    was passed through as a malformed tool result; it's now JSON-serialized.