h3-mcp logoh3-mcp

Exports

Everything h3-mcp exports at runtime.

The runtime surface is deliberately small: one handler factory, four identity helpers for type inference, and one error class. Everything else is types.

#defineMcpHandler(handlerOpts)

Define an H3 event handler that implements the Model Context Protocol (MCP) over HTTP using JSON-RPC 2.0 as the wire format.

The handler is dual-era: a POST whose params._meta["io.modelcontextprotocol/protocolVersion"] is set is served statelessly per 2026-07-28; anything else (including initialize and MCP-Session-Id traffic) takes the legacy ≤2025-11-25 path. Use era: "modern" or era: "legacy" to serve only one.

To also drop the unused era from your bundle, import from h3-mcp/modern or h3-mcp/legacy instead — those entrypoints never reference the other era's implementation.

Example:

app.all(
  "/mcp",
  defineMcpHandler({
    name: "my-server",
    version: "1.0.0",
    tools: [echoTool],
    resources: [readmeResource],
    prompts: [greetPrompt],
  }),
);

Example:

// Dynamic options based on request context
app.all(
  "/mcp",
  defineMcpHandler((event) => ({
    name: "my-server",
    version: "1.0.0",
    tools: getToolsForUser(event),
  })),
);

#defineMcpPrompt(definition)

Define an MCP prompt with optional arguments and a handler that returns messages.

Example:

// Prompt with arguments
const greetPrompt = defineMcpPrompt({
  name: "greet",
  description: "Generate a greeting",
  args: [{ name: "name", required: true }],
  handler: async (args, event) => ({
    messages: [
      { role: "user", content: { type: "text", text: `Hello ${args.name}!` } },
    ],
  }),
});

Example:

// Prompt without arguments
const helpPrompt = defineMcpPrompt({
  name: "help",
  description: "Show help information",
  handler: async (event) => ({
    messages: [
      { role: "user", content: { type: "text", text: "How can I help?" } },
    ],
  }),
});

#defineMcpResource(definition)

Define an MCP resource with a static URI and a handler that returns its contents.

Example:

const readmeResource = defineMcpResource({
  name: "readme",
  uri: "file:///readme",
  description: "Project README",
  mimeType: "text/markdown",
  handler: async (uri, event) => ({
    contents: [{ uri: uri.toString(), text: "# My Project" }],
  }),
});

#defineMcpResourceTemplate(definition)

Define an MCP resource template with a URI template (RFC 6570) and a handler.

Resource templates expose parameterized resources. Clients fill in template parameters and call resources/read with the expanded URI.

Example:

const fileTemplate = defineMcpResourceTemplate({
  name: "file",
  uriTemplate: "file:///{path}",
  description: "Read a file by path",
  mimeType: "text/plain",
  handler: async (uri, event) => ({
    contents: [{ uri: uri.toString(), text: `Contents of ${uri.pathname}` }],
  }),
});

#defineMcpTool(definition)

Define an MCP tool with a name, optional JSON Schema input, and a handler function.

Example:

// Tool with input parameters
const echoTool = defineMcpTool({
  name: "echo",
  description: "Echo back a message",
  inputSchema: {
    type: "object",
    properties: { message: { type: "string" } },
    required: ["message"],
  },
  handler: async (args, event) => ({
    content: [{ type: "text", text: args.message as string }],
  }),
});

Example:

// Tool without input parameters
const pingTool = defineMcpTool({
  name: "ping",
  description: "Returns pong",
  handler: async (event) => ({
    content: [{ type: "text", text: "pong" }],
  }),
});

#McpJsonRpcError()

#McpJsonRpcError

A JSON-RPC error with an explicit code and HTTP status — the one error class whose message reaches the client verbatim on the modern era.

import { McpJsonRpcError } from "h3-mcp";

throw new McpJsonRpcError(-32602, "Widget id must be a UUID", { status: 400 });

new McpJsonRpcError(code, message, { status?, data? }). When status is omitted it defaults per code: -32601404, -32603500, otherwise 400. McpJsonRpcError.isMcpJsonRpcError(value) is a type guard.

Read more in Errors.

#Era Entrypoints

h3-mcp/modern and h3-mcp/legacy export the same helpers and error class, plus a single-era defineMcpHandler and the version it serves:

Exporth3-mcph3-mcp/modernh3-mcp/legacy
defineMcpHandler✅ dual✅ modern-only✅ legacy-only
defineMcpTool
defineMcpResource
defineMcpResourceTemplate
defineMcpPrompt
McpJsonRpcError
MCP_PROTOCOL_VERSION2026-07-28
MCP_LEGACY_PROTOCOL_VERSION2025-11-25
all types

Each entrypoint is self-contained — never import from two of them in the same file, or you defeat the bundle split.

Read more in Entrypoints.

#Types

Every type is exported from each entrypoint. The ones you are most likely to name explicitly:

TypeUse
McpHandlerOptionsThe options object
McpToolDefinition · McpResourceDefinition · McpResourceTemplateDefinition · McpPromptDefinitionDefinition shapes
McpCallToolResult · McpReadResourceResult · McpGetPromptResultHandler return values
McpContentBlock · McpIconContent and icons
McpRequestContextevent.context.mcp
McpInputRequiredResult · McpInputRequests · McpInputResponsesMRTR
McpSubscription · McpSubscriptionFilter · McpSubscriptionOptionsSubscriptions
McpCacheOptions · McpCacheHints · McpCacheScopeCaching
McpAuthOptions · McpOriginOptions · McpLimitsOptions · McpSessionOptionsSecurity
McpEra · McpImplementation · McpClientCapabilities · McpExtensionsEra and identity
StandardSchemaV1 · StandardJSONSchemaV1 · StandardTypedV1Standard Schema (vendored)

h3-mcp also augments h3's H3EventContext with mcp?: McpRequestContext, so event.context.mcp is typed everywhere once the package is imported.

#Deprecated but Functional

These are legacy-era features removed in 2026-07-28. They still work and are not going away — the JSDoc @deprecated marks are there to point you at the modern replacement:

DeprecatedModern replacement
sessionstateless requests; explicit handles in tool arguments
onStreamonListen (subscriptions)
onSubscribe / onUnsubscribeonListen
onLogLevelSet_meta log level + mcp.log()
h3-mcp logo

h3-mcp  MCP servers, built on H3.