Patch Changes
-
#2929
40f8f4eThanks @claude! -requireBearerAuthandverifyBearerTokentake a new optionalexpectedResource, which makes them accept only tokens issued for this resource (the token's audience). Set it to the value your authorization server puts into tokens meant for this server, usually the server's URL. When it is set, a token is accepted only if the verifier reports that value inAuthInfo.resource; the two are compared as strings, ignoring a fragment and one trailing slash. A token reported for another value, or for none, is answered401 invalid_tokenwith the usualWWW-Authenticatechallenge. When it is not set, nothing changes. To use it, passexpectedResourceand haveverifyAccessTokenfillAuthInfo.resource, for example from theaudclaim. The option is declared on a new exported type,VerifyBearerTokenOptions, which extendsBearerAuthOptions;BearerAuthOptionsitself is unchanged. The ExpressrequireBearerAuthpasses the option through. With Express,@modelcontextprotocol/expresshas to be upgraded to this release as well: 2.0.1 does not pass the option on, so nothing is compared. Its options type does not have the option, so TypeScript reports anexpectedResourcewritten in a call to the 2.0.1requireBearerAuthas an error. -
#2918
84804c2Thanks @claude! - AServerorMcpServernow 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. -
#2908
633dd3eThanks @claude! - Thelicensefield 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. -
Updated dependencies [
40f8f4e,6d8dbc6,5238fba,2fc49ea,4d94e7b,84804c2,e55f9ac,633dd3e,2237555]:- @modelcontextprotocol/server@2.3.0