Skip to content

Conversation

@felixweinberger
Copy link
Contributor

@felixweinberger felixweinberger commented Feb 2, 2026

Replace blanket export * barrel files in client and server packages with explicit named exports, removing 59 internal/deprecated symbols from the public API.

Motivation and Context

The SDK currently uses export * barrel files that re-export everything from every module, resulting in 400+ symbols visible to users. Many of these are internal implementation details (OAuth sub-steps, Zod v3/v4 compatibility layer, stdio parsing, completable internals) that users should never import directly. Every leaked internal symbol becomes an implicit API contract that blocks refactoring.

v2 is the right time to fix this since we have a breaking change window.

Approach

  • Replace export * in packages/client/src/index.ts and packages/server/src/index.ts with explicit named exports
  • Keep @modelcontextprotocol/core as export * since it is "private": true and only consumed within the monorepo
  • Delete 5 deprecated symbols entirely: discoverOAuthMetadata, extractResourceMetadataUrl, unwrapCompletable, McpZodTypeKind, CompletableDef

What was removed (59 symbols)

Core internals (34): Zod compat layer (AnySchema, safeParse, SchemaOutput, etc.), stdio parsing (ReadBuffer, deserializeMessage, serializeMessage), Protocol base class, mergeCapabilities, normalizeHeaders, validateToolName, toJsonSchemaCompat, and other internal plumbing

Client internals (16): 13 OAuth sub-step functions (startAuthorization, exchangeAuthorization, refreshAuthorization, fetchToken, registerClient, etc.), 2 deprecated functions, getSupportedElicitationModes

Server internals (10): Completable internals (COMPLETABLE_SYMBOL, getCompleter, etc.), deprecated symbols, BaseToolCallback, AnyToolHandler, StreamId, EventId

What stays public

All protocol types/schemas (~327 from types.ts), all OAuth error classes, all transports, Client, McpServer, Server, middleware, auth providers, and all user-facing utilities confirmed by example usage.

How Has This Been Tested

  • pnpm typecheck:all — all packages pass (core, client, server, express, hono, node, examples)
  • pnpm test:all — all tests pass (one pre-existing flake in authExtensions unrelated to this change)
  • pnpm lint:all — clean
  • All 487 integration tests pass

Breaking Changes

Users who import any of the 59 removed symbols from @modelcontextprotocol/client or @modelcontextprotocol/server will get import errors. These symbols were internal implementation details not intended for external use.

Types of changes

  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

@changeset-bot
Copy link

changeset-bot bot commented Feb 2, 2026

⚠️ No Changeset found

Latest commit: d4dfef4

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 2, 2026

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/client@1447

@modelcontextprotocol/server

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/server@1447

@modelcontextprotocol/express

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/express@1447

@modelcontextprotocol/hono

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/hono@1447

@modelcontextprotocol/node

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/node@1447

commit: d4dfef4

@felixweinberger felixweinberger requested review from a team and removed request for a team February 2, 2026 17:32
@felixweinberger
Copy link
Contributor Author

Problem: We currently use export * barrel files, which means ~460 symbols are importable by users. Many are internal (OAuth sub-steps, Zod compat layer, stdio parsing, completable internals). Every leaked internal is an
implicit API contract.

Approach: Replace export * in client/server index.ts with explicit named exports. Core stays export * since it's "private": true. No code is deleted — deprecated functions remain in source, they're just not re-exported.

What's removed from the public API (59 symbols):

  • Zod v3/v4 compat layer (13 symbols) — AnySchema, safeParse, SchemaOutput, etc.
  • OAuth internal sub-steps (13 functions) — startAuthorization, exchangeAuthorization, etc. (auth() orchestrates all of these)
  • Stdio internals (3) — ReadBuffer, deserializeMessage, serializeMessage
  • Protocol base class, mergeCapabilities, validateToolName, toJsonSchemaCompat
  • Server completable internals (6) — COMPLETABLE_SYMBOL, getCompleter, BaseToolCallback, etc.
  • Transport type aliases (StreamId, EventId), misc internal helpers

What stays: All protocol types/schemas (~327), all transports, Client, McpServer, Server, middleware, auth providers, OAuth error classes, InMemoryTransport, getDisplayName, RELATED_TASK_META_KEY, validation providers.

Questions:

  1. Should Protocol be public? (Library authors extending it vs. users only needing Client/Server)
  2. Should the Zod compat utilities be public? (Zero example usage, but advanced users might want them)
  3. Should we go further? (The aggressive case is removing ~120 Zod schemas since users could work with just TypeScript types — but the current client.request(req, Schema) API requires schema imports)

