Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 36 additions & 8 deletions src/mcp/server/fastmcp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@

import inspect
import re
from collections.abc import AsyncIterator, Awaitable, Callable, Collection, Iterable, Sequence
from collections.abc import (
AsyncIterator,
Awaitable,
Callable,
Collection,
Iterable,
Sequence,
)
from contextlib import AbstractAsyncContextManager, asynccontextmanager
from typing import Any, Generic, Literal

Expand All @@ -22,10 +29,21 @@
from starlette.types import Receive, Scope, Send

from mcp.server.auth.middleware.auth_context import AuthContextMiddleware
from mcp.server.auth.middleware.bearer_auth import BearerAuthBackend, RequireAuthMiddleware
from mcp.server.auth.provider import OAuthAuthorizationServerProvider, ProviderTokenVerifier, TokenVerifier
from mcp.server.auth.middleware.bearer_auth import (
BearerAuthBackend,
RequireAuthMiddleware,
)
from mcp.server.auth.provider import (
OAuthAuthorizationServerProvider,
ProviderTokenVerifier,
TokenVerifier,
)
from mcp.server.auth.settings import AuthSettings
from mcp.server.elicitation import ElicitationResult, ElicitSchemaModelT, elicit_with_validation
from mcp.server.elicitation import (
ElicitationResult,
ElicitSchemaModelT,
elicit_with_validation,
)
from mcp.server.fastmcp.exceptions import ResourceError
from mcp.server.fastmcp.prompts import Prompt, PromptManager
from mcp.server.fastmcp.resources import FunctionResource, Resource, ResourceManager
Expand Down Expand Up @@ -112,7 +130,9 @@ def lifespan_wrapper(
lifespan: Callable[[FastMCP[LifespanResultT]], AbstractAsyncContextManager[LifespanResultT]],
) -> Callable[[MCPServer[LifespanResultT, Request]], AbstractAsyncContextManager[LifespanResultT]]:
@asynccontextmanager
async def wrap(_: MCPServer[LifespanResultT, Request]) -> AsyncIterator[LifespanResultT]:
async def wrap(
_: MCPServer[LifespanResultT, Request],
) -> AsyncIterator[LifespanResultT]:
async with lifespan(app) as context:
yield context

Expand All @@ -126,7 +146,7 @@ def __init__( # noqa: PLR0913
instructions: str | None = None,
website_url: str | None = None,
icons: list[Icon] | None = None,
auth_server_provider: OAuthAuthorizationServerProvider[Any, Any, Any] | None = None,
auth_server_provider: (OAuthAuthorizationServerProvider[Any, Any, Any] | None) = None,
token_verifier: TokenVerifier | None = None,
event_store: EventStore | None = None,
*,
Expand All @@ -145,7 +165,7 @@ def __init__( # noqa: PLR0913
warn_on_duplicate_tools: bool = True,
warn_on_duplicate_prompts: bool = True,
dependencies: Collection[str] = (),
lifespan: Callable[[FastMCP[LifespanResultT]], AbstractAsyncContextManager[LifespanResultT]] | None = None,
lifespan: (Callable[[FastMCP[LifespanResultT]], AbstractAsyncContextManager[LifespanResultT]] | None) = None,
auth: AuthSettings | None = None,
transport_security: TransportSecuritySettings | None = None,
):
Expand Down Expand Up @@ -290,6 +310,7 @@ async def list_tools(self) -> list[MCPTool]:
outputSchema=info.output_schema,
annotations=info.annotations,
icons=info.icons,
_meta=info.meta,
)
for info in tools
]
Expand Down Expand Up @@ -363,6 +384,7 @@ def add_tool(
description: str | None = None,
annotations: ToolAnnotations | None = None,
icons: list[Icon] | None = None,
meta: dict[str, Any] | None = None,
structured_output: bool | None = None,
) -> None:
"""Add a tool to the server.
Expand All @@ -388,6 +410,7 @@ def add_tool(
description=description,
annotations=annotations,
icons=icons,
meta=meta,
structured_output=structured_output,
)

Expand All @@ -409,6 +432,7 @@ def tool(
description: str | None = None,
annotations: ToolAnnotations | None = None,
icons: list[Icon] | None = None,
meta: dict[str, Any] | None = None,
structured_output: bool | None = None,
) -> Callable[[AnyFunction], AnyFunction]:
"""Decorator to register a tool.
Expand Down Expand Up @@ -456,6 +480,7 @@ def decorator(fn: AnyFunction) -> AnyFunction:
description=description,
annotations=annotations,
icons=icons,
meta=meta,
structured_output=structured_output,
)
return fn
Expand Down Expand Up @@ -1164,7 +1189,10 @@ async def elicit(
"""

return await elicit_with_validation(
session=self.request_context.session, message=message, schema=schema, related_request_id=self.request_id
session=self.request_context.session,
message=message,
schema=schema,
related_request_id=self.request_id,
)

async def log(
Expand Down
3 changes: 3 additions & 0 deletions src/mcp/server/fastmcp/tools/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class Tool(BaseModel):
context_kwarg: str | None = Field(None, description="Name of the kwarg that should receive context")
annotations: ToolAnnotations | None = Field(None, description="Optional annotations for the tool")
icons: list[Icon] | None = Field(default=None, description="Optional list of icons for this tool")
meta: dict[str, Any] | None = Field(default=None, description="Optional metadata for this tool")

@cached_property
def output_schema(self) -> dict[str, Any] | None:
Expand All @@ -49,6 +50,7 @@ def from_function(
context_kwarg: str | None = None,
annotations: ToolAnnotations | None = None,
icons: list[Icon] | None = None,
meta: dict[str, Any] | None = None,
structured_output: bool | None = None,
) -> Tool:
"""Create a Tool from a function."""
Expand Down Expand Up @@ -81,6 +83,7 @@ def from_function(
context_kwarg=context_kwarg,
annotations=annotations,
icons=icons,
meta=meta,
)

async def run(
Expand Down
2 changes: 2 additions & 0 deletions src/mcp/server/fastmcp/tools/tool_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def add_tool(
description: str | None = None,
annotations: ToolAnnotations | None = None,
icons: list[Icon] | None = None,
meta: dict[str, Any] | None = None,
structured_output: bool | None = None,
) -> Tool:
"""Add a tool to the server."""
Expand All @@ -60,6 +61,7 @@ def add_tool(
description=description,
annotations=annotations,
icons=icons,
meta=meta,
structured_output=structured_output,
)
existing = self._tools.get(tool.name)
Expand Down
Loading