Skip to content

Commit a13de1a

Browse files
committed
Switch to immutable types and add typing.Final for constants per PEP 591
1 parent c47c767 commit a13de1a

File tree

7 files changed

+48
-38
lines changed

7 files changed

+48
-38
lines changed

src/mcp/cli/claude.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
import shutil
66
import sys
77
from pathlib import Path
8-
from typing import Any
8+
from typing import Any, Final
99

1010
from mcp.server.fastmcp.utilities.logging import get_logger
1111

1212
logger = get_logger(__name__)
1313

14-
MCP_PACKAGE = "mcp[cli]"
14+
MCP_PACKAGE: Final = "mcp[cli]"
1515

1616

1717
def get_claude_config_path() -> Path | None:

src/mcp/client/stdio/__init__.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import sys
44
from contextlib import asynccontextmanager
55
from pathlib import Path
6-
from typing import Literal, TextIO
6+
from typing import Final, Literal, TextIO
77

88
import anyio
99
import anyio.lowlevel
@@ -25,8 +25,8 @@
2525
logger = logging.getLogger(__name__)
2626

2727
# Environment variables to inherit by default
28-
DEFAULT_INHERITED_ENV_VARS = (
29-
[
28+
DEFAULT_INHERITED_ENV_VARS: Final = (
29+
(
3030
"APPDATA",
3131
"HOMEDRIVE",
3232
"HOMEPATH",
@@ -39,13 +39,20 @@
3939
"TEMP",
4040
"USERNAME",
4141
"USERPROFILE",
42-
]
42+
)
4343
if sys.platform == "win32"
44-
else ["HOME", "LOGNAME", "PATH", "SHELL", "TERM", "USER"]
44+
else (
45+
"HOME",
46+
"LOGNAME",
47+
"PATH",
48+
"SHELL",
49+
"TERM",
50+
"USER",
51+
)
4552
)
4653

4754
# Timeout for process termination before falling back to force kill
48-
PROCESS_TERMINATION_TIMEOUT = 2.0
55+
PROCESS_TERMINATION_TIMEOUT: Final = 2.0
4956

5057

5158
def get_default_environment() -> dict[str, str]:

src/mcp/client/streamable_http.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from contextlib import asynccontextmanager
1212
from dataclasses import dataclass
1313
from datetime import timedelta
14+
from typing import Final
1415

1516
import anyio
1617
import httpx
@@ -39,15 +40,15 @@
3940
StreamReader = MemoryObjectReceiveStream[SessionMessage]
4041
GetSessionIdCallback = Callable[[], str | None]
4142

42-
MCP_SESSION_ID = "mcp-session-id"
43-
MCP_PROTOCOL_VERSION = "mcp-protocol-version"
44-
LAST_EVENT_ID = "last-event-id"
45-
CONTENT_TYPE = "content-type"
46-
ACCEPT = "accept"
43+
MCP_SESSION_ID: Final = "mcp-session-id"
44+
MCP_PROTOCOL_VERSION: Final = "mcp-protocol-version"
45+
LAST_EVENT_ID: Final = "last-event-id"
46+
CONTENT_TYPE: Final = "content-type"
47+
ACCEPT: Final = "accept"
4748

4849

49-
JSON = "application/json"
50-
SSE = "text/event-stream"
50+
JSON: Final = "application/json"
51+
SSE: Final = "text/event-stream"
5152

5253

5354
class StreamableHTTPError(Exception):

src/mcp/server/auth/routes.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from collections.abc import Awaitable, Callable
2-
from typing import Any
2+
from typing import Any, Final
33

44
from pydantic import AnyHttpUrl
55
from starlette.middleware.cors import CORSMiddleware
@@ -46,10 +46,10 @@ def validate_issuer_url(url: AnyHttpUrl):
4646
raise ValueError("Issuer URL must not have a query string")
4747

4848

49-
AUTHORIZATION_PATH = "/authorize"
50-
TOKEN_PATH = "/token"
51-
REGISTRATION_PATH = "/register"
52-
REVOCATION_PATH = "/revoke"
49+
AUTHORIZATION_PATH: Final = "/authorize"
50+
TOKEN_PATH: Final = "/token"
51+
REGISTRATION_PATH: Final = "/register"
52+
REVOCATION_PATH: Final = "/revoke"
5353

5454

5555
def cors_middleware(

src/mcp/server/streamable_http.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from contextlib import asynccontextmanager
1616
from dataclasses import dataclass
1717
from http import HTTPStatus
18+
from typing import Final
1819

1920
import anyio
2021
from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
@@ -48,20 +49,20 @@
4849

4950

5051
# Header names
51-
MCP_SESSION_ID_HEADER = "mcp-session-id"
52-
MCP_PROTOCOL_VERSION_HEADER = "mcp-protocol-version"
53-
LAST_EVENT_ID_HEADER = "last-event-id"
52+
MCP_SESSION_ID_HEADER: Final = "mcp-session-id"
53+
MCP_PROTOCOL_VERSION_HEADER: Final = "mcp-protocol-version"
54+
LAST_EVENT_ID_HEADER: Final = "last-event-id"
5455

5556
# Content types
56-
CONTENT_TYPE_JSON = "application/json"
57-
CONTENT_TYPE_SSE = "text/event-stream"
57+
CONTENT_TYPE_JSON: Final = "application/json"
58+
CONTENT_TYPE_SSE: Final = "text/event-stream"
5859

5960
# Special key for the standalone GET stream
60-
GET_STREAM_KEY = "_GET_stream"
61+
GET_STREAM_KEY: Final = "_GET_stream"
6162

6263
# Session ID validation pattern (visible ASCII characters ranging from 0x21 to 0x7E)
6364
# Pattern ensures entire string contains only valid characters by using ^ and $ anchors
64-
SESSION_ID_PATTERN = re.compile(r"^[\x21-\x7E]+$")
65+
SESSION_ID_PATTERN: Final = re.compile(r"^[\x21-\x7E]+$")
6566

6667
# Type aliases
6768
StreamId = str

src/mcp/shared/version.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import Final
2+
13
from mcp.types import LATEST_PROTOCOL_VERSION
24

3-
SUPPORTED_PROTOCOL_VERSIONS: list[str] = ["2024-11-05", "2025-03-26", LATEST_PROTOCOL_VERSION]
5+
SUPPORTED_PROTOCOL_VERSIONS: Final = ("2024-11-05", "2025-03-26", LATEST_PROTOCOL_VERSION)

src/mcp/types.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from collections.abc import Callable
2-
from typing import Annotated, Any, Generic, Literal, TypeAlias, TypeVar
2+
from typing import Annotated, Any, Final, Generic, Literal, TypeAlias, TypeVar
33

44
from pydantic import BaseModel, ConfigDict, Field, FileUrl, RootModel
55
from pydantic.networks import AnyUrl, UrlConstraints
@@ -23,15 +23,15 @@
2323
not separate types in the schema.
2424
"""
2525

26-
LATEST_PROTOCOL_VERSION = "2025-06-18"
26+
LATEST_PROTOCOL_VERSION: Final = "2025-06-18"
2727

2828
"""
2929
The default negotiated version of the Model Context Protocol when no version is specified.
3030
We need this to satisfy the MCP specification, which requires the server to assume a
3131
specific version if none is provided by the client. See section "Protocol Version Header" at
3232
https://modelcontextprotocol.io/specification
3333
"""
34-
DEFAULT_NEGOTIATED_VERSION = "2025-03-26"
34+
DEFAULT_NEGOTIATED_VERSION: Final = "2025-03-26"
3535

3636
ProgressToken = str | int
3737
Cursor = str
@@ -147,15 +147,14 @@ class JSONRPCResponse(BaseModel):
147147

148148

149149
# SDK error codes
150-
CONNECTION_CLOSED = -32000
150+
CONNECTION_CLOSED: Final = -32000
151151
# REQUEST_TIMEOUT = -32001 # the typescript sdk uses this
152-
153152
# Standard JSON-RPC error codes
154-
PARSE_ERROR = -32700
155-
INVALID_REQUEST = -32600
156-
METHOD_NOT_FOUND = -32601
157-
INVALID_PARAMS = -32602
158-
INTERNAL_ERROR = -32603
153+
PARSE_ERROR: Final = -32700
154+
INVALID_REQUEST: Final = -32600
155+
METHOD_NOT_FOUND: Final = -32601
156+
INVALID_PARAMS: Final = -32602
157+
INTERNAL_ERROR: Final = -32603
159158

160159

161160
class ErrorData(BaseModel):

0 commit comments

Comments
 (0)