|
6 | 6 | import inspect |
7 | 7 | from collections.abc import AsyncIterator, Awaitable, Callable, Iterable, Mapping, Sequence |
8 | 8 | from contextlib import AbstractAsyncContextManager, asynccontextmanager |
9 | | -from typing import Any, Generic, Literal, TypeVar, overload |
| 9 | +from typing import TYPE_CHECKING, Any, Generic, Literal, TypeVar, overload |
10 | 10 |
|
11 | 11 | import anyio |
12 | 12 | import pydantic_core |
|
46 | 46 | from mcp_types import Tool as MCPTool |
47 | 47 | from pydantic import BaseModel |
48 | 48 | from pydantic.networks import AnyUrl |
49 | | -from starlette.applications import Starlette |
50 | | -from starlette.middleware import Middleware |
51 | | -from starlette.middleware.authentication import AuthenticationMiddleware |
52 | | -from starlette.requests import Request |
53 | | -from starlette.responses import Response |
54 | | -from starlette.routing import Mount, Route |
55 | | -from starlette.types import Receive, Scope, Send |
56 | | - |
57 | | -from mcp.server.auth.middleware.auth_context import AuthContextMiddleware |
58 | | -from mcp.server.auth.middleware.bearer_auth import BearerAuthBackend, RequireAuthMiddleware |
| 49 | + |
| 50 | +from mcp.server._http_defaults import DEFAULT_MAX_REQUEST_BODY_SIZE |
59 | 51 | from mcp.server.auth.provider import OAuthAuthorizationServerProvider, ProviderTokenVerifier, TokenVerifier |
60 | 52 | from mcp.server.auth.settings import AuthSettings |
61 | 53 | from mcp.server.caching import CacheableMethod, CacheHint |
|
84 | 76 | from mcp.server.mcpserver.utilities.context_injection import find_context_parameter |
85 | 77 | from mcp.server.mcpserver.utilities.logging import configure_logging, get_logger |
86 | 78 | from mcp.server.request_state import RequestStateBoundary, RequestStateSecurity |
87 | | -from mcp.server.sse import SseServerTransport |
88 | 79 | from mcp.server.stdio import stdio_server |
89 | | -from mcp.server.streamable_http import EventStore |
90 | | -from mcp.server.streamable_http_manager import DEFAULT_MAX_REQUEST_BODY_SIZE, StreamableHTTPSessionManager |
91 | 80 | from mcp.server.subscriptions import InMemorySubscriptionBus, ListenHandler, SubscriptionBus |
92 | | -from mcp.server.transport_security import TransportSecuritySettings |
93 | 81 | from mcp.shared.exceptions import MCPError |
94 | 82 | from mcp.shared.uri_template import UriTemplate |
95 | 83 |
|
| 84 | +if TYPE_CHECKING: |
| 85 | + # HTTP transport types appear only in the SSE / streamable-HTTP methods' |
| 86 | + # signatures and in narrowed attributes. Their runtime imports live inside |
| 87 | + # those methods (and `custom_route`), so `import mcp.server.mcpserver` |
| 88 | + # (and every stdio server) never loads starlette, sse_starlette or |
| 89 | + # uvicorn - only building an HTTP app pays for the web stack, once. |
| 90 | + from starlette.applications import Starlette |
| 91 | + from starlette.requests import Request |
| 92 | + from starlette.responses import Response |
| 93 | + from starlette.routing import Route |
| 94 | + from starlette.types import Receive, Scope, Send |
| 95 | + |
| 96 | + from mcp.server.streamable_http import EventStore |
| 97 | + from mcp.server.streamable_http_manager import StreamableHTTPSessionManager |
| 98 | + from mcp.server.transport_security import TransportSecuritySettings |
| 99 | + |
96 | 100 | logger = get_logger(__name__) |
97 | 101 |
|
98 | 102 | _CallableT = TypeVar("_CallableT", bound=Callable[..., Any]) |
@@ -1005,6 +1009,10 @@ async def health_check(request: Request) -> Response: |
1005 | 1009 | ``` |
1006 | 1010 | """ |
1007 | 1011 |
|
| 1012 | + # A custom route is an HTTP feature: starlette is imported here rather |
| 1013 | + # than at module top so stdio servers never load the HTTP stack. |
| 1014 | + from starlette.routing import Route |
| 1015 | + |
1008 | 1016 | def decorator( |
1009 | 1017 | func: Callable[[Request], Awaitable[Response]], |
1010 | 1018 | ) -> Callable[[Request], Awaitable[Response]]: |
@@ -1097,6 +1105,21 @@ def sse_app( |
1097 | 1105 | host: str = "127.0.0.1", |
1098 | 1106 | ) -> Starlette: |
1099 | 1107 | """Return an instance of the SSE server app.""" |
| 1108 | + # The SSE transport stack (starlette, sse_starlette, plus this SDK's SSE |
| 1109 | + # transport and auth ASGI modules) is imported here rather than at module |
| 1110 | + # top so that stdio servers never load it: only building an SSE app |
| 1111 | + # pays for it, once. |
| 1112 | + from starlette.applications import Starlette |
| 1113 | + from starlette.middleware import Middleware |
| 1114 | + from starlette.middleware.authentication import AuthenticationMiddleware |
| 1115 | + from starlette.responses import Response |
| 1116 | + from starlette.routing import Mount, Route |
| 1117 | + |
| 1118 | + from mcp.server.auth.middleware.auth_context import AuthContextMiddleware |
| 1119 | + from mcp.server.auth.middleware.bearer_auth import BearerAuthBackend, RequireAuthMiddleware |
| 1120 | + from mcp.server.sse import SseServerTransport |
| 1121 | + from mcp.server.transport_security import TransportSecuritySettings |
| 1122 | + |
1100 | 1123 | # Auto-enable DNS rebinding protection for localhost (IPv4 and IPv6) |
1101 | 1124 | if transport_security is None and host in ("127.0.0.1", "localhost", "::1"): |
1102 | 1125 | transport_security = TransportSecuritySettings( |
|
0 commit comments