docs: fix docstrings across public API surface (#2095)

This commit is contained in:
Jonathan Hefner 2026-02-18 23:45:59 -06:00 • committed by GitHub
commit c0328540c9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 177 additions and 163 deletions

View file

@ -317,12 +317,12 @@ def run(
) -> None: # pragma: no cover
"""Run an MCP server.
The server can be specified in two ways:\n
1. Module approach: server.py - runs the module directly, expecting a server.run() call.\n
2. Import approach: server.py:app - imports and runs the specified server object.\n\n
The server can be specified in two ways:
1. Module approach: server.py - runs the module directly, expecting a server.run() call.
2. Import approach: server.py:app - imports and runs the specified server object.
Note: This command runs the server directly. You are responsible for ensuring
all dependencies are available.\n
all dependencies are available.
For dependency management, use `mcp install` or `mcp dev` instead.
""" # noqa: E501
file, server_object = _parse_file_path(file_spec)

View file

@ -450,7 +450,7 @@ class RFC7523OAuthClientProvider(OAuthClientProvider):
# When using private_key_jwt, in a client_credentials flow, we use RFC 7523 Section 2.2
token_data["client_assertion"] = assertion
token_data["client_assertion_type"] = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
# We need to set the audience to the resource server, the audience is difference from the one in claims
# We need to set the audience to the resource server, the audience is different from the one in claims
# it represents the resource server that will validate the token
token_data["audience"] = self.context.get_resource_url()

View file

@ -215,6 +215,7 @@ class OAuthContext:
class OAuthClientProvider(httpx.Auth):
"""OAuth2 authentication for httpx.
Handles OAuth flow with automatic client registration and token storage.
"""
@ -241,7 +242,7 @@ class OAuthClientProvider(httpx.Auth):
callback_handler: Handler for authorization callbacks.
timeout: Timeout for the OAuth flow.
client_metadata_url: URL-based client ID. When provided and the server
advertises client_id_metadata_document_supported=true, this URL will be
advertises client_id_metadata_document_supported=True, this URL will be
used as the client_id instead of performing dynamic client registration.
Must be a valid HTTPS URL with a non-root pathname.
validate_resource_url: Optional callback to override resource URL validation.

View file

@ -38,7 +38,7 @@ def extract_field_from_www_auth(response: Response, field_name: str) -> str | No
def extract_scope_from_www_auth(response: Response) -> str | None:
"""Extract scope parameter from WWW-Authenticate header as per RFC6750.
"""Extract scope parameter from WWW-Authenticate header as per RFC 6750.
Returns:
Scope string if found in WWW-Authenticate header, None otherwise
@ -47,7 +47,7 @@ def extract_scope_from_www_auth(response: Response) -> str | None:
def extract_resource_metadata_from_www_auth(response: Response) -> str | None:
"""Extract protected resource metadata URL from WWW-Authenticate header as per RFC9728.
"""Extract protected resource metadata URL from WWW-Authenticate header as per RFC 9728.
Returns:
Resource metadata URL if found in WWW-Authenticate header, None otherwise
@ -67,8 +67,8 @@ def build_protected_resource_metadata_discovery_urls(www_auth_url: str | None, s
3. Fall back to root-based well-known URI: /.well-known/oauth-protected-resource
Args:
www_auth_url: optional resource_metadata url extracted from the WWW-Authenticate header
server_url: server url
www_auth_url: Optional resource_metadata URL extracted from the WWW-Authenticate header
server_url: Server URL
Returns:
Ordered list of URLs to try for discovery
@ -120,10 +120,10 @@ def get_client_metadata_scopes(
def build_oauth_authorization_server_metadata_discovery_urls(auth_server_url: str | None, server_url: str) -> list[str]:
"""Generate ordered list of (url, type) tuples for discovery attempts.
"""Generate an ordered list of URLs for authorization server metadata discovery.
Args:
auth_server_url: URL for the OAuth Authorization Metadata URL if found, otherwise None
auth_server_url: OAuth Authorization Server Metadata URL if found, otherwise None
server_url: URL for the MCP server, used as a fallback if auth_server_url is None
"""
@ -170,7 +170,7 @@ async def handle_protected_resource_response(
Per SEP-985, supports fallback when discovery fails at one URL.
Returns:
True if metadata was successfully discovered, False if we should try next URL
ProtectedResourceMetadata if successfully discovered, None if we should try next URL
"""
if response.status_code == 200:
try:
@ -206,7 +206,7 @@ def create_oauth_metadata_request(url: str) -> Request:
def create_client_registration_request(
auth_server_metadata: OAuthMetadata | None, client_metadata: OAuthClientMetadata, auth_base_url: str
) -> Request:
"""Build registration request or skip if already registered."""
"""Build a client registration request."""
if auth_server_metadata and auth_server_metadata.registration_endpoint:
registration_url = str(auth_server_metadata.registration_endpoint)
@ -261,7 +261,7 @@ def should_use_client_metadata_url(
"""Determine if URL-based client ID (CIMD) should be used instead of DCR.
URL-based client IDs should be used when:
1. The server advertises client_id_metadata_document_supported=true
1. The server advertises client_id_metadata_document_supported=True
2. The client has a valid client_metadata_url configured
Args:
@ -306,7 +306,7 @@ def create_client_info_from_metadata_url(
async def handle_token_response_scopes(
response: Response,
) -> OAuthToken:
"""Parse and validate token response with optional scope validation.
"""Parse and validate a token response.
Parses token response JSON. Callers should check response.status_code before calling.

View file

@ -37,8 +37,8 @@ from mcp.types import (
class Client:
"""A high-level MCP client for connecting to MCP servers.
Currently supports in-memory transport for testing. Pass a Server or
MCPServer instance directly to the constructor.
Supports in-memory transport for testing (pass a Server or MCPServer instance),
Streamable HTTP transport (pass a URL string), or a custom Transport instance.
Example:
```python
@ -205,7 +205,7 @@ class Client:
Args:
uri: The URI of the resource to read.
meta: Additional metadata for the request
meta: Additional metadata for the request.
Returns:
The resource content.
@ -239,7 +239,7 @@ class Client:
meta: Additional metadata for the request
Returns:
The tool result
The tool result.
"""
return await self.session.call_tool(
name=name,

View file

@ -83,7 +83,7 @@ class ExperimentalClientFeatures:
status = await session.experimental.get_task(task_id)
if status.status == "completed":
break
await asyncio.sleep(0.5)
await anyio.sleep(0.5)
# Get result
final = await session.experimental.get_task_result(task_id, CallToolResult)
@ -177,7 +177,7 @@ class ExperimentalClientFeatures:
"""Poll a task until it reaches a terminal status.
Yields GetTaskResult for each poll, allowing the caller to react to
status changes (e.g., handle input_required). Exits when task reaches
status changes (e.g., handle input_required). Exits when the task reaches
a terminal status (completed, failed, cancelled).
Respects the pollInterval hint from the server.

View file

@ -3,7 +3,7 @@
Tools, resources, and prompts are aggregated across servers. Servers may
be connected to or disconnected from at any point after initialization.
This abstractions can handle naming collisions using a custom user-provided hook.
This abstraction can handle naming collisions using a custom user-provided hook.
"""
import contextlib
@ -30,7 +30,7 @@ from mcp.shared.session import ProgressFnT
class SseServerParameters(BaseModel):
"""Parameters for initializing a sse_client."""
"""Parameters for initializing an sse_client."""
# The endpoint URL.
url: str
@ -67,8 +67,8 @@ class StreamableHttpParameters(BaseModel):
ServerParameters: TypeAlias = StdioServerParameters | SseServerParameters | StreamableHttpParameters
# Use dataclass instead of pydantic BaseModel
# because pydantic BaseModel cannot handle Protocol fields.
# Use dataclass instead of Pydantic BaseModel
# because Pydantic BaseModel cannot handle Protocol fields.
@dataclass
class ClientSessionParameters:
"""Parameters for establishing a client session to an MCP server."""
@ -119,7 +119,7 @@ class ClientSessionGroup:
_session_exit_stacks: dict[mcp.ClientSession, contextlib.AsyncExitStack]
# Optional fn consuming (component_name, server_info) for custom names.
# This is provide a means to mitigate naming conflicts across servers.
# This is to provide a means to mitigate naming conflicts across servers.
# Example: (tool_name, server_info) => "{result.server_info.name}.{tool_name}"
_ComponentNameHook: TypeAlias = Callable[[str, types.Implementation], str]
_component_name_hook: _ComponentNameHook | None

View file

@ -47,6 +47,7 @@ async def sse_client(
headers: Optional headers to include in requests.
timeout: HTTP timeout for regular operations (in seconds).
sse_read_timeout: Timeout for SSE read operations (in seconds).
httpx_client_factory: Factory function for creating the HTTPX client.
auth: Optional HTTPX authentication handler.
on_session_created: Optional callback invoked with the session ID when received.
"""

View file

@ -87,9 +87,9 @@ class StdioServerParameters(BaseModel):
encoding: str = "utf-8"
"""
The text encoding used when sending/receiving messages to the server
The text encoding used when sending/receiving messages to the server.
defaults to utf-8
Defaults to utf-8.
"""
encoding_error_handler: Literal["strict", "ignore", "replace"] = "strict"
@ -97,7 +97,7 @@ class StdioServerParameters(BaseModel):
The text encoding error handler.
See https://docs.python.org/3/library/codecs.html#codec-base-classes for
explanations of possible values
explanations of possible values.
"""

View file

@ -358,7 +358,7 @@ class StreamableHTTPTransport:
resumption_callback=(ctx.metadata.on_resumption_token_update if ctx.metadata else None),
is_initialization=is_initialization,
)
# If the SSE event indicates completion, like returning respose/error
# If the SSE event indicates completion, like returning response/error
# break the loop
if is_complete:
await response.aclose()

View file

@ -25,8 +25,8 @@ async def websocket_client(
(read_stream, write_stream)
- read_stream: As you read from this stream, you'll receive either valid
JSONRPCMessage objects or Exception objects (when validation fails).
- write_stream: Write JSONRPCMessage objects to this stream to send them
SessionMessage objects or Exception objects (when validation fails).
- write_stream: Write SessionMessage objects to this stream to send them
over the WebSocket to the server.
"""

View file

@ -138,9 +138,9 @@ async def create_windows_process(
) -> Process | FallbackProcess:
"""Creates a subprocess in a Windows-compatible way with Job Object support.
Attempt to use anyio's open_process for async subprocess creation.
In some cases this will throw NotImplementedError on Windows, e.g.
when using the SelectorEventLoop which does not support async subprocesses.
Attempts to use anyio's open_process for async subprocess creation.
In some cases this will throw NotImplementedError on Windows, e.g.,
when using the SelectorEventLoop, which does not support async subprocesses.
In that case, we fall back to using subprocess.Popen.
The process is automatically added to a Job Object to ensure all child
@ -242,8 +242,9 @@ def _create_job_object() -> int | None:
def _maybe_assign_process_to_job(process: Process | FallbackProcess, job: JobHandle | None) -> None:
"""Try to assign a process to a job object. If assignment fails
for any reason, the job handle is closed.
"""Try to assign a process to a job object.
If assignment fails for any reason, the job handle is closed.
"""
if not job:
return
@ -312,8 +313,8 @@ async def terminate_windows_process(process: Process | FallbackProcess):
Note: On Windows, terminating a process with process.terminate() doesn't
always guarantee immediate process termination.
So we give it 2s to exit, or we call process.kill()
which sends a SIGKILL equivalent signal.
If the process does not exit within 2 seconds, process.kill() is called
to send a SIGKILL-equivalent signal.
Args:
process: The process to terminate

View file

@ -15,7 +15,7 @@ from mcp.server.auth.provider import AccessToken, OAuthAuthorizationServerProvid
class RevocationRequest(BaseModel):
"""# See https://datatracker.ietf.org/doc/html/rfc7009#section-2.1"""
"""See https://datatracker.ietf.org/doc/html/rfc7009#section-2.1"""
token: str
token_type_hint: Literal["access_token", "refresh_token"] | None = None

View file

@ -19,15 +19,17 @@ class AuthenticationError(Exception):
class ClientAuthenticator:
"""ClientAuthenticator is a callable which validates requests from a client
application, used to verify /token calls.
If, during registration, the client requested to be issued a secret, the
authenticator asserts that /token calls must be authenticated with
that same token.
that same secret.
NOTE: clients can opt for no authentication during registration, in which case this
logic is skipped.
"""
def __init__(self, provider: OAuthAuthorizationServerProvider[Any, Any, Any]):
"""Initialize the dependency.
"""Initialize the authenticator.
Args:
provider: Provider to look up client information
@ -83,7 +85,7 @@ class ClientAuthenticator:
elif client.token_endpoint_auth_method == "client_secret_post":
raw_form_data = form_data.get("client_secret")
# form_data.get() can return a UploadFile or None, so we need to check if it's a string
# form_data.get() can return an UploadFile or None, so we need to check if it's a string
if isinstance(raw_form_data, str):
request_client_secret = str(raw_form_data)

View file

@ -131,8 +131,9 @@ class OAuthAuthorizationServerProvider(Protocol, Generic[AuthorizationCodeT, Ref
"""
async def authorize(self, client: OAuthClientInformationFull, params: AuthorizationParams) -> str:
"""Called as part of the /authorize endpoint, and returns a URL that the client
"""Handle the /authorize endpoint and return a URL that the client
will be redirected to.
Many MCP implementations will redirect to a third-party provider to perform
a second OAuth exchange with that provider. In this sort of setup, the client
has an OAuth connection with the MCP server, and the MCP server has an OAuth
@ -151,7 +152,7 @@ class OAuthAuthorizationServerProvider(Protocol, Generic[AuthorizationCodeT, Ref
| |
+------------+
Implementations will need to define another handler on the MCP server return
Implementations will need to define another handler on the MCP server's return
flow to perform the second redirect, and generate and store an authorization
code as part of completing the OAuth authorization step.
@ -182,7 +183,7 @@ class OAuthAuthorizationServerProvider(Protocol, Generic[AuthorizationCodeT, Ref
authorization_code: The authorization code to get the challenge for.
Returns:
The AuthorizationCode, or None if not found
The AuthorizationCode, or None if not found.
"""
...
@ -199,7 +200,7 @@ class OAuthAuthorizationServerProvider(Protocol, Generic[AuthorizationCodeT, Ref
The OAuth token, containing access and refresh tokens.
Raises:
TokenError: If the request is invalid
TokenError: If the request is invalid.
"""
...
@ -234,18 +235,18 @@ class OAuthAuthorizationServerProvider(Protocol, Generic[AuthorizationCodeT, Ref
The OAuth token, containing access and refresh tokens.
Raises:
TokenError: If the request is invalid
TokenError: If the request is invalid.
"""
...
async def load_access_token(self, token: str) -> AccessTokenT | None:
"""Loads an access token by its token.
"""Loads an access token by its token string.
Args:
token: The access token to verify.
Returns:
The AuthInfo, or None if the token is invalid.
The access token, or None if the token is invalid.
"""
async def revoke_token(
@ -261,7 +262,7 @@ class OAuthAuthorizationServerProvider(Protocol, Generic[AuthorizationCodeT, Ref
provided.
Args:
token: the token to revoke
token: The token to revoke.
"""

View file

@ -25,10 +25,10 @@ def validate_issuer_url(url: AnyHttpUrl):
"""Validate that the issuer URL meets OAuth 2.0 requirements.
Args:
url: The issuer URL to validate
url: The issuer URL to validate.
Raises:
ValueError: If the issuer URL is invalid
ValueError: If the issuer URL is invalid.
"""
# RFC 8414 requires HTTPS, but we allow loopback/localhost HTTP for testing
@ -213,6 +213,8 @@ def create_protected_resource_routes(
resource_url: The URL of this resource server
authorization_servers: List of authorization servers that can issue tokens
scopes_supported: Optional list of scopes supported by this resource
resource_name: Optional human-readable name for this resource
resource_documentation: Optional URL to documentation for this resource
Returns:
List of Starlette routes for protected resource metadata

View file

@ -112,8 +112,8 @@ async def elicit_with_validation(
This method can be used to interactively ask for additional information from the
client within a tool's execution. The client might display the message to the
user and collect a response according to the provided schema. Or in case a
client is an agent, it might decide how to handle the elicitation -- either by asking
user and collect a response according to the provided schema. If the client
is an agent, it might decide how to handle the elicitation -- either by asking
the user or automatically generating a response.
For sensitive data like credentials or OAuth flows, use elicit_url() instead.

View file

@ -62,8 +62,8 @@ class Experimental:
"""Validate that the request is compatible with the tool's task execution mode.
Per MCP spec:
- "required": Clients MUST invoke as task. Server returns -32601 if not.
- "forbidden" (or None): Clients MUST NOT invoke as task. Server returns -32601 if they do.
- "required": Clients MUST invoke as a task. Server returns -32601 if not.
- "forbidden" (or None): Clients MUST NOT invoke as a task. Server returns -32601 if they do.
- "optional": Either is acceptable.
Args:
@ -111,7 +111,7 @@ class Experimental:
"""Check if this client can use a tool with the given task mode.
Useful for filtering tool lists or providing warnings.
Returns False if tool requires "required" but client doesn't support tasks.
Returns False if the tool's task mode is "required" but the client doesn't support tasks.
Args:
tool_task_mode: The tool's execution.taskSupport value
@ -164,7 +164,7 @@ class Experimental:
async def work(task: ServerTaskContext) -> CallToolResult:
result = await task.elicit(
message="Are you sure?",
requestedSchema={"type": "object", ...}
requested_schema={"type": "object", ...}
)
confirmed = result.content.get("confirm", False)
return CallToolResult(content=[TextContent(text="Done" if confirmed else "Cancelled")])

View file

@ -88,9 +88,6 @@ class NotificationOptions:
async def lifespan(_: Server[LifespanResultT]) -> AsyncIterator[dict[str, Any]]:
"""Default lifespan context manager that does nothing.
Args:
server: The server instance this lifespan is managing
Returns:
An empty context object
"""

View file

@ -109,7 +109,7 @@ class FunctionResource(Resource):
class FileResource(Resource):
"""A resource that reads from a file.
Set is_binary=True to read file as binary data instead of text.
Set is_binary=True to read the file as binary data instead of text.
"""
path: Path = Field(description="Path to the file")

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