@modelcontextprotocol/hono
2.0.2 · 2 Oct 2026Apache-2.067.3k / weekRepositoryHomepagenpmAtom feed
3 stable releases, newest first, by release line. Notes are quoted as the maintainers published them.
2.0.2
2 Oct 2026A
ServerorMcpServernow serves one connection at a time, and a Streamable HTTP server transport without sessions (sessionIdGenerator: undefined) serves one request. An app that uses one server object, or one stateless transport, for every HTTP request fails on the second request after this upgrade. Build the server and the transport per request instead.What keeps working without a change:
What fails now, how it shows, and what to change:
What the caller sees when
connect()orhandleRequest()rejects depends on the host. Express 5, Fastify and Hono answer500. A plainnode:httplistener without its own error handling gets an unhandled rejection, which ends the process.The README examples of
@modelcontextprotocol/express,@modelcontextprotocol/fastify,@modelcontextprotocol/honoand@modelcontextprotocol/node, and the handler examples in the JSDoc ofWebStandardStreamableHTTPServerTransportandNodeStreamableHTTPServerTransport, now build a server and a transport per request.The
licensefield of the package manifests is nowApache-2.0; theLICENSEfile shipped in each package carries the full terms, including the MIT text for earlier contributions. No code change.
Patch Changes
A
ServerorMcpServernow serves one connection at a time, and a Streamable HTTP server transport without sessions (sessionIdGenerator: undefined) serves one request. An app that uses one server object, or one stateless transport, for every HTTP request fails on the second request after this upgrade. Build the server and the transport per request instead.What keeps working without a change:
createMcpHandler(buildServer)andserveStdio(buildServer), wherebuildServerreturns a new server on every call.A handler that builds a new server and a new stateless transport for each request.
One server and one transport per session (a transport with a
sessionIdGenerator).Connecting a server again after
close().Client.
What fails now, how it shows, and what to change:
One server object with a new stateless transport per request (
const server = new McpServer(...)outside the handler,await server.connect(transport)inside it): the second HTTP request the process receives fails, and so does every later one.connect()rejects with anSdkErrorof codeALREADY_CONNECTED. If the handler closes the transport when the response ends, requests that arrive one after the other still work and a request that overlaps another one fails. Change: movenew McpServer(...)and its registrations into the handler.One stateless transport for every request (a transport built once with
sessionIdGenerator: undefined): the second HTTP request fails.WebStandardStreamableHTTPServerTransport.handleRequest()rejects withStateless transport cannot be reused across requests. Create a new transport per request., andNodeStreamableHTTPServerTransport.handleRequest()answers500. Change: build the server and the transport inside the handler and connect them there.createMcpHandler(() => server)with a server built once: a request that arrives after the previous response has been read to its end still works. A request that arrives while another one is being served is answered500with the JSON-RPC error-32603(Internal server error); the reason is reported only through theonerroroption. Change: pass a function that builds the server, as increateMcpHandler(buildServer).One server object for every session: the
initializerequest of the second session fails withALREADY_CONNECTED. Change: build a server per session.
What the caller sees when
connect()orhandleRequest()rejects depends on the host. Express 5, Fastify and Hono answer500. A plainnode:httplistener without its own error handling gets an unhandled rejection, which ends the process.The README examples of
@modelcontextprotocol/express,@modelcontextprotocol/fastify,@modelcontextprotocol/honoand@modelcontextprotocol/node, and the handler examples in the JSDoc ofWebStandardStreamableHTTPServerTransportandNodeStreamableHTTPServerTransport, now build a server and a transport per request.The
licensefield of the package manifests is nowApache-2.0; theLICENSEfile shipped in each package carries the full terms, including the MIT text for earlier contributions. No code change.
2.0.1
23 Sep 2026Read Streamable HTTP request bodies with a size limit. Every SDK-owned body read
WebStandardStreamableHTTPServerTransport(and the Node transport built on it),createMcpHandler,toNodeHandler, andcreateMcpHonoApp's JSON pre-parse — now stops at
4 MiB by default (the limit the legacy SSE transport already uses; the Express adapter and stdio
bound their reads too) and answers413 Payload Too Largebefore anything is parsed.toWebRequest(when it reads the Node stream itself) now rejects once the body exceeds the
limit with an error whosenameis'RequestBodyTooLargeError'andstatusis413, andtoNodeHandleranswers that with413; hand-wired callers oftoWebRequestshould handle the
rejection or pass a pre-parsed body, andisLegacyRequestreports such a request as non-legacy
so the modern handler answers it. JSON-RPC batch arrays are limited to 100 messages; a longer
batch is answered400/-32600and none of it is dispatched.The limit is configurable with a new
maxRequestBodySizeoption (bytes, default
DEFAULT_MAX_REQUEST_BODY_SIZE= 4 MiB, exported from@modelcontextprotocol/server) on
WebStandardStreamableHTTPServerTransportOptions,CreateMcpHandlerOptions(forwarded to its
stateless legacy leg;isLegacyRequestandlegacyStatelessFallbacktake the same option),
CreateMcpHonoAppOptions, andToNodeHandlerOptions/ToWebRequestOptions(the adapter's
bound applies before the handler's, so raise both). The bounded reader is exported as
readRequestBodyfor adapter authors. Hosts that pre-parse the body and pass it as
parsedBodyskip the SDK's read and its size limit entirely; the batch bound applies either way.createMcpHonoAppandcreateMcpExpressAppnow run their Host/Origin validation before the
JSON body parser, so a request from a disallowed Host or Origin with an invalid JSON body is
answered403rather than400, and its body is not read.
Patch Changes
Read Streamable HTTP request bodies with a size limit. Every SDK-owned body read
WebStandardStreamableHTTPServerTransport(and the Node transport built on it),createMcpHandler,toNodeHandler, andcreateMcpHonoApp's JSON pre-parse — now stops at
4 MiB by default (the limit the legacy SSE transport already uses; the Express adapter and stdio
bound their reads too) and answers413 Payload Too Largebefore anything is parsed.toWebRequest(when it reads the Node stream itself) now rejects once the body exceeds the
limit with an error whosenameis'RequestBodyTooLargeError'andstatusis413, andtoNodeHandleranswers that with413; hand-wired callers oftoWebRequestshould handle the
rejection or pass a pre-parsed body, andisLegacyRequestreports such a request as non-legacy
so the modern handler answers it. JSON-RPC batch arrays are limited to 100 messages; a longer
batch is answered400/-32600and none of it is dispatched.The limit is configurable with a new
maxRequestBodySizeoption (bytes, default
DEFAULT_MAX_REQUEST_BODY_SIZE= 4 MiB, exported from@modelcontextprotocol/server) on
WebStandardStreamableHTTPServerTransportOptions,CreateMcpHandlerOptions(forwarded to its
stateless legacy leg;isLegacyRequestandlegacyStatelessFallbacktake the same option),
CreateMcpHonoAppOptions, andToNodeHandlerOptions/ToWebRequestOptions(the adapter's
bound applies before the handler's, so raise both). The bounded reader is exported as
readRequestBodyfor adapter authors. Hosts that pre-parse the body and pass it as
parsedBodyskip the SDK's read and its size limit entirely; the batch bound applies either way.createMcpHonoAppandcreateMcpExpressAppnow run their Host/Origin validation before the
JSON body parser, so a request from a disallowed Host or Origin with an invalid JSON body is
answered403rather than400, and its body is not read.
2.0.0
27 Jul 2026First beta release of SDK v2 with support for the MCP 2026-07-28 specification
revision. See the migration guides for upgrading from v1
(docs/migration/upgrade-to-v2.md) and adopting the 2026-07-28 revision
(docs/migration/support-2026-07-28.md).Ship CommonJS builds alongside ESM. Each package now emits both
.mjs/.d.mts
and.cjs/.d.cts(via tsdownformat: ['esm', 'cjs']), and itsexportsmap
adds arequirecondition sorequire('@modelcontextprotocol/…')works from
CommonJS consumers. Output extensions are normalized across all packages
(@modelcontextprotocol/coremoves from.js/.d.tsto.mjs/.d.mts); the
public import paths are unchanged.POSTs whose
Content-Typemedia type is notapplication/jsonare now
rejected with415 Unsupported Media Type; the header is parsed instead of
substring-matched. Previously any value merely containing the substring
passed the check (for exampletext/plain; a=application/json), case
variants were wrongly rejected, and the 2026-07-28 entry did not inspectContent-Typeat all — requests with a missing or non-JSON header that used
to be served on that path now also answer 415. Values with parameters
(application/json; charset=utf-8, including malformed parameter sections
likeapplication/json;) continue to work. SDK clients always send the
correct header and are unaffected.The new
isJsonContentType(header)helper is exported for transport and
framework-adapter authors — custom entries composing the exported building
blocks (classifyInboundRequest,PerRequestHTTPServerTransport) must apply
it themselves. The hono adapter's JSON body pre-parse and the client's
response dispatch now use the same parsed-media-type comparison.
Patch Changes
First beta release of SDK v2 with support for the MCP 2026-07-28 specification
revision. See the migration guides for upgrading from v1
(docs/migration/upgrade-to-v2.md) and adopting the 2026-07-28 revision
(docs/migration/support-2026-07-28.md).Ship CommonJS builds alongside ESM. Each package now emits both
.mjs/.d.mts
and.cjs/.d.cts(via tsdownformat: ['esm', 'cjs']), and itsexportsmap
adds arequirecondition sorequire('@modelcontextprotocol/…')works from
CommonJS consumers. Output extensions are normalized across all packages
(@modelcontextprotocol/coremoves from.js/.d.tsto.mjs/.d.mts); the
public import paths are unchanged.POSTs whose
Content-Typemedia type is notapplication/jsonare now
rejected with415 Unsupported Media Type; the header is parsed instead of
substring-matched. Previously any value merely containing the substring
passed the check (for exampletext/plain; a=application/json), case
variants were wrongly rejected, and the 2026-07-28 entry did not inspectContent-Typeat all — requests with a missing or non-JSON header that used
to be served on that path now also answer 415. Values with parameters
(application/json; charset=utf-8, including malformed parameter sections
likeapplication/json;) continue to work. SDK clients always send the
correct header and are unaffected.The new
isJsonContentType(header)helper is exported for transport and
framework-adapter authors — custom entries composing the exported building
blocks (classifyInboundRequest,PerRequestHTTPServerTransport) must apply
it themselves. The hono adapter's JSON body pre-parse and the client's
response dispatch now use the same parsed-media-type comparison.