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
4 changed files with 177 additions and 163 deletions

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")

View file

@ -108,7 +108,7 @@ class Settings(BaseSettings, Generic[LifespanResultT]):
warn_on_duplicate_prompts: bool
lifespan: Callable[[MCPServer[LifespanResultT]], AbstractAsyncContextManager[LifespanResultT]] | None
"""A async context manager that will be called when the server is started."""
"""An async context manager that will be called when the server is started."""
auth: AuthSettings | None
@ -388,8 +388,10 @@ class MCPServer(Generic[LifespanResultT]):
]
def get_context(self) -> Context[LifespanResultT, Request]:
"""Returns a Context object. Note that the context will only be valid
during a request; outside a request, most methods will error.
"""Return a Context object.
Note that the context will only be valid during a request; outside a
request, most methods will error.
"""
try:
request_context = request_ctx.get()
@ -475,6 +477,8 @@ class MCPServer(Generic[LifespanResultT]):
title: Optional human-readable title for the tool
description: Optional description of what the tool does
annotations: Optional ToolAnnotations providing additional tool information
icons: Optional list of icons for the tool
meta: Optional metadata dictionary for the tool
structured_output: Controls whether the tool's output is structured or unstructured
- If None, auto-detects based on the function's return type annotation
- If True, creates a structured tool (return type annotation permitting)
@ -523,6 +527,8 @@ class MCPServer(Generic[LifespanResultT]):
title: Optional human-readable title for the tool
description: Optional description of what the tool does
annotations: Optional ToolAnnotations providing additional tool information
icons: Optional list of icons for the tool
meta: Optional metadata dictionary for the tool
structured_output: Controls whether the tool's output is structured or unstructured
- If None, auto-detects based on the function's return type annotation
- If True, creates a structured tool (return type annotation permitting)
@ -534,8 +540,8 @@ class MCPServer(Generic[LifespanResultT]):
return str(x)
@server.tool()
def tool_with_context(x: int, ctx: Context) -> str:
ctx.info(f"Processing {x}")
async def tool_with_context(x: int, ctx: Context) -> str:
await ctx.info(f"Processing {x}")
return str(x)
@server.tool()
@ -636,6 +642,8 @@ class MCPServer(Generic[LifespanResultT]):
title: Optional human-readable title for the resource
description: Optional description of the resource
mime_type: Optional MIME type for the resource
icons: Optional list of icons for the resource
annotations: Optional annotations for the resource
meta: Optional metadata dictionary for the resource
Example:
@ -644,7 +652,7 @@ class MCPServer(Generic[LifespanResultT]):
return "Hello, world!"
@server.resource("resource://my-resource")
async get_data() -> str:
async def get_data() -> str:
data = await fetch_data()
return f"Hello, world! {data}"
@ -736,6 +744,7 @@ class MCPServer(Generic[LifespanResultT]):
name: Optional name for the prompt (defaults to function name)
title: Optional human-readable title for the prompt
description: Optional description of what the prompt does
icons: Optional list of icons for the prompt
Example:
@server.prompt()
@ -1092,18 +1101,18 @@ class Context(BaseModel, Generic[LifespanContextT, RequestT]):
```python
@server.tool()
def my_tool(x: int, ctx: Context) -> str:
async def my_tool(x: int, ctx: Context) -> str:
# Log messages to the client
ctx.info(f"Processing {x}")
ctx.debug("Debug info")
ctx.warning("Warning message")
ctx.error("Error message")
await ctx.info(f"Processing {x}")
await ctx.debug("Debug info")
await ctx.warning("Warning message")
await ctx.error("Error message")
# Report progress
ctx.report_progress(50, 100)
await ctx.report_progress(50, 100)
# Access resources
data = ctx.read_resource("resource://data")
data = await ctx.read_resource("resource://data")
# Get request info
request_id = ctx.request_id
@ -1149,9 +1158,9 @@ class Context(BaseModel, Generic[LifespanContextT, RequestT]):
"""Report progress for the current operation.
Args:
progress: Current progress value e.g. 24
total: Optional total value e.g. 100
message: Optional message e.g. Starting render...
progress: Current progress value (e.g., 24)
total: Optional total value (e.g., 100)
message: Optional message (e.g., "Starting render...")
"""
progress_token = self.request_context.meta.get("progress_token") if self.request_context.meta else None
@ -1187,15 +1196,14 @@ class Context(BaseModel, Generic[LifespanContextT, RequestT]):
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.
Args:
schema: A Pydantic model class defining the expected response structure, according to the specification,
only primitive types are allowed.
message: Optional message to present to the user. If not provided, will use
a default message based on the schema
message: Message to present to the user
schema: A Pydantic model class defining the expected response structure.
According to the specification, only primitive types are allowed.
Returns:
An ElicitationResult containing the action taken and the data if accepted
@ -1229,7 +1237,7 @@ class Context(BaseModel, Generic[LifespanContextT, RequestT]):
The response indicates whether the user consented to navigate to the URL.
The actual interaction happens out-of-band. When the elicitation completes,
call `self.session.send_elicit_complete(elicitation_id)` to notify the client.
call `ctx.session.send_elicit_complete(elicitation_id)` to notify the client.
Args:
message: Human-readable explanation of why the interaction is needed
@ -1299,7 +1307,7 @@ class Context(BaseModel, Generic[LifespanContextT, RequestT]):
be replayed when the client reconnects with Last-Event-ID.
Use this to implement polling behavior during long-running operations -
client will reconnect after the retry interval specified in the priming event.
the client will reconnect after the retry interval specified in the priming event.
Note:
This is a no-op if not using StreamableHTTP transport with event_store.

View file

@ -46,7 +46,7 @@ class ArgModelBase(BaseModel):
def model_dump_one_level(self) -> dict[str, Any]:
"""Return a dict of the model's fields, one level deep.
That is, sub-models etc are not dumped - they are kept as pydantic models.
That is, sub-models etc are not dumped - they are kept as Pydantic models.
"""
kwargs: dict[str, Any] = {}
for field_name, field_info in self.__class__.model_fields.items():
@ -89,8 +89,7 @@ class FuncMetadata(BaseModel):
return await anyio.to_thread.run_sync(functools.partial(fn, **arguments_parsed_dict))
def convert_result(self, result: Any) -> Any:
"""Convert the result of a function call to the appropriate format for
the lowlevel server tool call handler:
"""Convert a function call result to the format for the lowlevel tool call handler.
- If output_model is None, return the unstructured content directly.
- If output_model is not None, convert the result to structured output format
@ -126,11 +125,11 @@ class FuncMetadata(BaseModel):
def pre_parse_json(self, data: dict[str, Any]) -> dict[str, Any]:
"""Pre-parse data from JSON.
Return a dict with same keys as input but with values parsed from JSON
Return a dict with the same keys as input but with values parsed from JSON
if appropriate.
This is to handle cases like `["a", "b", "c"]` being passed in as JSON inside
a string rather than an actual list. Claude desktop is prone to this - in fact
a string rather than an actual list. Claude Desktop is prone to this - in fact
it seems incapable of NOT doing this. For sub-models, it tends to pass
dicts (JSON objects) as JSON strings, which can be pre-parsed here.
"""
@ -173,8 +172,7 @@ def func_metadata(
skip_names: Sequence[str] = (),
structured_output: bool | None = None,
) -> FuncMetadata:
"""Given a function, return metadata including a pydantic model representing its
signature.
"""Given a function, return metadata including a Pydantic model representing its signature.
The use case for this is
```
@ -183,11 +181,11 @@ def func_metadata(
return func(**validated_args.model_dump_one_level())
```
**critically** it also provides pre-parse helper to attempt to parse things from
**critically** it also provides a pre-parse helper to attempt to parse things from
JSON.
Args:
func: The function to convert to a pydantic model
func: The function to convert to a Pydantic model
skip_names: A list of parameter names to skip. These will not be included in
the model.
structured_output: Controls whether the tool's output is structured or unstructured
@ -195,8 +193,8 @@ def func_metadata(
- If True, creates a structured tool (return type annotation permitting)
- If False, unconditionally creates an unstructured tool
If structured, creates a Pydantic model for the function's result based on its annotation.
Supports various return types:
If structured, creates a Pydantic model for the function's result based on its annotation.
Supports various return types:
- BaseModel subclasses (used directly)
- Primitive types (str, int, float, bool, bytes, None) - wrapped in a
model with a 'result' field
@ -206,9 +204,9 @@ def func_metadata(
Returns:
A FuncMetadata object containing:
- arg_model: A pydantic model representing the function's arguments
- output_model: A pydantic model for the return type if output is structured
- output_conversion: Records how function output should be converted before returning.
- arg_model: A Pydantic model representing the function's arguments
- output_model: A Pydantic model for the return type if the output is structured
- wrap_output: Whether the function result needs to be wrapped in `{"result": ...}` for structured output.
"""
try:
sig = inspect.signature(func, eval_str=True)
@ -296,7 +294,7 @@ def func_metadata(
] # pragma: no cover
else:
# We only had `Annotated[CallToolResult, ReturnType]`, treat the original annotation
# as beging `ReturnType`:
# as being `ReturnType`:
original_annotation = return_type_expr
else:
return FuncMetadata(arg_model=arguments_model)
@ -355,7 +353,7 @@ def _try_create_model_and_schema(
if origin is dict:
args = get_args(type_expr)
if len(args) == 2 and args[0] is str:
# TODO: should we use the original annotation? We are loosing any potential `Annotated`
# TODO: should we use the original annotation? We are losing any potential `Annotated`
# metadata for Pydantic here:
model = _create_dict_model(func_name, type_expr)
else:

View file

@ -8,10 +8,10 @@ def get_logger(name: str) -> logging.Logger:
"""Get a logger nested under MCP namespace.
Args:
name: the name of the logger
name: The name of the logger.
Returns:
a configured logger instance
A configured logger instance.
"""
return logging.getLogger(name)
@ -22,7 +22,7 @@ def configure_logging(
"""Configure logging for MCP.
Args:
level: the log level to use
level: The log level to use.
"""
handlers: list[logging.Handler] = []
try: