Split protocol types into a standalone mcp-types package (#2973)

This commit is contained in:
Marcelo Trylesinski 2026-06-25 19:18:38 +02:00 • committed by GitHub
commit 0ee7f1b293
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
47 changed files with 1040 additions and 867 deletions

View file

@ -24,7 +24,7 @@ flows — with a single subprocess test for stdio.
rewrite preserved behaviour; a passing test that pins the wrong output exactly does. Known
divergences are recorded as data on the requirement (see below), not worked around in the test.
- **Spec-mandated assertions, not implementation quirks.** Error *codes* are asserted against
the constants in `mcp.types`; error *message strings* are pinned only where they are the
the constants in `mcp_types`; error *message strings* are pinned only where they are the
SDK's own deliberate output.
- **No sleeps, no real I/O.** Concurrency is coordinated with `anyio.Event`; every wait that
could hang is bounded by `anyio.fail_after(5)`. The HTTP and OAuth tests drive the Starlette
@ -243,7 +243,7 @@ many requirements at once; if the assertions would be separate, write separate t
|---|---|
| the result of a transformation (arguments → output, exception → error result) | `result == snapshot(...)` of the full object, so any field the implementation adds or drops fails the test |
| pass-through of an opaque value (`_meta`, cursors) | identity against the same variable that was sent — a snapshot of a pass-through value only matches the input because a human checked two literals correspond |
| an error | `pytest.raises(MCPError)` and a snapshot of `exc.value.error` when the message is the SDK's own; a plain `==` on `.code` against the `mcp.types` constant when it is not |
| an error | `pytest.raises(MCPError)` and a snapshot of `exc.value.error` when the message is the SDK's own; a plain `==` on `.code` against the `mcp_types` constant when it is not |
| third-party output embedded in a result (validation messages) | the stable prefix only — never pin text that changes with a dependency upgrade |
### Notifications and concurrency

View file

@ -14,6 +14,16 @@ from typing import Any, Protocol
import httpx
from httpx_sse import ServerSentEvent, aconnect_sse
from mcp_types import (
ClientCapabilities,
Implementation,
InitializeRequestParams,
JSONRPCMessage,
JSONRPCRequest,
JSONRPCResponse,
jsonrpc_message_adapter,
)
from mcp_types.version import LATEST_HANDSHAKE_VERSION, MODERN_PROTOCOL_VERSIONS
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import Response
@ -31,16 +41,6 @@ from mcp.server.sse import SseServerTransport
from mcp.server.streamable_http import EventStore
from mcp.server.streamable_http_manager import StreamableHTTPSessionManager
from mcp.server.transport_security import TransportSecuritySettings
from mcp.shared.version import LATEST_HANDSHAKE_VERSION, MODERN_PROTOCOL_VERSIONS
from mcp.types import (
ClientCapabilities,
Implementation,
InitializeRequestParams,
JSONRPCMessage,
JSONRPCRequest,
JSONRPCResponse,
jsonrpc_message_adapter,
)
from tests.interaction.transports._bridge import StreamingASGITransport
# The in-process app is mounted at this origin purely so URLs are well-formed; nothing listens here.

View file

@ -9,12 +9,12 @@ them.
from types import TracebackType
import anyio
from mcp_types import ClientResult, ServerNotification, ServerRequest
from typing_extensions import Self
from mcp.client._transport import ReadStream, Transport, TransportStreams, WriteStream
from mcp.shared.message import SessionMessage
from mcp.shared.session import RequestResponder
from mcp.types import ClientResult, ServerNotification, ServerRequest
# TODO: this union is the parameter type of every client message handler (MessageHandlerFnT),
# but the SDK does not export a name for it -- writing a correctly-typed handler requires

View file

@ -18,8 +18,7 @@ assumptions about which side produced what.
from dataclasses import dataclass
import httpx
from mcp.types import JSONRPCMessage, jsonrpc_message_adapter
from mcp_types import JSONRPCMessage, jsonrpc_message_adapter
#: Substrings that must not appear anywhere in a request body or JSON-RPC frame on a legacy
#: exchange. Matching is by raw substring against the by-alias JSON serialisation, so a leaked

View file

@ -38,8 +38,7 @@ from dataclasses import dataclass
from typing import Any, Literal, TypeVar
import pytest
from mcp.shared.version import KNOWN_PROTOCOL_VERSIONS
from mcp_types.version import KNOWN_PROTOCOL_VERSIONS
SpecVersion = Literal["2025-11-25", "2026-07-28"]
"""A protocol version the suite parametrizes over. Both values are typed even though only one is

View file

@ -20,15 +20,15 @@ from dataclasses import dataclass
from urllib.parse import parse_qsl, quote, urlsplit
import anyio
import mcp_types as types
import pytest
from inline_snapshot import snapshot
from mcp_types import ListToolsResult, Tool
from pydantic import AnyHttpUrl, AnyUrl
from mcp import types
from mcp.client.auth import OAuthFlowError
from mcp.server import Server, ServerRequestContext
from mcp.shared.auth import OAuthClientInformationFull, OAuthMetadata
from mcp.types import ListToolsResult, Tool
from tests.interaction._connect import BASE_URL
from tests.interaction._requirements import requirement
from tests.interaction.auth._harness import (

View file

@ -13,10 +13,10 @@ from collections.abc import AsyncIterator
import httpx
import pytest
from inline_snapshot import snapshot
from mcp_types import JSONRPCResponse
from mcp.server import Server
from mcp.server.auth.provider import AccessToken
from mcp.types import JSONRPCResponse
from tests.interaction._connect import base_headers, initialize_body, mounted_app
from tests.interaction._requirements import requirement
from tests.interaction.auth._harness import StaticTokenVerifier, auth_settings

View file

@ -13,15 +13,15 @@ assertions are the metadata response bodies and headers, which `Client` does not
import json
import anyio
import mcp_types as types
import pytest
from inline_snapshot import snapshot
from mcp_types import ListToolsResult, Tool
from pydantic import AnyHttpUrl
from mcp import types
from mcp.client.auth import OAuthFlowError, OAuthRegistrationError
from mcp.server import Server, ServerRequestContext
from mcp.shared.auth import OAuthMetadata, ProtectedResourceMetadata
from mcp.types import ListToolsResult, Tool
from tests.interaction._connect import BASE_URL, mounted_app
from tests.interaction._requirements import requirement
from tests.interaction.auth._harness import (

View file

@ -14,15 +14,15 @@ from urllib.parse import parse_qs, urlsplit
import anyio
import httpx
import mcp_types as types
import pytest
from inline_snapshot import snapshot
from mcp_types import CallToolResult, ListToolsResult, TextContent, Tool
from pydantic import AnyUrl
from mcp import types
from mcp.server import Server, ServerRequestContext
from mcp.server.auth.middleware.auth_context import get_access_token
from mcp.shared.auth import OAuthClientInformationFull
from mcp.types import CallToolResult, ListToolsResult, TextContent, Tool
from tests.interaction._connect import BASE_URL
from tests.interaction._requirements import requirement
from tests.interaction.auth._harness import (

View file

@ -11,15 +11,16 @@ from collections import Counter
from urllib.parse import parse_qsl, urlsplit
import anyio
import mcp_types as types
import pytest
from inline_snapshot import snapshot
from mcp_types import INTERNAL_ERROR, ListToolsResult, Tool
from pydantic import AnyHttpUrl, AnyUrl
from mcp import MCPError, types
from mcp import MCPError
from mcp.client.auth.extensions.client_credentials import ClientCredentialsOAuthProvider, PrivateKeyJWTOAuthProvider
from mcp.server import Server, ServerRequestContext
from mcp.shared.auth import OAuthClientInformationFull, OAuthMetadata
from mcp.types import INTERNAL_ERROR, ListToolsResult, Tool
from tests.interaction._connect import BASE_URL
from tests.interaction._requirements import requirement
from tests.interaction.auth._harness import (

View file

@ -7,15 +7,10 @@ on an Event rather than a sleep, and every wait is bounded by `anyio.fail_after`
"""
import anyio
import mcp_types as types
import pytest
from inline_snapshot import snapshot
from mcp import MCPError, types
from mcp.client import ClientRequestContext, ClientSession
from mcp.server import Server, ServerRequestContext
from mcp.shared.memory import MessageStream, create_client_server_memory_streams
from mcp.shared.message import SessionMessage
from mcp.types import (
from mcp_types import (
REQUEST_TIMEOUT,
CallToolResult,
EmptyResult,
@ -29,6 +24,12 @@ from mcp.types import (
ServerCapabilities,
TextContent,
)
from mcp import MCPError
from mcp.client import ClientRequestContext, ClientSession
from mcp.server import Server, ServerRequestContext
from mcp.shared.memory import MessageStream, create_client_server_memory_streams
from mcp.shared.message import SessionMessage
from tests.interaction._connect import Connect
from tests.interaction._helpers import IncomingMessage
from tests.interaction._requirements import requirement

View file

@ -17,18 +17,9 @@ from contextlib import asynccontextmanager
import anyio
import httpx
import mcp_types as types
import pytest
from mcp import MCPError, types
from mcp.client._memory import InMemoryTransport
from mcp.client._transport import TransportStreams
from mcp.client.client import Client
from mcp.client.streamable_http import streamable_http_client
from mcp.server import Server, ServerRequestContext
from mcp.shared.memory import MessageStream, create_client_server_memory_streams
from mcp.shared.message import SessionMessage
from mcp.shared.version import LATEST_HANDSHAKE_VERSION, LATEST_MODERN_VERSION, MODERN_PROTOCOL_VERSIONS
from mcp.types import (
from mcp_types import (
CLIENT_CAPABILITIES_META_KEY,
CLIENT_INFO_META_KEY,
INVALID_REQUEST,
@ -45,6 +36,16 @@ from mcp.types import (
ServerCapabilities,
ToolsCapability,
)
from mcp_types.version import LATEST_HANDSHAKE_VERSION, LATEST_MODERN_VERSION, MODERN_PROTOCOL_VERSIONS
from mcp import MCPError
from mcp.client._memory import InMemoryTransport
from mcp.client._transport import TransportStreams
from mcp.client.client import Client
from mcp.client.streamable_http import streamable_http_client
from mcp.server import Server, ServerRequestContext
from mcp.shared.memory import MessageStream, create_client_server_memory_streams
from mcp.shared.message import SessionMessage
from tests.interaction._connect import BASE_URL, Connect, mounted_app
from tests.interaction._helpers import RecordingTransport
from tests.interaction._requirements import requirement

View file

@ -1,11 +1,9 @@
"""Completion interactions against the low-level Server, driven through the public Client API."""
import mcp_types as types
import pytest
from inline_snapshot import snapshot
from mcp import MCPError, types
from mcp.server import Server, ServerRequestContext
from mcp.types import (
from mcp_types import (
INVALID_PARAMS,
METHOD_NOT_FOUND,
CompleteResult,
@ -14,6 +12,9 @@ from mcp.types import (
PromptReference,
ResourceTemplateReference,
)
from mcp import MCPError
from mcp.server import Server, ServerRequestContext
from tests.interaction._connect import Connect
from tests.interaction._requirements import requirement

View file

@ -5,15 +5,10 @@ mode field, because the typed server API (`elicit_form`/`elicit_url`) always ser
"""
import anyio
import mcp_types as types
import pytest
from inline_snapshot import snapshot
from mcp import MCPError, UrlElicitationRequiredError, types
from mcp.client import ClientRequestContext, ClientSession
from mcp.server import Server, ServerRequestContext
from mcp.shared.memory import MessageStream, create_client_server_memory_streams
from mcp.shared.message import SessionMessage
from mcp.types import (
from mcp_types import (
CallToolResult,
ElicitCompleteNotification,
ElicitCompleteNotificationParams,
@ -31,6 +26,12 @@ from mcp.types import (
ServerCapabilities,
TextContent,
)
from mcp import MCPError, UrlElicitationRequiredError
from mcp.client import ClientRequestContext, ClientSession
from mcp.server import Server, ServerRequestContext
from mcp.shared.memory import MessageStream, create_client_server_memory_streams
from mcp.shared.message import SessionMessage
from tests.interaction._connect import Connect
from tests.interaction._helpers import IncomingMessage
from tests.interaction._requirements import requirement

View file

@ -9,14 +9,10 @@ individual features are pinned by their own tests; these prove they compose.
from collections.abc import Awaitable, Callable
import anyio
import mcp_types as types
import pytest
from inline_snapshot import snapshot
from mcp import MCPError, UrlElicitationRequiredError, types
from mcp.client import ClientRequestContext
from mcp.server import Server, ServerRequestContext
from mcp.server.session import ServerSession
from mcp.types import (
from mcp_types import (
URL_ELICITATION_REQUIRED,
CallToolResult,
ElicitCompleteNotification,
@ -31,6 +27,11 @@ from mcp.types import (
TextResourceContents,
Tool,
)
from mcp import MCPError, UrlElicitationRequiredError
from mcp.client import ClientRequestContext
from mcp.server import Server, ServerRequestContext
from mcp.server.session import ServerSession
from tests.interaction._connect import Connect
from tests.interaction._helpers import IncomingMessage
from tests.interaction._requirements import requirement

View file

@ -8,16 +8,10 @@ answer initialize with an unsupported protocol version.
"""
import anyio
import mcp_types as types
import pytest
from inline_snapshot import snapshot
from mcp import MCPError, types
from mcp.client import ClientRequestContext, ClientSession
from mcp.client._memory import InMemoryTransport
from mcp.server import Server, ServerRequestContext
from mcp.shared.memory import MessageStream, create_client_server_memory_streams
from mcp.shared.message import SessionMessage
from mcp.types import (
from mcp_types import (
INVALID_PARAMS,
CallToolResult,
ClientCapabilities,
@ -40,6 +34,13 @@ from mcp.types import (
TextContent,
ToolsCapability,
)
from mcp import MCPError
from mcp.client import ClientRequestContext, ClientSession
from mcp.client._memory import InMemoryTransport
from mcp.server import Server, ServerRequestContext
from mcp.shared.memory import MessageStream, create_client_server_memory_streams
from mcp.shared.message import SessionMessage
from tests.interaction._connect import Connect
from tests.interaction._requirements import requirement

View file

@ -15,18 +15,18 @@ alongside the fix that introduces capability gating.
"""
import anyio
import mcp_types as types
import pytest
from inline_snapshot import snapshot
from mcp import types
from mcp.server import Server, ServerRequestContext
from mcp.types import (
from mcp_types import (
CallToolResult,
PromptListChangedNotification,
ResourceListChangedNotification,
TextContent,
ToolListChangedNotification,
)
from mcp.server import Server, ServerRequestContext
from tests.interaction._connect import Connect
from tests.interaction._helpers import IncomingMessage
from tests.interaction._requirements import requirement

View file

@ -5,12 +5,12 @@ Notification ordering: await-free callbacks finish in arrival order, and passing
streamable HTTP, so plain-list collection is deterministic on every transport leg.
"""
import mcp_types as types
import pytest
from inline_snapshot import snapshot
from mcp_types import CallToolResult, EmptyResult, LoggingMessageNotificationParams, TextContent
from mcp import types
from mcp.server import Server, ServerRequestContext
from mcp.types import CallToolResult, EmptyResult, LoggingMessageNotificationParams, TextContent
from tests.interaction._connect import Connect
from tests.interaction._requirements import requirement

View file

@ -5,11 +5,11 @@ rather than snapshotting a literal: the expected value and the sent value are th
which also proves the SDK injected nothing alongside it.
"""
import mcp_types as types
import pytest
from mcp_types import CallToolResult, RequestParamsMeta, TextContent
from mcp import types
from mcp.server import Server, ServerRequestContext
from mcp.types import CallToolResult, RequestParamsMeta, TextContent
from tests.interaction._connect import Connect
from tests.interaction._requirements import requirement

View file

@ -5,12 +5,10 @@ handler returns as next_cursor comes back verbatim on the client's next call, no
pagination scheme.
"""
import mcp_types as types
import pytest
from inline_snapshot import snapshot
from mcp import MCPError, types
from mcp.server import Server, ServerRequestContext
from mcp.types import (
from mcp_types import (
INVALID_PARAMS,
ListPromptsResult,
ListResourcesResult,
@ -21,6 +19,9 @@ from mcp.types import (
ResourceTemplate,
Tool,
)
from mcp import MCPError
from mcp.server import Server, ServerRequestContext
from tests.interaction._connect import Connect
from tests.interaction._requirements import requirement

Some files were not shown because too many files have changed in this diff Show more