felixweinberger added a commit that referenced this pull request Feb 2, 2026
- Move assertTaskCapability/assertTaskHandlerCapability from mutable
  properties on TaskManager to TaskManagerOptions constructor params,
  eliminating fragile post-construction wiring
- Add _requireHost getter with clear error message instead of _host!
  non-null assertions throughout TaskManager
- Extract duplicated relatedTask metadata injection in Protocol.notification()
  into _buildJsonRpcNotification() helper
- Add @internal JSDoc to TaskManagerHost (will be removed from public
  exports in PR #1447)
- Add changeset for the breaking changes
- Revert unrelated pnpm-workspace.yaml change
…API surface

Replace blanket `export *` barrel files in client and server packages with
explicit named exports, removing 59 internal/deprecated symbols from the
public API. This prevents SDK internals (OAuth sub-steps, Zod compat layer,
stdio parsing, completable internals) from leaking to users while keeping
all protocol types, schemas, and user-facing APIs intact.

Deleted deprecated symbols: discoverOAuthMetadata, extractResourceMetadataUrl,
unwrapCompletable, McpZodTypeKind, CompletableDef.
Keep deprecated functions (discoverOAuthMetadata, extractResourceMetadataUrl,
unwrapCompletable, McpZodTypeKind, CompletableDef) in source files. The API
surface tightening should only control what is re-exported from barrel files,
not delete functionality. Tests that reference internal symbols now import
from source paths instead of the package barrel.
Both client and server barrel files had ~460 identical lines re-exporting
curated symbols from @modelcontextprotocol/core. Extract these into a
single packages/core/src/publicExports.ts file that both barrels
re-export via `export * from '@modelcontextprotocol/core/public'`.

Adding a new public symbol to core now means updating one file instead
of two.
@felixweinberger felixweinberger force-pushed the fweinberger/v2-api-audit branch from b85d9de to 7719034 Compare February 3, 2026 09:48
@@ -0,0 +1,476 @@
/**
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the most interesting file and what we should make sure to get right - i.e. the explicit exports from core that we knowingly make public.

@felixweinberger felixweinberger force-pushed the fweinberger/v2-api-audit branch from 7719034 to d4dfef4 Compare February 3, 2026 09:51
@felixweinberger felixweinberger changed the title v2: tighten public API surface with explicit named exports [RFC]: tighten public API surface with explicit named exports Feb 3, 2026
@felixweinberger felixweinberger marked this pull request as ready for review February 3, 2026 09:53
@felixweinberger felixweinberger requested a review from a team as a code owner February 3, 2026 09:53
export type { AddClientAuthentication, AuthResult, OAuthClientProvider } from './client/auth.js';
export { auth, extractWWWAuthenticateParams, UnauthorizedError } from './client/auth.js';

// client/authExtensions.ts
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explicit exports from client

export * from './server/server.js';
export * from './server/stdio.js';
export * from './server/streamableHttp.js';
// server/completable.ts — public completion API (internals are not re-exported)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explicit server exports

CompleteRequestResourceTemplate,
CompleteResult,
ContentBlock,
CreateMessageRequest,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validate that we can potentially delete all of these schemas after #1446

felixweinberger added a commit that referenced this pull request Feb 3, 2026
- Move assertTaskCapability/assertTaskHandlerCapability from mutable
  properties on TaskManager to TaskManagerOptions constructor params,
  eliminating fragile post-construction wiring
- Add _requireHost getter with clear error message instead of _host!
  non-null assertions throughout TaskManager
- Extract duplicated relatedTask metadata injection in Protocol.notification()
  into _buildJsonRpcNotification() helper
- Add @internal JSDoc to TaskManagerHost (will be removed from public
  exports in PR #1447)
- Add changeset for the breaking changes
- Revert unrelated pnpm-workspace.yaml change
@felixweinberger felixweinberger marked this pull request as draft February 3, 2026 10:08
export { UriTemplate } from './shared/uriTemplate.js';

// --- types/types.ts ---
export type {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving a note on our discussion - we could use this as a starting point; as opposed to enumerating all the export one by one and having to remember to add an export here, we could take an approach where we split large .ts files into two categories - publicly exportable, and private ones - we could then do export * from the ones we've chosen to be public. We could also feed that to CLAUDE.md and contributor guidelines

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants