Packages

@modelcontextprotocol/server

2.3.1 · 5 Oct 2026Apache-2.08.2M / weekRepositoryHomepagenpmAtom feed

5 stable releases, newest first, by release line. Notes are quoted as the maintainers published them.

  1. 2.3.1

    5 Oct 2026
  2. 2.3.0

    2 Oct 2026
    • One server per request. Server.connect() now rejects while the instance is already connected, and a stateless Streamable HTTP transport handles one request. Create the McpServer and the transport inside the request handler (or in the createMcpHandler factory) instead of sharing one instance across requests. Creating a server is cheap since #2889.

    • Redirects stay on the same origin. The HTTP client transports now follow a redirect only when it stays on the same origin (same scheme, host and port; http to https on the same host is allowed). A deployment whose endpoint redirects to another host or port either configures the final URL or sets redirectPolicy: 'follow' on the transport. In browsers, a redirected request fails unless that option is set.

    • New options, both off unless you set them. maxToolInputElements on McpServer limits the number of array elements and object members in a tool call's arguments. expectedResource on requireBearerAuth / verifyBearerToken accepts only tokens issued for this server (the token's audience); with Express, upgrade @modelcontextprotocol/express together with @modelcontextprotocol/server. (#2926, #2929)

  3. 2.2.0

    28 Sep 2026
    • deprecated

      Pass expectedIssuer to the machine-to-machine OAuth providers. Constructing ClientCredentialsProvider, PrivateKeyJwtProvider, StaticPrivateKeyJwtProvider or CrossAppAccessProvider without it is deprecated and logs a warning. Set it to the issuer of the authorization server the credentials were registered with.

    • fetchToken() checks which authorization server the client information belongs to. It throws AuthorizationServerMismatchError before sending anything when the provider's client information is bound to a different authorization server.

    • List calls return the whole list. listTools(), listPrompts(), listResources() and listResourceTemplates() called without a cursor now follow nextCursor until the server stops sending one. listMaxPages still caps the walk.

  4. 2.1.0

    23 Sep 2026
    • deprecated

      SdkError and SdkHttpError accept standard ErrorOptions as an optional fourth constructor argument and forward it to Error, so a wrapped error is reachable through the standard Error.cause chain. Version-negotiation probe failures (SdkErrorCode.EraNegotiationFailed) now use it: the underlying TypeError: fetch failed and the DNS or socket error beneath it surface via error.cause, so pino, Sentry, and util.inspect render ENOTFOUND / ECONNREFUSED / ETIMEDOUT instead of stopping at the SdkError (#2657). The previous error.data.cause slot is still populated for compatibility but is deprecated and slated for removal; read error.cause instead.

    • Add request-time OAuth scope challenges for tools, resources, resource templates,
      and prompts. Each primitive's scopeChallenge callback receives the parsed
      request and verified authentication info, then either continues or returns the
      exact scope set for an insufficient_scope response. requireScopes provides a
      small helper for static all-of checks.

      createMcpHandler and Streamable HTTP transports return HTTP 403 with an
      insufficient_scope challenge before handler execution or SSE setup. The
      preflight is active whenever a registered primitive carries a scopeChallenge
      callback — there is no handler- or transport-level configuration. The
      challenge's WWW-Authenticate header is built by the same formatter as the
      bearer-auth 401/403 answers, and its resource_metadata parameter is derived
      from the verified AuthInfo: requireBearerAuth / verifyBearerToken now
      stamp their configured resourceMetadataUrl onto the AuthInfo they return
      (new optional AuthInfo.resourceMetadataUrl field), with a fallback to the
      well-known location for an HTTP(S) RFC 8707 resource identifier; the
      parameter is omitted when neither is available.

    • Treat request id 0 as a real id. Two guards tested a RequestId for truthiness, so the legal JSON-RPC ids 0 and '' were read as absent. Id 0 is not a corner case: the outbound request counter is zero-based, so it is the first id every peer assigns, which on the server→client leg is the first sampling/createMessage, elicitation/create, or roots/list a server sends.

      Absent is now the only value that means "no id".

  5. 2.0.0

    27 Jul 2026
    • Export the Protocol base class and mergeCapabilities from the @modelcontextprotocol/client and @modelcontextprotocol/server package roots, restoring the v1 import for consumers that subclass Protocol (e.g. the MCP Apps SDK). The client and server packages each bundle their own compiled copy of the class, so import it from one package consistently within a process.

      The codemod now rewrites Protocol and mergeCapabilities imports from shared/protocol.js to the client or server package root, like the module's other symbols, instead of dropping them with an action-required marker.

    • Move the schema source modules (spec schemas, OAuth schemas, protocol constants) into @modelcontextprotocol/core and resolve them from there as a regular runtime dependency instead of bundling a private copy into each package. An application importing more than one of the packages now evaluates a single shared schema graph with shared object identity. @modelcontextprotocol/core gains a ./internal subpath (SDK-internal contract; may change in any release) and the four packages now version together.

    • Align the 2026-07-28 wire with the final revision (spec PR #3002): serverInfo moves from the DiscoverResult body to the result _meta, and the per-request envelope's clientInfo demotes from required to SHOULD.

      Before this change the SDK shipped the pre-#3002 shape in both directions: the client hard-rejected a conforming server's DiscoverResult (missing body serverInfo failed parse, so the probe misclassified the server as legacy and attempted an initialize handshake against it — a hard connect failure against a modern-only server such as go-sdk v1.7.0-pre.3), and the server rejected conforming clients that omit clientInfo.

      Now: