Handler Options
Every field of McpHandlerOptions.
defineMcpHandler takes this object, or a function returning it:
defineMcpHandler(options: McpHandlerOptions | ((event: H3Event) => McpHandlerOptions));#Identity
| Option | Type | Default | Notes |
|---|---|---|---|
name | string | — | Required. Machine name of the server |
version | string | — | Required. Server version |
title | string | — | Human-friendly display name |
description | string | — | Short description |
icons | McpIcon[] | — | { src, mimeType?, sizes?, theme? } |
websiteUrl | string | — | Server homepage |
instructions | string | — | Guidance passed to the model — worth writing well |
#Definitions
| Option | Type | Notes |
|---|---|---|
tools | MaybeLazy<McpToolDefinition>[] | Tools |
resources | MaybeLazy<McpResourceDefinition>[] | Resources |
resourceTemplates | MaybeLazy<McpResourceTemplateDefinition>[] | Templates |
prompts | MaybeLazy<McpPromptDefinition>[] | Prompts |
MaybeLazy<T> is T | (() => T | Promise<T>), so any entry may be a function resolved once on first use.
Read more in Lazy definitions.
#Era
| Option | Type | Default | Notes |
|---|---|---|---|
era | "dual" \| "modern" \| "legacy" | "dual" | Ignored on the h3-mcp/modern and h3-mcp/legacy entrypoints |
Read more in Protocol eras.
#Modern Era
| Option | Type | Default | Notes |
|---|---|---|---|
cache | McpCacheOptions | { ttlMs: 0, cacheScope: "private" } | Per-method keys: discover, tools, prompts, resources, resourceTemplates, resourceRead |
extensions | Record<string, object> | — | Advertised in capabilities.extensions |
logging | boolean | false | Advertise logging on server/discover |
echoServerInfo | boolean | true | Include _meta server info on modern results |
subscriptions | { max?, keepAliveMs? } | { max: 100, keepAliveMs: 15000 } | subscriptions/listen limits |
onListen | (subscription, event) => void | — | Called when a listen stream opens |
Read more in Caching.
#Legacy Era
| Option | Type | Default | Notes |
|---|---|---|---|
session | boolean \| McpSessionOptions | false | { enabled?, generateId?, maxSessions? } |
onStream | (stream, event) => void | — | Enables the GET/SSE stream |
onSubscribe | (uri, event) => void | — | resources/subscribe |
onUnsubscribe | (uri, event) => void | — | resources/unsubscribe |
onLogLevelSet | (level, event) => void | — | logging/setLevel |
onCancelled | (notification, event) => void | — | notifications/cancelled |
onProgress | (notification, event) => void | — | notifications/progress |
All of these are @deprecated in the sense that 2026-07-28 removed the feature — they remain fully functional on the legacy path.
Read more in Legacy era.
#Security
| Option | Type | Default | Notes |
|---|---|---|---|
auth | false \| McpAuthOptions | false (disabled) | { enabled?, schemes?, tokens?, header?, validate? } |
origin | false \| McpOriginOptions | enabled: { allow: [], allowMissing: true } | { allow?, allowMissing?, validate? } |
limits | false \| McpLimitsOptions | { maxBodySize: 4 MiB, contentType: ["application/json"] } | Applied to POST before parsing |
Auth defaults, once enabled: schemes: ["bearer", "api-key"], header: "x-api-key". Enabling auth requires at least one of tokens or validate.
Read more in Security.
#Dynamic Resolution
Every option above can be computed per request:
defineMcpHandler((event) => ({
name: "my-server",
version: "1.0.0",
tools: getToolsForUser(event),
auth: { tokens: tokensForTenant(event) },
}));The function runs at most once per event and the result is cached in a WeakMap.
Read more in Dynamic options.