
# 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.

<!-- automd:jsdocs src="../../../src/index.ts" -->

### `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:**

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

**Example:**

```ts
// 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:**

```ts
// 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:**

```ts
// 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:**

```ts
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:**

```ts
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:**

```ts
// 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:**

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

### `McpJsonRpcError()`

<!-- /automd -->

## `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.

```ts
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: `-32601` → `404`, `-32603` → `500`, otherwise `400`. `McpJsonRpcError.isMcpJsonRpcError(value)` is a type guard.

:read-more{to="/guide/basics/errors" title="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:

| Export                        | `h3-mcp` | `h3-mcp/modern` | `h3-mcp/legacy` |
| ----------------------------- | :------: | :-------------: | :-------------: |
| `defineMcpHandler`            | ✅ dual  | ✅ modern-only  | ✅ legacy-only  |
| `defineMcpTool`               |    ✅    |       ✅        |       ✅        |
| `defineMcpResource`           |    ✅    |       ✅        |       ✅        |
| `defineMcpResourceTemplate`   |    ✅    |       ✅        |       ✅        |
| `defineMcpPrompt`             |    ✅    |       ✅        |       ✅        |
| `McpJsonRpcError`             |    ✅    |       ✅        |       ✅        |
| `MCP_PROTOCOL_VERSION`        |    —     | ✅ `2026-07-28` |        —        |
| `MCP_LEGACY_PROTOCOL_VERSION` |    —     |        —        | ✅ `2025-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{to="/guide/eras#entrypoints" title="Entrypoints"}

## Types

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

| Type                                                                                                    | Use                                          |
| ------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
| `McpHandlerOptions`                                                                                     | The options object                           |
| `McpToolDefinition` · `McpResourceDefinition` · `McpResourceTemplateDefinition` · `McpPromptDefinition` | Definition shapes                            |
| `McpCallToolResult` · `McpReadResourceResult` · `McpGetPromptResult`                                    | Handler return values                        |
| `McpContentBlock` · `McpIcon`                                                                           | Content and icons                            |
| `McpRequestContext`                                                                                     | `event.context.mcp`                          |
| `McpInputRequiredResult` · `McpInputRequests` · `McpInputResponses`                                     | [MRTR](/guide/modern/mrtr)                   |
| `McpSubscription` · `McpSubscriptionFilter` · `McpSubscriptionOptions`                                  | [Subscriptions](/guide/modern/subscriptions) |
| `McpCacheOptions` · `McpCacheHints` · `McpCacheScope`                                                   | [Caching](/guide/modern/caching)             |
| `McpAuthOptions` · `McpOriginOptions` · `McpLimitsOptions` · `McpSessionOptions`                        | [Security](/security)                        |
| `McpEra` · `McpImplementation` · `McpClientCapabilities` · `McpExtensions`                              | Era and identity                             |
| `StandardSchemaV1` · `StandardJSONSchemaV1` · `StandardTypedV1`                                         | Standard 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:

| Deprecated                      | Modern replacement                                        |
| ------------------------------- | --------------------------------------------------------- |
| `session`                       | stateless requests; explicit handles in tool arguments    |
| `onStream`                      | `onListen` ([subscriptions](/guide/modern/subscriptions)) |
| `onSubscribe` / `onUnsubscribe` | `onListen`                                                |
| `onLogLevelSet`                 | `_meta` log level + `mcp.log()`                           |
