Rename FastMCP to MCPServer (#1951)

This commit is contained in:
Marcelo Trylesinski
2026-01-25 14:45:52 +01:00
committed by GitHub
parent 4a2d83a0cb
commit 65c614e48e
123 changed files with 713 additions and 693 deletions
+1 -1
View File
@@ -39,7 +39,7 @@ body:
demonstrating the bug.
placeholder: |
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
...
render: Python
+92 -92
View File
@@ -45,7 +45,7 @@
- [Sampling](#sampling)
- [Logging and Notifications](#logging-and-notifications)
- [Authentication](#authentication)
- [FastMCP Properties](#fastmcp-properties)
- [MCPServer Properties](#mcpserver-properties)
- [Session Properties and Methods](#session-properties-and-methods)
- [Request Context Properties](#request-context-properties)
- [Running Your Server](#running-your-server)
@@ -134,18 +134,18 @@ uv run mcp
Let's create a simple MCP server that exposes a calculator tool and some data:
<!-- snippet-source examples/snippets/servers/fastmcp_quickstart.py -->
<!-- snippet-source examples/snippets/servers/mcpserver_quickstart.py -->
```python
"""FastMCP quickstart example.
"""MCPServer quickstart example.
Run from the repository root:
uv run examples/snippets/servers/fastmcp_quickstart.py
uv run examples/snippets/servers/mcpserver_quickstart.py
"""
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create an MCP server
mcp = FastMCP("Demo")
mcp = MCPServer("Demo")
# Add an addition tool
@@ -180,13 +180,13 @@ if __name__ == "__main__":
mcp.run(transport="streamable-http", json_response=True)
```
_Full example: [examples/snippets/servers/fastmcp_quickstart.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/fastmcp_quickstart.py)_
_Full example: [examples/snippets/servers/mcpserver_quickstart.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/mcpserver_quickstart.py)_
<!-- /snippet-source -->
You can install this server in [Claude Code](https://docs.claude.com/en/docs/claude-code/mcp) and interact with it right away. First, run the server:
```bash
uv run --with mcp examples/snippets/servers/fastmcp_quickstart.py
uv run --with mcp examples/snippets/servers/mcpserver_quickstart.py
```
Then add it to Claude Code:
@@ -216,7 +216,7 @@ The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) lets you bui
### Server
The FastMCP server is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:
The MCPServer server is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:
<!-- snippet-source examples/snippets/servers/lifespan_example.py -->
```python
@@ -226,7 +226,7 @@ from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from dataclasses import dataclass
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.mcpserver import Context, MCPServer
from mcp.server.session import ServerSession
@@ -256,7 +256,7 @@ class AppContext:
@asynccontextmanager
async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
async def app_lifespan(server: MCPServer) -> AsyncIterator[AppContext]:
"""Manage application lifecycle with type-safe context."""
# Initialize on startup
db = await Database.connect()
@@ -268,7 +268,7 @@ async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
# Pass lifespan to server
mcp = FastMCP("My App", lifespan=app_lifespan)
mcp = MCPServer("My App", lifespan=app_lifespan)
# Access type-safe lifespan context in tools
@@ -288,9 +288,9 @@ Resources are how you expose data to LLMs. They're similar to GET endpoints in a
<!-- snippet-source examples/snippets/servers/basic_resource.py -->
```python
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
mcp = FastMCP(name="Resource Example")
mcp = MCPServer(name="Resource Example")
@mcp.resource("file://documents/{name}")
@@ -319,9 +319,9 @@ Tools let LLMs take actions through your server. Unlike resources, tools are exp
<!-- snippet-source examples/snippets/servers/basic_tool.py -->
```python
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
mcp = FastMCP(name="Tool Example")
mcp = MCPServer(name="Tool Example")
@mcp.tool()
@@ -340,14 +340,14 @@ def get_weather(city: str, unit: str = "celsius") -> str:
_Full example: [examples/snippets/servers/basic_tool.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_tool.py)_
<!-- /snippet-source -->
Tools can optionally receive a Context object by including a parameter with the `Context` type annotation. This context is automatically injected by the FastMCP framework and provides access to MCP capabilities:
Tools can optionally receive a Context object by including a parameter with the `Context` type annotation. This context is automatically injected by the MCPServer framework and provides access to MCP capabilities:
<!-- snippet-source examples/snippets/servers/tool_progress.py -->
```python
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.mcpserver import Context, MCPServer
from mcp.server.session import ServerSession
mcp = FastMCP(name="Progress Example")
mcp = MCPServer(name="Progress Example")
@mcp.tool()
@@ -395,7 +395,7 @@ validated data that clients can easily process.
**Note:** For backward compatibility, unstructured results are also
returned. Unstructured results are provided for backward compatibility
with previous versions of the MCP specification, and are quirks-compatible
with previous versions of FastMCP in the current version of the SDK.
with previous versions of MCPServer in the current version of the SDK.
**Note:** In cases where a tool function's return type annotation
causes the tool to be classified as structured _and this is undesirable_,
@@ -414,10 +414,10 @@ from typing import Annotated
from pydantic import BaseModel
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
from mcp.types import CallToolResult, TextContent
mcp = FastMCP("CallToolResult Example")
mcp = MCPServer("CallToolResult Example")
class ValidationModel(BaseModel):
@@ -465,9 +465,9 @@ from typing import TypedDict
from pydantic import BaseModel, Field
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
mcp = FastMCP("Structured Output Example")
mcp = MCPServer("Structured Output Example")
# Using Pydantic models for rich structured data
@@ -567,10 +567,10 @@ Prompts are reusable templates that help LLMs interact with your server effectiv
<!-- snippet-source examples/snippets/servers/basic_prompt.py -->
```python
from mcp.server.fastmcp import FastMCP
from mcp.server.fastmcp.prompts import base
from mcp.server.mcpserver import MCPServer
from mcp.server.mcpserver.prompts import base
mcp = FastMCP(name="Prompt Example")
mcp = MCPServer(name="Prompt Example")
@mcp.prompt(title="Code Review")
@@ -595,7 +595,7 @@ _Full example: [examples/snippets/servers/basic_prompt.py](https://github.com/mo
MCP servers can provide icons for UI display. Icons can be added to the server implementation, tools, resources, and prompts:
```python
from mcp.server.fastmcp import FastMCP, Icon
from mcp.server.mcpserver import MCPServer, Icon
# Create an icon from a file path or URL
icon = Icon(
@@ -605,7 +605,7 @@ icon = Icon(
)
# Add icons to server
mcp = FastMCP(
mcp = MCPServer(
"My Server",
website_url="https://example.com",
icons=[icon]
@@ -623,21 +623,21 @@ def my_resource():
return "content"
```
_Full example: [examples/fastmcp/icons_demo.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/fastmcp/icons_demo.py)_
_Full example: [examples/mcpserver/icons_demo.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/mcpserver/icons_demo.py)_
### Images
FastMCP provides an `Image` class that automatically handles image data:
MCPServer provides an `Image` class that automatically handles image data:
<!-- snippet-source examples/snippets/servers/images.py -->
```python
"""Example showing image handling with FastMCP."""
"""Example showing image handling with MCPServer."""
from PIL import Image as PILImage
from mcp.server.fastmcp import FastMCP, Image
from mcp.server.mcpserver import Image, MCPServer
mcp = FastMCP("Image Example")
mcp = MCPServer("Image Example")
@mcp.tool()
@@ -660,9 +660,9 @@ The Context object is automatically injected into tool and resource functions th
To use context in a tool or resource function, add a parameter with the `Context` type annotation:
```python
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.mcpserver import Context, MCPServer
mcp = FastMCP(name="Context Example")
mcp = MCPServer(name="Context Example")
@mcp.tool()
@@ -678,7 +678,7 @@ The Context object provides the following capabilities:
- `ctx.request_id` - Unique ID for the current request
- `ctx.client_id` - Client ID if available
- `ctx.fastmcp` - Access to the FastMCP server instance (see [FastMCP Properties](#fastmcp-properties))
- `ctx.mcp_server` - Access to the MCPServer server instance (see [MCPServer Properties](#mcpserver-properties))
- `ctx.session` - Access to the underlying session for advanced communication (see [Session Properties and Methods](#session-properties-and-methods))
- `ctx.request_context` - Access to request-specific data and lifespan resources (see [Request Context Properties](#request-context-properties))
- `await ctx.debug(message)` - Send debug log message
@@ -692,10 +692,10 @@ The Context object provides the following capabilities:
<!-- snippet-source examples/snippets/servers/tool_progress.py -->
```python
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.mcpserver import Context, MCPServer
from mcp.server.session import ServerSession
mcp = FastMCP(name="Progress Example")
mcp = MCPServer(name="Progress Example")
@mcp.tool()
@@ -824,12 +824,12 @@ import uuid
from pydantic import BaseModel, Field
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.mcpserver import Context, MCPServer
from mcp.server.session import ServerSession
from mcp.shared.exceptions import UrlElicitationRequiredError
from mcp.types import ElicitRequestURLParams
mcp = FastMCP(name="Elicitation Example")
mcp = MCPServer(name="Elicitation Example")
class BookingPreferences(BaseModel):
@@ -931,11 +931,11 @@ Tools can interact with LLMs through sampling (generating text):
<!-- snippet-source examples/snippets/servers/sampling.py -->
```python
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.mcpserver import Context, MCPServer
from mcp.server.session import ServerSession
from mcp.types import SamplingMessage, TextContent
mcp = FastMCP(name="Sampling Example")
mcp = MCPServer(name="Sampling Example")
@mcp.tool()
@@ -968,10 +968,10 @@ Tools can send logs and notifications through the context:
<!-- snippet-source examples/snippets/servers/notifications.py -->
```python
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.mcpserver import Context, MCPServer
from mcp.server.session import ServerSession
mcp = FastMCP(name="Notifications Example")
mcp = MCPServer(name="Notifications Example")
@mcp.tool()
@@ -1010,7 +1010,7 @@ from pydantic import AnyHttpUrl
from mcp.server.auth.provider import AccessToken, TokenVerifier
from mcp.server.auth.settings import AuthSettings
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
class SimpleTokenVerifier(TokenVerifier):
@@ -1020,8 +1020,8 @@ class SimpleTokenVerifier(TokenVerifier):
pass # This is where you would implement actual token validation
# Create FastMCP instance as a Resource Server
mcp = FastMCP(
# Create MCPServer instance as a Resource Server
mcp = MCPServer(
"Weather Service",
# Token verifier for authentication
token_verifier=SimpleTokenVerifier(),
@@ -1062,15 +1062,15 @@ For a complete example with separate Authorization Server and Resource Server im
See [TokenVerifier](src/mcp/server/auth/provider.py) for more details on implementing token validation.
### FastMCP Properties
### MCPServer Properties
The FastMCP server instance accessible via `ctx.fastmcp` provides access to server configuration and metadata:
The MCPServer server instance accessible via `ctx.mcp_server` provides access to server configuration and metadata:
- `ctx.fastmcp.name` - The server's name as defined during initialization
- `ctx.fastmcp.instructions` - Server instructions/description provided to clients
- `ctx.fastmcp.website_url` - Optional website URL for the server
- `ctx.fastmcp.icons` - Optional list of icons for UI display
- `ctx.fastmcp.settings` - Complete server configuration object containing:
- `ctx.mcp_server.name` - The server's name as defined during initialization
- `ctx.mcp_server.instructions` - Server instructions/description provided to clients
- `ctx.mcp_server.website_url` - Optional website URL for the server
- `ctx.mcp_server.icons` - Optional list of icons for UI display
- `ctx.mcp_server.settings` - Complete server configuration object containing:
- `debug` - Debug mode flag
- `log_level` - Current logging level
- `host` and `port` - Server network configuration
@@ -1083,12 +1083,12 @@ The FastMCP server instance accessible via `ctx.fastmcp` provides access to serv
def server_info(ctx: Context) -> dict:
"""Get information about the current server."""
return {
"name": ctx.fastmcp.name,
"instructions": ctx.fastmcp.instructions,
"debug_mode": ctx.fastmcp.settings.debug,
"log_level": ctx.fastmcp.settings.log_level,
"host": ctx.fastmcp.settings.host,
"port": ctx.fastmcp.settings.port,
"name": ctx.mcp_server.name,
"instructions": ctx.mcp_server.instructions,
"debug_mode": ctx.mcp_server.settings.debug,
"log_level": ctx.mcp_server.settings.log_level,
"host": ctx.mcp_server.settings.host,
"port": ctx.mcp_server.settings.port,
}
```
@@ -1203,9 +1203,9 @@ cd to the `examples/snippets` directory and run:
python servers/direct_execution.py
"""
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
mcp = FastMCP("My App")
mcp = MCPServer("My App")
@mcp.tool()
@@ -1234,7 +1234,7 @@ python servers/direct_execution.py
uv run mcp run servers/direct_execution.py
```
Note that `uv run mcp run` or `uv run mcp dev` only supports server using FastMCP and not the low-level server variant.
Note that `uv run mcp run` or `uv run mcp dev` only supports server using MCPServer and not the low-level server variant.
### Streamable HTTP Transport
@@ -1246,9 +1246,9 @@ Note that `uv run mcp run` or `uv run mcp dev` only supports server using FastMC
uv run examples/snippets/servers/streamable_config.py
"""
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
mcp = FastMCP("StatelessServer")
mcp = MCPServer("StatelessServer")
# Add a simple tool to demonstrate the server
@@ -1275,7 +1275,7 @@ if __name__ == "__main__":
_Full example: [examples/snippets/servers/streamable_config.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_config.py)_
<!-- /snippet-source -->
You can mount multiple FastMCP servers in a Starlette application:
You can mount multiple MCPServer servers in a Starlette application:
<!-- snippet-source examples/snippets/servers/streamable_starlette_mount.py -->
```python
@@ -1288,10 +1288,10 @@ import contextlib
from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create the Echo server
echo_mcp = FastMCP(name="EchoServer")
echo_mcp = MCPServer(name="EchoServer")
@echo_mcp.tool()
@@ -1301,7 +1301,7 @@ def echo(message: str) -> str:
# Create the Math server
math_mcp = FastMCP(name="MathServer")
math_mcp = MCPServer(name="MathServer")
@math_mcp.tool()
@@ -1400,10 +1400,10 @@ import contextlib
from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create MCP server
mcp = FastMCP("My App")
mcp = MCPServer("My App")
@mcp.tool()
@@ -1447,10 +1447,10 @@ import contextlib
from starlette.applications import Starlette
from starlette.routing import Host
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create MCP server
mcp = FastMCP("MCP Host App")
mcp = MCPServer("MCP Host App")
@mcp.tool()
@@ -1494,11 +1494,11 @@ import contextlib
from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create multiple MCP servers
api_mcp = FastMCP("API Server")
chat_mcp = FastMCP("Chat Server")
api_mcp = MCPServer("API Server")
chat_mcp = MCPServer("Chat Server")
@api_mcp.tool()
@@ -1540,7 +1540,7 @@ _Full example: [examples/snippets/servers/streamable_http_multiple_servers.py](h
<!-- snippet-source examples/snippets/servers/streamable_http_path_config.py -->
```python
"""Example showing path configuration when mounting FastMCP.
"""Example showing path configuration when mounting MCPServer.
Run from the repository root:
uvicorn examples.snippets.servers.streamable_http_path_config:app --reload
@@ -1549,10 +1549,10 @@ Run from the repository root:
from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create a simple FastMCP server
mcp_at_root = FastMCP("My Server")
# Create a simple MCPServer server
mcp_at_root = MCPServer("My Server")
@mcp_at_root.tool()
@@ -1585,10 +1585,10 @@ You can mount the SSE server to an existing ASGI server using the `sse_app` meth
```python
from starlette.applications import Starlette
from starlette.routing import Mount, Host
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
mcp = FastMCP("My App")
mcp = MCPServer("My App")
# Mount the SSE server to the existing ASGI server
app = Starlette(
@@ -1606,12 +1606,12 @@ You can also mount multiple MCP servers at different sub-paths. The SSE transpor
```python
from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create multiple MCP servers
github_mcp = FastMCP("GitHub API")
browser_mcp = FastMCP("Browser")
search_mcp = FastMCP("Search")
github_mcp = MCPServer("GitHub API")
browser_mcp = MCPServer("Browser")
search_mcp = MCPServer("Search")
# Mount each server at its own sub-path
# The SSE transport automatically uses ASGI's root_path to construct
@@ -2126,7 +2126,7 @@ from mcp.shared.context import RequestContext
# Create server parameters for stdio connection
server_params = StdioServerParameters(
command="uv", # Using uv to run the server
args=["run", "server", "fastmcp_quickstart", "stdio"], # We're already in snippets dir
args=["run", "server", "mcpserver_quickstart", "stdio"], # We're already in snippets dir
env={"UV_INDEX": os.environ.get("UV_INDEX", "")},
)
@@ -2157,7 +2157,7 @@ async def run():
prompts = await session.list_prompts()
print(f"Available prompts: {[p.name for p in prompts.prompts]}")
# Get a prompt (greet_user prompt from fastmcp_quickstart)
# Get a prompt (greet_user prompt from mcpserver_quickstart)
if prompts.prompts:
prompt = await session.get_prompt("greet_user", arguments={"name": "Alice", "style": "friendly"})
print(f"Prompt result: {prompt.messages[0].content}")
@@ -2170,13 +2170,13 @@ async def run():
tools = await session.list_tools()
print(f"Available tools: {[t.name for t in tools.tools]}")
# Read a resource (greeting resource from fastmcp_quickstart)
# Read a resource (greeting resource from mcpserver_quickstart)
resource_content = await session.read_resource("greeting://World")
content_block = resource_content.contents[0]
if isinstance(content_block, types.TextContent):
print(f"Resource content: {content_block.text}")
# Call a tool (add tool from fastmcp_quickstart)
# Call a tool (add tool from mcpserver_quickstart)
result = await session.call_tool("add", arguments={"a": 5, "b": 3})
result_unstructured = result.content[0]
if isinstance(result_unstructured, types.TextContent):
@@ -2254,7 +2254,7 @@ from mcp.shared.metadata_utils import get_display_name
# Create server parameters for stdio connection
server_params = StdioServerParameters(
command="uv", # Using uv to run the server
args=["run", "server", "fastmcp_quickstart", "stdio"],
args=["run", "server", "mcpserver_quickstart", "stdio"],
env={"UV_INDEX": os.environ.get("UV_INDEX", "")},
)
+2 -2
View File
@@ -15,9 +15,9 @@ If you want to read more about the specification, please visit the [MCP document
Here's a simple MCP server that exposes a tool, resource, and prompt:
```python title="server.py"
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
mcp = FastMCP("Test Server", json_response=True)
mcp = MCPServer("Test Server", json_response=True)
@mcp.tool()
+1 -1
View File
@@ -21,7 +21,7 @@ The following dependencies are automatically installed:
- [`starlette`](https://pypi.org/project/starlette/): Web framework used to build the HTTP transport endpoints.
- [`python-multipart`](https://pypi.org/project/python-multipart/): Handle HTTP body parsing.
- [`sse-starlette`](https://pypi.org/project/sse-starlette/): Server-Sent Events for Starlette, used to build the SSE transport endpoint.
- [`pydantic-settings`](https://pypi.org/project/pydantic-settings/): Settings management used in FastMCP.
- [`pydantic-settings`](https://pypi.org/project/pydantic-settings/): Settings management used in MCPServer.
- [`uvicorn`](https://pypi.org/project/uvicorn/): ASGI server used to run the HTTP transport endpoints.
- [`jsonschema`](https://pypi.org/project/jsonschema/): JSON schema validation.
- [`pywin32`](https://pypi.org/project/pywin32/): Windows specific dependencies for the CLI tools.
+34 -10
View File
@@ -121,15 +121,35 @@ result = await session.list_resources(params=PaginatedRequestParams(cursor="next
result = await session.list_tools(params=PaginatedRequestParams(cursor="next_page_token"))
```
### `mount_path` parameter removed from FastMCP
### `FastMCP` renamed to `MCPServer`
The `mount_path` parameter has been removed from `FastMCP.__init__()`, `FastMCP.run()`, `FastMCP.run_sse_async()`, and `FastMCP.sse_app()`. It was also removed from the `Settings` class.
The `FastMCP` class has been renamed to `MCPServer` to better reflect its role as the main server class in the SDK. This is a simple rename with no functional changes to the class itself.
**Before (v1):**
```python
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Demo")
```
**After (v2):**
```python
from mcp.server.mcpserver import MCPServer
mcp = MCPServer("Demo")
```
### `mount_path` parameter removed from MCPServer
The `mount_path` parameter has been removed from `MCPServer.__init__()`, `MCPServer.run()`, `MCPServer.run_sse_async()`, and `MCPServer.sse_app()`. It was also removed from the `Settings` class.
This parameter was redundant because the SSE transport already handles sub-path mounting via ASGI's standard `root_path` mechanism. When using Starlette's `Mount("/path", app=mcp.sse_app())`, Starlette automatically sets `root_path` in the ASGI scope, and the `SseServerTransport` uses this to construct the correct message endpoint path.
### Transport-specific parameters moved from FastMCP constructor to run()/app methods
### Transport-specific parameters moved from MCPServer constructor to run()/app methods
Transport-specific parameters have been moved from the `FastMCP` constructor to the `run()`, `sse_app()`, and `streamable_http_app()` methods. This provides better separation of concerns - the constructor now only handles server identity and authentication, while transport configuration is passed when starting the server.
Transport-specific parameters have been moved from the `MCPServer` constructor to the `run()`, `sse_app()`, and `streamable_http_app()` methods. This provides better separation of concerns - the constructor now only handles server identity and authentication, while transport configuration is passed when starting the server.
**Parameters moved:**
@@ -157,28 +177,32 @@ mcp.run(transport="sse")
**After (v2):**
```python
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Transport params passed to run()
mcp = FastMCP("Demo")
mcp = MCPServer("Demo")
mcp.run(transport="streamable-http", json_response=True, stateless_http=True)
# Or for SSE
mcp = FastMCP("Server")
mcp = MCPServer("Server")
mcp.run(transport="sse", host="0.0.0.0", port=9000, sse_path="/events")
```
**For mounted apps:**
When mounting FastMCP in a Starlette app, pass transport params to the app methods:
When mounting in a Starlette app, pass transport params to the app methods:
```python
# Before (v1)
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("App", json_response=True)
app = Starlette(routes=[Mount("/", app=mcp.streamable_http_app())])
# After (v2)
mcp = FastMCP("App")
from mcp.server.mcpserver import MCPServer
mcp = MCPServer("App")
app = Starlette(routes=[Mount("/", app=mcp.streamable_http_app(json_response=True))])
```
@@ -354,7 +378,7 @@ params = CallToolRequestParams(
### `streamable_http_app()` available on lowlevel Server
The `streamable_http_app()` method is now available directly on the lowlevel `Server` class, not just `FastMCP`. This allows using the streamable HTTP transport without the FastMCP wrapper.
The `streamable_http_app()` method is now available directly on the lowlevel `Server` class, not just `MCPServer`. This allows using the streamable HTTP transport without the MCPServer wrapper.
```python
from mcp.server.lowlevel.server import Server
+2 -2
View File
@@ -8,9 +8,9 @@ This makes it easy to write tests without network overhead.
Let's assume you have a simple server with a single tool:
```python title="server.py"
from mcp.server import FastMCP
from mcp.server import MCPServer
app = FastMCP("Calculator")
app = MCPServer("Calculator")
@app.tool()
def add(a: int, b: int) -> int:
@@ -1,4 +1,4 @@
"""FastMCP Complex inputs Example
"""MCPServer Complex inputs Example
Demonstrates validation via pydantic with complex models.
"""
@@ -7,9 +7,9 @@ from typing import Annotated
from pydantic import BaseModel, Field
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
mcp = FastMCP("Shrimp Tank")
mcp = MCPServer("Shrimp Tank")
class ShrimpTank(BaseModel):
@@ -1,14 +1,14 @@
"""FastMCP Desktop Example
"""MCPServer Desktop Example
A simple example that exposes the desktop directory as a resource.
"""
from pathlib import Path
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create server
mcp = FastMCP("Demo")
mcp = MCPServer("Demo")
@mcp.resource("dir://desktop")
@@ -1,13 +1,13 @@
"""FastMCP Echo Server with direct CallToolResult return"""
"""MCPServer Echo Server with direct CallToolResult return"""
from typing import Annotated
from pydantic import BaseModel
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
from mcp.types import CallToolResult, TextContent
mcp = FastMCP("Echo Server")
mcp = MCPServer("Echo Server")
class EchoResponse(BaseModel):
@@ -1,9 +1,9 @@
"""FastMCP Echo Server"""
"""MCPServer Echo Server"""
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create server
mcp = FastMCP("Echo Server")
mcp = MCPServer("Echo Server")
@mcp.tool()
@@ -1,4 +1,4 @@
"""FastMCP Icons Demo Server
"""MCPServer Icons Demo Server
Demonstrates using icons with tools, resources, prompts, and implementation.
"""
@@ -6,7 +6,7 @@ Demonstrates using icons with tools, resources, prompts, and implementation.
import base64
from pathlib import Path
from mcp.server.fastmcp import FastMCP, Icon
from mcp.server.mcpserver import Icon, MCPServer
# Load the icon file and convert to data URI
icon_path = Path(__file__).parent / "mcp.png"
@@ -16,7 +16,9 @@ icon_data_uri = f"data:image/png;base64,{icon_data}"
icon_data = Icon(src=icon_data_uri, mime_type="image/png", sizes=["64x64"])
# Create server with icons in implementation
mcp = FastMCP("Icons Demo Server", website_url="https://github.com/modelcontextprotocol/python-sdk", icons=[icon_data])
mcp = MCPServer(
"Icons Demo Server", website_url="https://github.com/modelcontextprotocol/python-sdk", icons=[icon_data]
)
@mcp.tool(icons=[icon_data])
@@ -1,11 +1,11 @@
"""FastMCP Echo Server that sends log messages and progress updates to the client"""
"""MCPServer Echo Server that sends log messages and progress updates to the client"""
import asyncio
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.mcpserver import Context, MCPServer
# Create server
mcp = FastMCP("Echo Server with logging and progress updates")
mcp = MCPServer("Echo Server with logging and progress updates")
@mcp.tool()

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

@@ -24,7 +24,7 @@ from pgvector.asyncpg import register_vector # Import register_vector
from pydantic import BaseModel, Field
from pydantic_ai import Agent
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
MAX_DEPTH = 5
SIMILARITY_THRESHOLD = 0.7
@@ -36,11 +36,11 @@ DEFAULT_EMBEDDING_MODEL = "text-embedding-3-small"
T = TypeVar("T")
mcp = FastMCP("memory")
mcp = MCPServer("memory")
DB_DSN = "postgresql://postgres:postgres@localhost:54320/memory_db"
# reset memory with rm ~/.fastmcp/{USER}/memory/*
PROFILE_DIR = (Path.home() / ".fastmcp" / os.environ.get("USER", "anon") / "memory").resolve()
# reset memory with rm ~/.mcp/{USER}/memory/*
PROFILE_DIR = (Path.home() / ".mcp" / os.environ.get("USER", "anon") / "memory").resolve()
PROFILE_DIR.mkdir(parents=True, exist_ok=True)
@@ -1,11 +1,11 @@
"""FastMCP Example showing parameter descriptions"""
"""MCPServer Example showing parameter descriptions"""
from pydantic import Field
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create server
mcp = FastMCP("Parameter Descriptions Server")
mcp = MCPServer("Parameter Descriptions Server")
@mcp.tool()
@@ -1,7 +1,7 @@
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create an MCP server
mcp = FastMCP("Demo")
mcp = MCPServer("Demo")
# Add an addition tool
@@ -1,15 +1,15 @@
"""FastMCP Screenshot Example
"""MCPServer Screenshot Example
Give Claude a tool to capture and view screenshots.
"""
import io
from mcp.server.fastmcp import FastMCP
from mcp.server.fastmcp.utilities.types import Image
from mcp.server.mcpserver import MCPServer
from mcp.server.mcpserver.utilities.types import Image
# Create server
mcp = FastMCP("Screenshot Demo")
mcp = MCPServer("Screenshot Demo")
@mcp.tool()
@@ -1,9 +1,9 @@
"""FastMCP Echo Server"""
"""MCPServer Echo Server"""
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create server
mcp = FastMCP("Echo Server")
mcp = MCPServer("Echo Server")
@mcp.tool()
@@ -2,9 +2,9 @@
# dependencies = []
# ///
"""FastMCP Text Me Server
"""MCPServer Text Me Server
--------------------------------
This defines a simple FastMCP server that sends a text message to a phone number via https://surgemsg.com/.
This defines a simple MCPServer server that sends a text message to a phone number via https://surgemsg.com/.
To run this example, create a `.env` file with the following values:
@@ -23,7 +23,7 @@ import httpx
from pydantic import BeforeValidator
from pydantic_settings import BaseSettings, SettingsConfigDict
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
class SurgeSettings(BaseSettings):
@@ -37,7 +37,7 @@ class SurgeSettings(BaseSettings):
# Create server
mcp = FastMCP("Text me")
mcp = MCPServer("Text me")
surge_settings = SurgeSettings() # type: ignore
@@ -1,10 +1,10 @@
"""Example FastMCP server that uses Unicode characters in various places to help test
"""Example MCPServer server that uses Unicode characters in various places to help test
Unicode handling in tools and inspectors.
"""
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
mcp = FastMCP()
mcp = MCPServer()
@mcp.tool(description="🌟 A tool that uses various Unicode characters in its description: á é í ó ú ñ 漢字 🎉")
@@ -1,4 +1,4 @@
"""FastMCP Weather Example with Structured Output
"""MCPServer Weather Example with Structured Output
Demonstrates how to use structured output with tools to return
well-typed, validated data that clients can easily process.
@@ -14,10 +14,10 @@ from typing import TypedDict
from pydantic import BaseModel, Field
from mcp.client import Client
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create server
mcp = FastMCP("Weather Service")
mcp = MCPServer("Weather Service")
# Example 1: Using a Pydantic model for structured output
@@ -10,8 +10,8 @@ import json
import logging
import click
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.fastmcp.prompts.base import UserMessage
from mcp.server.mcpserver import Context, MCPServer
from mcp.server.mcpserver.prompts.base import UserMessage
from mcp.server.session import ServerSession
from mcp.server.streamable_http import EventCallback, EventMessage, EventStore
from mcp.types import (
@@ -80,7 +80,7 @@ watched_resource_content = "Watched resource content"
# Create event store for SSE resumability (SEP-1699)
event_store = InMemoryEventStore()
mcp = FastMCP(
mcp = MCPServer(
name="mcp-conformance-test-server",
)
@@ -391,9 +391,9 @@ def test_prompt_with_image() -> list[UserMessage]:
# Custom request handlers
# TODO(felix): Add public APIs to FastMCP for subscribe_resource, unsubscribe_resource,
# and set_logging_level to avoid accessing protected _mcp_server attribute.
@mcp._mcp_server.set_logging_level() # pyright: ignore[reportPrivateUsage]
# TODO(felix): Add public APIs to MCPServer for subscribe_resource, unsubscribe_resource,
# and set_logging_level to avoid accessing protected _lowlevel_server attribute.
@mcp._lowlevel_server.set_logging_level() # pyright: ignore[reportPrivateUsage]
async def handle_set_logging_level(level: str) -> None:
"""Handle logging level changes"""
logger.info(f"Log level set to: {level}")
@@ -413,8 +413,8 @@ async def handle_unsubscribe(uri: str) -> None:
logger.info(f"Unsubscribed from resource: {uri}")
mcp._mcp_server.subscribe_resource()(handle_subscribe) # pyright: ignore[reportPrivateUsage]
mcp._mcp_server.unsubscribe_resource()(handle_unsubscribe) # pyright: ignore[reportPrivateUsage]
mcp._lowlevel_server.subscribe_resource()(handle_subscribe) # pyright: ignore[reportPrivateUsage]
mcp._lowlevel_server.unsubscribe_resource()(handle_unsubscribe) # pyright: ignore[reportPrivateUsage]
@mcp.completion()
@@ -19,7 +19,7 @@ from starlette.requests import Request
from starlette.responses import Response
from mcp.server.auth.settings import AuthSettings, ClientRegistrationOptions
from mcp.server.fastmcp.server import FastMCP
from mcp.server.mcpserver.server import MCPServer
from .simple_auth_provider import SimpleAuthSettings, SimpleOAuthProvider
@@ -43,8 +43,8 @@ class LegacySimpleOAuthProvider(SimpleOAuthProvider):
super().__init__(auth_settings, auth_callback_path, server_url)
def create_simple_mcp_server(server_settings: ServerSettings, auth_settings: SimpleAuthSettings) -> FastMCP:
"""Create a simple FastMCP server with simple authentication."""
def create_simple_mcp_server(server_settings: ServerSettings, auth_settings: SimpleAuthSettings) -> MCPServer:
"""Create a simple MCPServer server with simple authentication."""
oauth_provider = LegacySimpleOAuthProvider(
auth_settings, server_settings.auth_callback_path, str(server_settings.server_url)
)
@@ -61,7 +61,7 @@ def create_simple_mcp_server(server_settings: ServerSettings, auth_settings: Sim
resource_server_url=None,
)
app = FastMCP(
app = MCPServer(
name="Simple Auth MCP Server",
instructions="A simple MCP server with simple credential authentication",
auth_server_provider=oauth_provider,
@@ -16,7 +16,7 @@ from pydantic import AnyHttpUrl
from pydantic_settings import BaseSettings, SettingsConfigDict
from mcp.server.auth.settings import AuthSettings
from mcp.server.fastmcp.server import FastMCP
from mcp.server.mcpserver.server import MCPServer
from .token_verifier import IntrospectionTokenVerifier
@@ -45,7 +45,7 @@ class ResourceServerSettings(BaseSettings):
oauth_strict: bool = False
def create_resource_server(settings: ResourceServerSettings) -> FastMCP:
def create_resource_server(settings: ResourceServerSettings) -> MCPServer:
"""Create MCP Resource Server with token introspection.
This server:
@@ -60,8 +60,8 @@ def create_resource_server(settings: ResourceServerSettings) -> FastMCP:
validate_resource=settings.oauth_strict, # Only validate when --oauth-strict is set
)
# Create FastMCP server as a Resource Server
app = FastMCP(
# Create MCPServer server as a Resource Server
app = MCPServer(
name="MCP Resource Server",
instructions="Resource Server that validates tokens via Authorization Server introspection",
debug=True,
@@ -12,7 +12,7 @@ from mcp.shared.metadata_utils import get_display_name
# Create server parameters for stdio connection
server_params = StdioServerParameters(
command="uv", # Using uv to run the server
args=["run", "server", "fastmcp_quickstart", "stdio"],
args=["run", "server", "mcpserver_quickstart", "stdio"],
env={"UV_INDEX": os.environ.get("UV_INDEX", "")},
)
+4 -4
View File
@@ -12,7 +12,7 @@ from mcp.shared.context import RequestContext
# Create server parameters for stdio connection
server_params = StdioServerParameters(
command="uv", # Using uv to run the server
args=["run", "server", "fastmcp_quickstart", "stdio"], # We're already in snippets dir
args=["run", "server", "mcpserver_quickstart", "stdio"], # We're already in snippets dir
env={"UV_INDEX": os.environ.get("UV_INDEX", "")},
)
@@ -43,7 +43,7 @@ async def run():
prompts = await session.list_prompts()
print(f"Available prompts: {[p.name for p in prompts.prompts]}")
# Get a prompt (greet_user prompt from fastmcp_quickstart)
# Get a prompt (greet_user prompt from mcpserver_quickstart)
if prompts.prompts:
prompt = await session.get_prompt("greet_user", arguments={"name": "Alice", "style": "friendly"})
print(f"Prompt result: {prompt.messages[0].content}")
@@ -56,13 +56,13 @@ async def run():
tools = await session.list_tools()
print(f"Available tools: {[t.name for t in tools.tools]}")
# Read a resource (greeting resource from fastmcp_quickstart)
# Read a resource (greeting resource from mcpserver_quickstart)
resource_content = await session.read_resource("greeting://World")
content_block = resource_content.contents[0]
if isinstance(content_block, types.TextContent):
print(f"Resource content: {content_block.text}")
# Call a tool (add tool from fastmcp_quickstart)
# Call a tool (add tool from mcpserver_quickstart)
result = await session.call_tool("add", arguments={"a": 5, "b": 3})
result_unstructured = result.content[0]
if isinstance(result_unstructured, types.TextContent):
+1 -1
View File
@@ -22,7 +22,7 @@ def run_server():
print("Usage: server <server-name> [transport]")
print("Available servers: basic_tool, basic_resource, basic_prompt, tool_progress,")
print(" sampling, elicitation, completion, notifications,")
print(" fastmcp_quickstart, structured_output, images")
print(" mcpserver_quickstart, structured_output, images")
print("Available transports: stdio (default), sse, streamable-http")
sys.exit(1)
+3 -3
View File
@@ -1,7 +1,7 @@
from mcp.server.fastmcp import FastMCP
from mcp.server.fastmcp.prompts import base
from mcp.server.mcpserver import MCPServer
from mcp.server.mcpserver.prompts import base
mcp = FastMCP(name="Prompt Example")
mcp = MCPServer(name="Prompt Example")
@mcp.prompt(title="Code Review")
+2 -2
View File
@@ -1,6 +1,6 @@
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
mcp = FastMCP(name="Resource Example")
mcp = MCPServer(name="Resource Example")
@mcp.resource("file://documents/{name}")
+2 -2
View File
@@ -1,6 +1,6 @@
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
mcp = FastMCP(name="Tool Example")
mcp = MCPServer(name="Tool Example")
@mcp.tool()
+2 -2
View File
@@ -1,4 +1,4 @@
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
from mcp.types import (
Completion,
CompletionArgument,
@@ -7,7 +7,7 @@ from mcp.types import (
ResourceTemplateReference,
)
mcp = FastMCP(name="Example")
mcp = MCPServer(name="Example")
@mcp.resource("github://repos/{owner}/{repo}")
@@ -4,10 +4,10 @@ from typing import Annotated
from pydantic import BaseModel
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
from mcp.types import CallToolResult, TextContent
mcp = FastMCP("CallToolResult Example")
mcp = MCPServer("CallToolResult Example")
class ValidationModel(BaseModel):
@@ -7,9 +7,9 @@ cd to the `examples/snippets` directory and run:
python servers/direct_execution.py
"""
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
mcp = FastMCP("My App")
mcp = MCPServer("My App")
@mcp.tool()
+2 -2
View File
@@ -9,12 +9,12 @@ import uuid
from pydantic import BaseModel, Field
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.mcpserver import Context, MCPServer
from mcp.server.session import ServerSession
from mcp.shared.exceptions import UrlElicitationRequiredError
from mcp.types import ElicitRequestURLParams
mcp = FastMCP(name="Elicitation Example")
mcp = MCPServer(name="Elicitation Example")
class BookingPreferences(BaseModel):
+3 -3
View File
@@ -1,10 +1,10 @@
"""Example showing image handling with FastMCP."""
"""Example showing image handling with MCPServer."""
from PIL import Image as PILImage
from mcp.server.fastmcp import FastMCP, Image
from mcp.server.mcpserver import Image, MCPServer
mcp = FastMCP("Image Example")
mcp = MCPServer("Image Example")
@mcp.tool()
@@ -4,7 +4,7 @@ from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from dataclasses import dataclass
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.mcpserver import Context, MCPServer
from mcp.server.session import ServerSession
@@ -34,7 +34,7 @@ class AppContext:
@asynccontextmanager
async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
async def app_lifespan(server: MCPServer) -> AsyncIterator[AppContext]:
"""Manage application lifecycle with type-safe context."""
# Initialize on startup
db = await Database.connect()
@@ -46,7 +46,7 @@ async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
# Pass lifespan to server
mcp = FastMCP("My App", lifespan=app_lifespan)
mcp = MCPServer("My App", lifespan=app_lifespan)
# Access type-safe lifespan context in tools
@@ -1,13 +1,13 @@
"""FastMCP quickstart example.
"""MCPServer quickstart example.
Run from the repository root:
uv run examples/snippets/servers/fastmcp_quickstart.py
uv run examples/snippets/servers/mcpserver_quickstart.py
"""
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create an MCP server
mcp = FastMCP("Demo")
mcp = MCPServer("Demo")
# Add an addition tool
+2 -2
View File
@@ -1,7 +1,7 @@
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.mcpserver import Context, MCPServer
from mcp.server.session import ServerSession
mcp = FastMCP(name="Notifications Example")
mcp = MCPServer(name="Notifications Example")
@mcp.tool()
+3 -3
View File
@@ -6,7 +6,7 @@ from pydantic import AnyHttpUrl
from mcp.server.auth.provider import AccessToken, TokenVerifier
from mcp.server.auth.settings import AuthSettings
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
class SimpleTokenVerifier(TokenVerifier):
@@ -16,8 +16,8 @@ class SimpleTokenVerifier(TokenVerifier):
pass # This is where you would implement actual token validation
# Create FastMCP instance as a Resource Server
mcp = FastMCP(
# Create MCPServer instance as a Resource Server
mcp = MCPServer(
"Weather Service",
# Token verifier for authentication
token_verifier=SimpleTokenVerifier(),
+2 -2
View File
@@ -1,8 +1,8 @@
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.mcpserver import Context, MCPServer
from mcp.server.session import ServerSession
from mcp.types import SamplingMessage, TextContent
mcp = FastMCP(name="Sampling Example")
mcp = MCPServer(name="Sampling Example")
@mcp.tool()
@@ -2,9 +2,9 @@
uv run examples/snippets/servers/streamable_config.py
"""
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
mcp = FastMCP("StatelessServer")
mcp = MCPServer("StatelessServer")
# Add a simple tool to demonstrate the server
@@ -9,10 +9,10 @@ import contextlib
from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create MCP server
mcp = FastMCP("My App")
mcp = MCPServer("My App")
@mcp.tool()
@@ -9,10 +9,10 @@ import contextlib
from starlette.applications import Starlette
from starlette.routing import Host
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create MCP server
mcp = FastMCP("MCP Host App")
mcp = MCPServer("MCP Host App")
@mcp.tool()
@@ -9,11 +9,11 @@ import contextlib
from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create multiple MCP servers
api_mcp = FastMCP("API Server")
chat_mcp = FastMCP("Chat Server")
api_mcp = MCPServer("API Server")
chat_mcp = MCPServer("Chat Server")
@api_mcp.tool()
@@ -1,4 +1,4 @@
"""Example showing path configuration when mounting FastMCP.
"""Example showing path configuration when mounting MCPServer.
Run from the repository root:
uvicorn examples.snippets.servers.streamable_http_path_config:app --reload
@@ -7,10 +7,10 @@ Run from the repository root:
from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create a simple FastMCP server
mcp_at_root = FastMCP("My Server")
# Create a simple MCPServer server
mcp_at_root = MCPServer("My Server")
@mcp_at_root.tool()
@@ -7,10 +7,10 @@ import contextlib
from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
# Create the Echo server
echo_mcp = FastMCP(name="EchoServer")
echo_mcp = MCPServer(name="EchoServer")
@echo_mcp.tool()
@@ -20,7 +20,7 @@ def echo(message: str) -> str:
# Create the Math server
math_mcp = FastMCP(name="MathServer")
math_mcp = MCPServer(name="MathServer")
@math_mcp.tool()
@@ -4,9 +4,9 @@ from typing import TypedDict
from pydantic import BaseModel, Field
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
mcp = FastMCP("Structured Output Example")
mcp = MCPServer("Structured Output Example")
# Using Pydantic models for rich structured data
+2 -2
View File
@@ -1,7 +1,7 @@
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.mcpserver import Context, MCPServer
from mcp.server.session import ServerSession
mcp = FastMCP(name="Progress Example")
mcp = MCPServer(name="Progress Example")
@mcp.tool()
+5 -1
View File
@@ -149,7 +149,7 @@ max-complexity = 24 # Default is 10
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]
"tests/server/fastmcp/test_func_metadata.py" = ["E501"]
"tests/server/mcpserver/test_func_metadata.py" = ["E501"]
"tests/shared/test_progress_notifications.py" = ["PLW0603"]
[tool.ruff.lint.pylint]
@@ -230,3 +230,7 @@ source = [
"/home/runner/work/python-sdk/python-sdk/src/",
'D:\a\python-sdk\python-sdk\src',
]
[tool.inline-snapshot]
default-flags = ["disable"]
format-command = "ruff format --stdin-filename {filename}"
+1 -1
View File
@@ -1,4 +1,4 @@
"""FastMCP CLI package."""
"""MCP CLI package."""
from .cli import app
+3 -3
View File
@@ -7,7 +7,7 @@ import sys
from pathlib import Path
from typing import Any
from mcp.server.fastmcp.utilities.logging import get_logger
from mcp.server.mcpserver.utilities.logging import get_logger
logger = get_logger(__name__)
@@ -49,7 +49,7 @@ def update_claude_config(
with_packages: list[str] | None = None,
env_vars: dict[str, str] | None = None,
) -> bool:
"""Add or update a FastMCP server in Claude's configuration.
"""Add or update an MCP server in Claude's configuration.
Args:
file_spec: Path to the server file, optionally with :object suffix
@@ -121,7 +121,7 @@ def update_claude_config(
else: # pragma: no cover
file_spec = str(Path(file_spec).resolve())
# Add fastmcp run command
# Add mcp run command
args.extend(["mcp", "run", file_spec])
server_config: dict[str, Any] = {"command": uv_path, "args": args}
+8 -10
View File
@@ -8,7 +8,7 @@ import sys
from pathlib import Path
from typing import Annotated, Any
from mcp.server import FastMCP
from mcp.server import MCPServer
from mcp.server import Server as LowLevelServer
try:
@@ -19,9 +19,9 @@ except ImportError: # pragma: no cover
try:
from mcp.cli import claude
from mcp.server.fastmcp.utilities.logging import get_logger
from mcp.server.mcpserver.utilities.logging import get_logger
except ImportError: # pragma: no cover
print("Error: mcp.server.fastmcp is not installed or not in PYTHONPATH")
print("Error: mcp.server is not installed or not in PYTHONPATH")
sys.exit(1)
try:
@@ -149,12 +149,10 @@ def _import_server(file: Path, server_object: str | None = None): # pragma: no
Returns:
True if it's supported.
"""
if not isinstance(server_object, FastMCP):
logger.error(f"The server object {object_name} is of type {type(server_object)} (expecting {FastMCP}).")
if not isinstance(server_object, MCPServer):
logger.error(f"The server object {object_name} is of type {type(server_object)} (expecting {MCPServer}).")
if isinstance(server_object, LowLevelServer):
logger.warning(
"Note that only FastMCP server is supported. Low level Server class is not yet supported."
)
logger.warning("Note that only MCPServer is supported. Low level Server class is not yet supported.")
return False
return True
@@ -172,8 +170,8 @@ def _import_server(file: Path, server_object: str | None = None): # pragma: no
f"No server object found in {file}. Please either:\n"
"1. Use a standard variable name (mcp, server, or app)\n"
"2. Specify the object name with file:object syntax"
"3. If the server creates the FastMCP object within main() "
" or another function, refactor the FastMCP object to be a "
"3. If the server creates the MCPServer object within main() "
" or another function, refactor the MCPServer object to be a "
" global variable named mcp, server, or app.",
extra={"file": str(file)},
)
+7 -7
View File
@@ -10,7 +10,7 @@ import anyio
from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
from mcp.server import Server
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
from mcp.shared.memory import create_client_server_memory_streams
from mcp.shared.message import SessionMessage
@@ -23,7 +23,7 @@ class InMemoryTransport:
stopped when the context manager exits.
Example:
server = FastMCP("test")
server = MCPServer("test")
transport = InMemoryTransport(server)
async with transport.connect() as (read_stream, write_stream):
@@ -36,11 +36,11 @@ class InMemoryTransport:
result = await client.call_tool("my_tool", {...})
"""
def __init__(self, server: Server[Any] | FastMCP, *, raise_exceptions: bool = False) -> None:
def __init__(self, server: Server[Any] | MCPServer, *, raise_exceptions: bool = False) -> None:
"""Initialize the in-memory transport.
Args:
server: The MCP server to connect to (Server or FastMCP instance)
server: The MCP server to connect to (Server or MCPServer instance)
raise_exceptions: Whether to raise exceptions from the server
"""
self._server = server
@@ -61,10 +61,10 @@ class InMemoryTransport:
Yields:
A tuple of (read_stream, write_stream) for bidirectional communication
"""
# Unwrap FastMCP to get underlying Server
# Unwrap MCPServer to get underlying Server
actual_server: Server[Any]
if isinstance(self._server, FastMCP):
actual_server = self._server._mcp_server # type: ignore[reportPrivateUsage]
if isinstance(self._server, MCPServer):
actual_server = self._server._lowlevel_server # type: ignore[reportPrivateUsage]
else:
actual_server = self._server
+7 -7
View File
@@ -8,7 +8,7 @@ from typing import Any
from mcp.client._memory import InMemoryTransport
from mcp.client.session import ClientSession, ElicitationFnT, ListRootsFnT, LoggingFnT, MessageHandlerFnT, SamplingFnT
from mcp.server import Server
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
from mcp.shared.session import ProgressFnT
from mcp.types import (
CallToolResult,
@@ -34,14 +34,14 @@ class Client:
"""A high-level MCP client for connecting to MCP servers.
Currently supports in-memory transport for testing. Pass a Server or
FastMCP instance directly to the constructor.
MCPServer instance directly to the constructor.
Example:
```python
from mcp.client import Client
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
server = FastMCP("test")
server = MCPServer("test")
@server.tool()
def add(a: int, b: int) -> int:
@@ -55,7 +55,7 @@ class Client:
```
"""
# TODO(felixweinberger): Expand to support all transport types (like FastMCP 2):
# TODO(felixweinberger): Expand to support all transport types:
# - Add ClientTransport base class with connect_session() method
# - Add StreamableHttpTransport, SSETransport, StdioTransport
# - Add infer_transport() to auto-detect transport from input type
@@ -64,7 +64,7 @@ class Client:
def __init__(
self,
server: Server[Any] | FastMCP,
server: Server[Any] | MCPServer,
*,
# TODO(Marcelo): When do `raise_exceptions=True` actually raises?
raise_exceptions: bool = False,
@@ -79,7 +79,7 @@ class Client:
"""Initialize the client with a server.
Args:
server: The MCP server to connect to (Server or FastMCP instance)
server: The MCP server to connect to (Server or MCPServer instance)
raise_exceptions: Whether to raise exceptions from the server
read_timeout_seconds: Timeout for read operations
sampling_callback: Callback for handling sampling requests
+4 -4
View File
@@ -15,7 +15,7 @@ from typing import Any, TypeAlias
import anyio
import httpx
from pydantic import BaseModel
from pydantic import BaseModel, Field
from typing_extensions import Self
import mcp
@@ -103,9 +103,9 @@ class ClientSessionGroup:
class _ComponentNames(BaseModel):
"""Used for reverse index to find components."""
prompts: set[str] = set()
resources: set[str] = set()
tools: set[str] = set()
prompts: set[str] = Field(default_factory=set)
resources: set[str] = Field(default_factory=set)
tools: set[str] = Field(default_factory=set)
# Standard MCP components.
_prompts: dict[str, types.Prompt]
+2 -2
View File
@@ -1,5 +1,5 @@
from .fastmcp import FastMCP
from .lowlevel import NotificationOptions, Server
from .mcpserver import MCPServer
from .models import InitializationOptions
__all__ = ["Server", "FastMCP", "NotificationOptions", "InitializationOptions"]
__all__ = ["Server", "MCPServer", "NotificationOptions", "InitializationOptions"]
+1 -1
View File
@@ -96,7 +96,7 @@ class TokenVerifier(Protocol):
"""Verify a bearer token and return access info if valid."""
# NOTE: FastMCP doesn't render any of these types in the user response, so it's
# NOTE: MCPServer doesn't render any of these types in the user response, so it's
# OK to add fields to subclasses which should not be exposed externally.
AuthorizationCodeT = TypeVar("AuthorizationCodeT", bound=AuthorizationCode)
RefreshTokenT = TypeVar("RefreshTokenT", bound=RefreshToken)
-8
View File
@@ -1,8 +0,0 @@
"""FastMCP - A more ergonomic interface for MCP servers."""
from mcp.types import Icon
from .server import Context, FastMCP
from .utilities.types import Audio, Image
__all__ = ["FastMCP", "Context", "Image", "Audio", "Icon"]
-21
View File
@@ -1,21 +0,0 @@
"""Custom exceptions for FastMCP."""
class FastMCPError(Exception):
"""Base error for FastMCP."""
class ValidationError(FastMCPError):
"""Error in validating parameters or return values."""
class ResourceError(FastMCPError):
"""Error in resource operations."""
class ToolError(FastMCPError):
"""Error in tool operations."""
class InvalidSignature(Exception):
"""Invalid signature for use with FastMCP."""
@@ -1 +0,0 @@
"""FastMCP utility modules."""
+8
View File
@@ -0,0 +1,8 @@
"""MCPServer - A more ergonomic interface for MCP servers."""
from mcp.types import Icon
from .server import Context, MCPServer
from .utilities.types import Audio, Image
__all__ = ["MCPServer", "Context", "Image", "Audio", "Icon"]
+21
View File
@@ -0,0 +1,21 @@
"""Custom exceptions for MCPServer."""
class MCPServerError(Exception):
"""Base error for MCPServer."""
class ValidationError(MCPServerError):
"""Error in validating parameters or return values."""
class ResourceError(MCPServerError):
"""Error in resource operations."""
class ToolError(MCPServerError):
"""Error in tool operations."""
class InvalidSignature(Exception):
"""Invalid signature for use with MCPServer."""
@@ -1,4 +1,4 @@
"""Base classes for FastMCP prompts."""
"""Base classes for MCPServer prompts."""
from __future__ import annotations
@@ -9,12 +9,12 @@ from typing import TYPE_CHECKING, Any, Literal
import pydantic_core
from pydantic import BaseModel, Field, TypeAdapter, validate_call
from mcp.server.fastmcp.utilities.context_injection import find_context_parameter, inject_context
from mcp.server.fastmcp.utilities.func_metadata import func_metadata
from mcp.server.mcpserver.utilities.context_injection import find_context_parameter, inject_context
from mcp.server.mcpserver.utilities.func_metadata import func_metadata
from mcp.types import ContentBlock, Icon, TextContent
if TYPE_CHECKING:
from mcp.server.fastmcp.server import Context
from mcp.server.mcpserver.server import Context
from mcp.server.session import ServerSessionT
from mcp.shared.context import LifespanContextT, RequestT
@@ -4,11 +4,11 @@ from __future__ import annotations
from typing import TYPE_CHECKING, Any
from mcp.server.fastmcp.prompts.base import Message, Prompt
from mcp.server.fastmcp.utilities.logging import get_logger
from mcp.server.mcpserver.prompts.base import Message, Prompt
from mcp.server.mcpserver.utilities.logging import get_logger
if TYPE_CHECKING:
from mcp.server.fastmcp.server import Context
from mcp.server.mcpserver.server import Context
from mcp.server.session import ServerSessionT
from mcp.shared.context import LifespanContextT, RequestT
@@ -16,7 +16,7 @@ logger = get_logger(__name__)
class PromptManager:
"""Manages FastMCP prompts."""
"""Manages MCPServer prompts."""
def __init__(self, warn_on_duplicate_prompts: bool = True):
self._prompts: dict[str, Prompt] = {}
@@ -1,4 +1,4 @@
"""Base classes and interfaces for FastMCP resources."""
"""Base classes and interfaces for MCPServer resources."""
import abc
from typing import Any
@@ -7,13 +7,13 @@ from typing import TYPE_CHECKING, Any
from pydantic import AnyUrl
from mcp.server.fastmcp.resources.base import Resource
from mcp.server.fastmcp.resources.templates import ResourceTemplate
from mcp.server.fastmcp.utilities.logging import get_logger
from mcp.server.mcpserver.resources.base import Resource
from mcp.server.mcpserver.resources.templates import ResourceTemplate
from mcp.server.mcpserver.utilities.logging import get_logger
from mcp.types import Annotations, Icon
if TYPE_CHECKING:
from mcp.server.fastmcp.server import Context
from mcp.server.mcpserver.server import Context
from mcp.server.session import ServerSessionT
from mcp.shared.context import LifespanContextT, RequestT
@@ -21,7 +21,7 @@ logger = get_logger(__name__)
class ResourceManager:
"""Manages FastMCP resources."""
"""Manages MCPServer resources."""
def __init__(self, warn_on_duplicate_resources: bool = True):
self._resources: dict[str, Resource] = {}
@@ -10,13 +10,13 @@ from urllib.parse import unquote
from pydantic import BaseModel, Field, validate_call
from mcp.server.fastmcp.resources.types import FunctionResource, Resource
from mcp.server.fastmcp.utilities.context_injection import find_context_parameter, inject_context
from mcp.server.fastmcp.utilities.func_metadata import func_metadata
from mcp.server.mcpserver.resources.types import FunctionResource, Resource
from mcp.server.mcpserver.utilities.context_injection import find_context_parameter, inject_context
from mcp.server.mcpserver.utilities.func_metadata import func_metadata
from mcp.types import Annotations, Icon
if TYPE_CHECKING:
from mcp.server.fastmcp.server import Context
from mcp.server.mcpserver.server import Context
from mcp.server.session import ServerSessionT
from mcp.shared.context import LifespanContextT, RequestT
@@ -13,7 +13,7 @@ import pydantic
import pydantic_core
from pydantic import Field, ValidationInfo, validate_call
from mcp.server.fastmcp.resources.base import Resource
from mcp.server.mcpserver.resources.base import Resource
from mcp.types import Annotations, Icon
@@ -1,4 +1,4 @@
"""FastMCP - A more ergonomic interface for MCP servers."""
"""MCPServer - A more ergonomic interface for MCP servers."""
from __future__ import annotations
@@ -27,16 +27,15 @@ from mcp.server.auth.provider import OAuthAuthorizationServerProvider, ProviderT
from mcp.server.auth.settings import AuthSettings
from mcp.server.elicitation import ElicitationResult, ElicitSchemaModelT, UrlElicitationResult, elicit_with_validation
from mcp.server.elicitation import elicit_url as _elicit_url
from mcp.server.fastmcp.exceptions import ResourceError
from mcp.server.fastmcp.prompts import Prompt, PromptManager
from mcp.server.fastmcp.resources import FunctionResource, Resource, ResourceManager
from mcp.server.fastmcp.tools import Tool, ToolManager
from mcp.server.fastmcp.utilities.context_injection import find_context_parameter
from mcp.server.fastmcp.utilities.logging import configure_logging, get_logger
from mcp.server.lowlevel.helper_types import ReadResourceContents
from mcp.server.lowlevel.server import LifespanResultT
from mcp.server.lowlevel.server import Server as MCPServer
from mcp.server.lowlevel.server import LifespanResultT, Server
from mcp.server.lowlevel.server import lifespan as default_lifespan
from mcp.server.mcpserver.exceptions import ResourceError
from mcp.server.mcpserver.prompts import Prompt, PromptManager
from mcp.server.mcpserver.resources import FunctionResource, Resource, ResourceManager
from mcp.server.mcpserver.tools import Tool, ToolManager
from mcp.server.mcpserver.utilities.context_injection import find_context_parameter
from mcp.server.mcpserver.utilities.logging import configure_logging, get_logger
from mcp.server.session import ServerSession, ServerSessionT
from mcp.server.sse import SseServerTransport
from mcp.server.stdio import stdio_server
@@ -57,14 +56,14 @@ _CallableT = TypeVar("_CallableT", bound=Callable[..., Any])
class Settings(BaseSettings, Generic[LifespanResultT]):
"""FastMCP server settings.
"""MCPServer settings.
All settings can be configured via environment variables with the prefix FASTMCP_.
For example, FASTMCP_DEBUG=true will set debug=True.
All settings can be configured via environment variables with the prefix MCP_.
For example, MCP_DEBUG=true will set debug=True.
"""
model_config = SettingsConfigDict(
env_prefix="FASTMCP_",
env_prefix="MCP_",
env_file=".env",
env_nested_delimiter="__",
nested_model_default_partial_update=True,
@@ -84,27 +83,25 @@ class Settings(BaseSettings, Generic[LifespanResultT]):
# prompt settings
warn_on_duplicate_prompts: bool
lifespan: Callable[[FastMCP[LifespanResultT]], AbstractAsyncContextManager[LifespanResultT]] | None
lifespan: Callable[[MCPServer[LifespanResultT]], AbstractAsyncContextManager[LifespanResultT]] | None
"""A async context manager that will be called when the server is started."""
auth: AuthSettings | None
def lifespan_wrapper(
app: FastMCP[LifespanResultT],
lifespan: Callable[[FastMCP[LifespanResultT]], AbstractAsyncContextManager[LifespanResultT]],
) -> Callable[[MCPServer[LifespanResultT, Request]], AbstractAsyncContextManager[LifespanResultT]]:
app: MCPServer[LifespanResultT],
lifespan: Callable[[MCPServer[LifespanResultT]], AbstractAsyncContextManager[LifespanResultT]],
) -> Callable[[Server[LifespanResultT, Request]], AbstractAsyncContextManager[LifespanResultT]]:
@asynccontextmanager
async def wrap(
_: MCPServer[LifespanResultT, Request],
) -> AsyncIterator[LifespanResultT]:
async def wrap(_: Server[LifespanResultT, Request]) -> AsyncIterator[LifespanResultT]:
async with lifespan(app) as context:
yield context
return wrap
class FastMCP(Generic[LifespanResultT]):
class MCPServer(Generic[LifespanResultT]):
def __init__(
self,
name: str | None = None,
@@ -123,7 +120,7 @@ class FastMCP(Generic[LifespanResultT]):
warn_on_duplicate_resources: bool = True,
warn_on_duplicate_tools: bool = True,
warn_on_duplicate_prompts: bool = True,
lifespan: Callable[[FastMCP[LifespanResultT]], AbstractAsyncContextManager[LifespanResultT]] | None = None,
lifespan: Callable[[MCPServer[LifespanResultT]], AbstractAsyncContextManager[LifespanResultT]] | None = None,
auth: AuthSettings | None = None,
):
self.settings = Settings(
@@ -136,15 +133,15 @@ class FastMCP(Generic[LifespanResultT]):
auth=auth,
)
self._mcp_server = MCPServer(
name=name or "FastMCP",
self._lowlevel_server = Server(
name=name or "mcp-server",
title=title,
description=description,
instructions=instructions,
website_url=website_url,
icons=icons,
version=version,
# TODO(Marcelo): It seems there's a type mismatch between the lifespan type from an FastMCP and Server.
# TODO(Marcelo): It seems there's a type mismatch between the lifespan type from an MCPServer and Server.
# We need to create a Lifespan type that is a generic on the server type, like Starlette does.
lifespan=(lifespan_wrapper(self, self.settings.lifespan) if self.settings.lifespan else default_lifespan), # type: ignore
)
@@ -176,43 +173,43 @@ class FastMCP(Generic[LifespanResultT]):
@property
def name(self) -> str:
return self._mcp_server.name
return self._lowlevel_server.name
@property
def title(self) -> str | None:
return self._mcp_server.title
return self._lowlevel_server.title
@property
def description(self) -> str | None:
return self._mcp_server.description
return self._lowlevel_server.description
@property
def instructions(self) -> str | None:
return self._mcp_server.instructions
return self._lowlevel_server.instructions
@property
def website_url(self) -> str | None:
return self._mcp_server.website_url
return self._lowlevel_server.website_url
@property
def icons(self) -> list[Icon] | None:
return self._mcp_server.icons
return self._lowlevel_server.icons
@property
def version(self) -> str | None:
return self._mcp_server.version
return self._lowlevel_server.version
@property
def session_manager(self) -> StreamableHTTPSessionManager:
"""Get the StreamableHTTP session manager.
This is exposed to enable advanced use cases like mounting multiple
FastMCP servers in a single FastAPI application.
MCPServer instances in a single FastAPI application.
Raises:
RuntimeError: If called before streamable_http_app() has been called.
"""
return self._mcp_server.session_manager # pragma: no cover
return self._lowlevel_server.session_manager # pragma: no cover
@overload
def run(self, transport: Literal["stdio"] = ...) -> None: ...
@@ -249,7 +246,7 @@ class FastMCP(Generic[LifespanResultT]):
transport: Literal["stdio", "sse", "streamable-http"] = "stdio",
**kwargs: Any,
) -> None:
"""Run the FastMCP server. Note this is a synchronous function.
"""Run the MCP server. Note this is a synchronous function.
Args:
transport: Transport protocol to use ("stdio", "sse", or "streamable-http")
@@ -269,16 +266,16 @@ class FastMCP(Generic[LifespanResultT]):
def _setup_handlers(self) -> None:
"""Set up core MCP protocol handlers."""
self._mcp_server.list_tools()(self.list_tools)
self._lowlevel_server.list_tools()(self.list_tools)
# Note: we disable the lowlevel server's input validation.
# FastMCP does ad hoc conversion of incoming data before validating -
# MCPServer does ad hoc conversion of incoming data before validating -
# for now we preserve this for backwards compatibility.
self._mcp_server.call_tool(validate_input=False)(self.call_tool)
self._mcp_server.list_resources()(self.list_resources)
self._mcp_server.read_resource()(self.read_resource)
self._mcp_server.list_prompts()(self.list_prompts)
self._mcp_server.get_prompt()(self.get_prompt)
self._mcp_server.list_resource_templates()(self.list_resource_templates)
self._lowlevel_server.call_tool(validate_input=False)(self.call_tool)
self._lowlevel_server.list_resources()(self.list_resources)
self._lowlevel_server.read_resource()(self.read_resource)
self._lowlevel_server.list_prompts()(self.list_prompts)
self._lowlevel_server.get_prompt()(self.get_prompt)
self._lowlevel_server.list_resource_templates()(self.list_resource_templates)
async def list_tools(self) -> list[MCPTool]:
"""List all available tools."""
@@ -302,10 +299,10 @@ class FastMCP(Generic[LifespanResultT]):
during a request; outside a request, most methods will error.
"""
try:
request_context = self._mcp_server.request_context
request_context = self._lowlevel_server.request_context
except LookupError:
request_context = None
return Context(request_context=request_context, fastmcp=self)
return Context(request_context=request_context, mcp_server=self)
async def call_tool(self, name: str, arguments: dict[str, Any]) -> Sequence[ContentBlock] | dict[str, Any]:
"""Call a tool by name with arguments."""
@@ -488,7 +485,7 @@ class FastMCP(Generic[LifespanResultT]):
return Completion(values=["option1", "option2"])
return None
"""
return self._mcp_server.completion()
return self._lowlevel_server.completion()
def add_resource(self, resource: Resource) -> None:
"""Add a resource to the server.
@@ -676,7 +673,7 @@ class FastMCP(Generic[LifespanResultT]):
name: str | None = None,
include_in_schema: bool = True,
):
"""Decorator to register a custom HTTP route on the FastMCP server.
"""Decorator to register a custom HTTP route on the MCP server.
Allows adding arbitrary HTTP endpoints outside the standard MCP protocol,
which can be useful for OAuth callbacks, health checks, or admin APIs.
@@ -704,13 +701,7 @@ class FastMCP(Generic[LifespanResultT]):
func: Callable[[Request], Awaitable[Response]],
) -> Callable[[Request], Awaitable[Response]]:
self._custom_starlette_routes.append(
Route(
path,
endpoint=func,
methods=methods,
name=name,
include_in_schema=include_in_schema,
)
Route(path, endpoint=func, methods=methods, name=name, include_in_schema=include_in_schema)
)
return func
@@ -719,10 +710,10 @@ class FastMCP(Generic[LifespanResultT]):
async def run_stdio_async(self) -> None:
"""Run the server using stdio transport."""
async with stdio_server() as (read_stream, write_stream):
await self._mcp_server.run(
await self._lowlevel_server.run(
read_stream,
write_stream,
self._mcp_server.create_initialization_options(),
self._lowlevel_server.create_initialization_options(),
)
async def run_sse_async( # pragma: no cover
@@ -810,7 +801,9 @@ class FastMCP(Generic[LifespanResultT]):
# Add client ID from auth context into request context if available
async with sse.connect_sse(scope, receive, send) as streams:
await self._mcp_server.run(streams[0], streams[1], self._mcp_server.create_initialization_options())
await self._lowlevel_server.run(
streams[0], streams[1], self._lowlevel_server.create_initialization_options()
)
return Response()
# Create routes
@@ -923,7 +916,7 @@ class FastMCP(Generic[LifespanResultT]):
host: str = "127.0.0.1",
) -> Starlette:
"""Return an instance of the StreamableHTTP server app."""
return self._mcp_server.streamable_http_app(
return self._lowlevel_server.streamable_http_app(
streamable_http_path=streamable_http_path,
json_response=json_response,
stateless_http=stateless_http,
@@ -1012,25 +1005,25 @@ class Context(BaseModel, Generic[ServerSessionT, LifespanContextT, RequestT]):
"""
_request_context: RequestContext[ServerSessionT, LifespanContextT, RequestT] | None
_fastmcp: FastMCP | None
_mcp_server: MCPServer | None
def __init__(
self,
*,
request_context: (RequestContext[ServerSessionT, LifespanContextT, RequestT] | None) = None,
fastmcp: FastMCP | None = None,
mcp_server: MCPServer | None = None,
**kwargs: Any,
):
super().__init__(**kwargs)
self._request_context = request_context
self._fastmcp = fastmcp
self._mcp_server = mcp_server
@property
def fastmcp(self) -> FastMCP:
"""Access to the FastMCP server."""
if self._fastmcp is None: # pragma: no cover
def mcp_server(self) -> MCPServer:
"""Access to the MCPServer instance."""
if self._mcp_server is None: # pragma: no cover
raise ValueError("Context is not available outside of a request")
return self._fastmcp # pragma: no cover
return self._mcp_server # pragma: no cover
@property
def request_context(
@@ -1070,8 +1063,8 @@ class Context(BaseModel, Generic[ServerSessionT, LifespanContextT, RequestT]):
Returns:
The resource content as either text or bytes
"""
assert self._fastmcp is not None, "Context is not available outside of a request"
return await self._fastmcp.read_resource(uri)
assert self._mcp_server is not None, "Context is not available outside of a request"
return await self._mcp_server.read_resource(uri)
async def elicit(
self,
@@ -8,15 +8,15 @@ from typing import TYPE_CHECKING, Any
from pydantic import BaseModel, Field
from mcp.server.fastmcp.exceptions import ToolError
from mcp.server.fastmcp.utilities.context_injection import find_context_parameter
from mcp.server.fastmcp.utilities.func_metadata import FuncMetadata, func_metadata
from mcp.server.mcpserver.exceptions import ToolError
from mcp.server.mcpserver.utilities.context_injection import find_context_parameter
from mcp.server.mcpserver.utilities.func_metadata import FuncMetadata, func_metadata
from mcp.shared.exceptions import UrlElicitationRequiredError
from mcp.shared.tool_name_validation import validate_and_warn_tool_name
from mcp.types import Icon, ToolAnnotations
if TYPE_CHECKING:
from mcp.server.fastmcp.server import Context
from mcp.server.mcpserver.server import Context
from mcp.server.session import ServerSessionT
from mcp.shared.context import LifespanContextT, RequestT
@@ -3,21 +3,21 @@ from __future__ import annotations
from collections.abc import Callable
from typing import TYPE_CHECKING, Any
from mcp.server.fastmcp.exceptions import ToolError
from mcp.server.fastmcp.tools.base import Tool
from mcp.server.fastmcp.utilities.logging import get_logger
from mcp.server.mcpserver.exceptions import ToolError
from mcp.server.mcpserver.tools.base import Tool
from mcp.server.mcpserver.utilities.logging import get_logger
from mcp.shared.context import LifespanContextT, RequestT
from mcp.types import Icon, ToolAnnotations
if TYPE_CHECKING:
from mcp.server.fastmcp.server import Context
from mcp.server.mcpserver.server import Context
from mcp.server.session import ServerSessionT
logger = get_logger(__name__)
class ToolManager:
"""Manages FastMCP tools."""
"""Manages MCPServer tools."""
def __init__(
self,
@@ -0,0 +1 @@
"""MCPServer utility modules."""
@@ -1,4 +1,4 @@
"""Context injection utilities for FastMCP."""
"""Context injection utilities for MCPServer."""
from __future__ import annotations
@@ -20,7 +20,7 @@ def find_context_parameter(fn: Callable[..., Any]) -> str | None:
Returns:
The name of the context parameter, or None if not found
"""
from mcp.server.fastmcp.server import Context
from mcp.server.mcpserver.server import Context
# Get type hints to properly resolve string annotations
try:
@@ -21,9 +21,9 @@ from typing_inspection.introspection import (
is_union_origin,
)
from mcp.server.fastmcp.exceptions import InvalidSignature
from mcp.server.fastmcp.utilities.logging import get_logger
from mcp.server.fastmcp.utilities.types import Audio, Image
from mcp.server.mcpserver.exceptions import InvalidSignature
from mcp.server.mcpserver.utilities.logging import get_logger
from mcp.server.mcpserver.utilities.types import Audio, Image
from mcp.types import CallToolResult, ContentBlock, TextContent
logger = get_logger(__name__)
@@ -98,8 +98,8 @@ class FuncMetadata(BaseModel):
Note: we return unstructured content here **even though the lowlevel server
tool call handler provides generic backwards compatibility serialization of
structured content**. This is for FastMCP backwards compatibility: we need to
retain FastMCP's ad hoc conversion logic for constructing unstructured output
structured content**. This is for MCPServer backwards compatibility: we need to
retain MCPServer's ad hoc conversion logic for constructing unstructured output
from function return values, whereas the lowlevel server simply serializes
the structured output.
"""
@@ -213,7 +213,7 @@ def func_metadata(
try:
sig = inspect.signature(func, eval_str=True)
except NameError as e: # pragma: no cover
# This raise could perhaps be skipped, and we (FastMCP) just call
# This raise could perhaps be skipped, and we (MCPServer) just call
# model_rebuild right before using it 🤷
raise InvalidSignature(f"Unable to evaluate type annotations for callable {func.__name__!r}") from e
params = sig.parameters
@@ -494,7 +494,7 @@ def _create_dict_model(func_name: str, dict_annotation: Any) -> type[BaseModel]:
def _convert_to_content(result: Any) -> Sequence[ContentBlock]:
"""Convert a result to a sequence of content objects.
Note: This conversion logic comes from previous versions of FastMCP and is being
Note: This conversion logic comes from previous versions of MCPServer and is being
retained for purposes of backwards compatibility. It produces different unstructured
output than the lowlevel server tool call handler, which just serializes structured
content verbatim.
@@ -1,14 +1,14 @@
"""Logging utilities for FastMCP."""
"""Logging utilities for MCPServer."""
import logging
from typing import Literal
def get_logger(name: str) -> logging.Logger:
"""Get a logger nested under MCPnamespace.
"""Get a logger nested under MCP namespace.
Args:
name: the name of the logger, which will be prefixed with 'FastMCP.'
name: the name of the logger
Returns:
a configured logger instance
@@ -1,4 +1,4 @@
"""Common types used across FastMCP."""
"""Common types used across MCPServer."""
import base64
from pathlib import Path
+1 -1
View File
@@ -22,7 +22,7 @@ class RequestContext(Generic[SessionT, LifespanContextT, RequestT]):
lifespan_context: LifespanContextT
# NOTE: This is typed as Any to avoid circular imports. The actual type is
# mcp.server.experimental.request_context.Experimental, but importing it here
# triggers mcp.server.__init__ -> fastmcp -> tools -> back to this module.
# triggers mcp.server.__init__ -> mcpserver -> tools -> back to this module.
# The Server sets this to an Experimental instance at runtime.
experimental: Any = field(default=None)
request: RequestT | None = None
+15 -15
View File
@@ -9,7 +9,7 @@ from inline_snapshot import snapshot
import mcp.types as types
from mcp.client.client import Client
from mcp.server import Server
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
from mcp.types import (
CallToolResult,
EmptyResult,
@@ -68,9 +68,9 @@ def simple_server() -> Server:
@pytest.fixture
def app() -> FastMCP:
"""Create a FastMCP server for testing."""
server = FastMCP("test")
def app() -> MCPServer:
"""Create an MCPServer server for testing."""
server = MCPServer("test")
@server.tool()
def greet(name: str) -> str:
@@ -90,7 +90,7 @@ def app() -> FastMCP:
return server
async def test_client_is_initialized(app: FastMCP):
async def test_client_is_initialized(app: MCPServer):
"""Test that the client is initialized after entering context."""
async with Client(app) as client:
assert client.server_capabilities == snapshot(
@@ -114,13 +114,13 @@ async def test_client_with_simple_server(simple_server: Server):
)
async def test_client_send_ping(app: FastMCP):
async def test_client_send_ping(app: MCPServer):
async with Client(app) as client:
result = await client.send_ping()
assert result == snapshot(EmptyResult())
async def test_client_list_tools(app: FastMCP):
async def test_client_list_tools(app: MCPServer):
async with Client(app) as client:
result = await client.list_tools()
assert result == snapshot(
@@ -147,7 +147,7 @@ async def test_client_list_tools(app: FastMCP):
)
async def test_client_call_tool(app: FastMCP):
async def test_client_call_tool(app: MCPServer):
async with Client(app) as client:
result = await client.call_tool("greet", {"name": "World"})
assert result == snapshot(
@@ -158,7 +158,7 @@ async def test_client_call_tool(app: FastMCP):
)
async def test_read_resource(app: FastMCP):
async def test_read_resource(app: MCPServer):
"""Test reading a resource."""
async with Client(app) as client:
result = await client.read_resource("test://resource")
@@ -169,7 +169,7 @@ async def test_read_resource(app: FastMCP):
)
async def test_get_prompt(app: FastMCP):
async def test_get_prompt(app: MCPServer):
"""Test getting a prompt."""
async with Client(app) as client:
result = await client.get_prompt("greeting_prompt", {"name": "Alice"})
@@ -181,14 +181,14 @@ async def test_get_prompt(app: FastMCP):
)
def test_client_session_property_before_enter(app: FastMCP):
def test_client_session_property_before_enter(app: MCPServer):
"""Test that accessing session before context manager raises RuntimeError."""
client = Client(app)
with pytest.raises(RuntimeError, match="Client must be used within an async context manager"):
client.session
async def test_client_reentry_raises_runtime_error(app: FastMCP):
async def test_client_reentry_raises_runtime_error(app: MCPServer):
"""Test that reentering a client raises RuntimeError."""
async with Client(app) as client:
with pytest.raises(RuntimeError, match="Client is already entered"):
@@ -237,7 +237,7 @@ async def test_client_set_logging_level(simple_server: Server):
assert result == snapshot(EmptyResult())
async def test_client_list_resources_with_params(app: FastMCP):
async def test_client_list_resources_with_params(app: MCPServer):
"""Test listing resources with params parameter."""
async with Client(app) as client:
result = await client.list_resources()
@@ -255,14 +255,14 @@ async def test_client_list_resources_with_params(app: FastMCP):
)
async def test_client_list_resource_templates(app: FastMCP):
async def test_client_list_resource_templates(app: MCPServer):
"""Test listing resource templates with params parameter."""
async with Client(app) as client:
result = await client.list_resource_templates()
assert result == snapshot(ListResourceTemplatesResult(resource_templates=[]))
async def test_list_prompts(app: FastMCP):
async def test_list_prompts(app: MCPServer):
"""Test listing prompts with params parameter."""
async with Client(app) as client:
result = await client.list_prompts()
+4 -4
View File
@@ -5,7 +5,7 @@ import pytest
import mcp.types as types
from mcp import Client
from mcp.server import Server
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
from mcp.types import ListToolsRequest, ListToolsResult
from .conftest import StreamSpyCollection
@@ -16,7 +16,7 @@ pytestmark = pytest.mark.anyio
@pytest.fixture
async def full_featured_server():
"""Create a server with tools, resources, prompts, and templates."""
server = FastMCP("test")
server = MCPServer("test")
# pragma: no cover on handlers below - these exist only to register items with the
# server so list_* methods return results. The handlers themselves are never called
@@ -55,7 +55,7 @@ async def full_featured_server():
)
async def test_list_methods_params_parameter(
stream_spy: Callable[[], StreamSpyCollection],
full_featured_server: FastMCP,
full_featured_server: MCPServer,
method_name: str,
request_method: str,
):
@@ -95,7 +95,7 @@ async def test_list_methods_params_parameter(
async def test_list_tools_with_strict_server_validation(
full_featured_server: FastMCP,
full_featured_server: MCPServer,
):
"""Test pagination with a server that validates request format strictly."""
async with Client(full_featured_server) as client:
+3 -3
View File
@@ -3,8 +3,8 @@ from pydantic import FileUrl
from mcp import Client
from mcp.client.session import ClientSession
from mcp.server.fastmcp import FastMCP
from mcp.server.fastmcp.server import Context
from mcp.server.mcpserver import MCPServer
from mcp.server.mcpserver.server import Context
from mcp.server.session import ServerSession
from mcp.shared.context import RequestContext
from mcp.types import ListRootsResult, Root, TextContent
@@ -12,7 +12,7 @@ from mcp.types import ListRootsResult, Root, TextContent
@pytest.mark.anyio
async def test_list_roots_callback():
server = FastMCP("test")
server = MCPServer("test")
callback_return = ListRootsResult(
roots=[
+2 -2
View File
@@ -4,7 +4,7 @@ import pytest
import mcp.types as types
from mcp import Client
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
from mcp.shared.session import RequestResponder
from mcp.types import (
LoggingMessageNotificationParams,
@@ -22,7 +22,7 @@ class LoggingCollector:
@pytest.mark.anyio
async def test_logging_callback():
server = FastMCP("test")
server = MCPServer("test")
logging_collector = LoggingCollector()
# Create a simple test tool
+3 -3
View File
@@ -2,7 +2,7 @@ import pytest
from mcp import Client
from mcp.client.session import ClientSession
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
from mcp.shared.context import RequestContext
from mcp.types import (
CreateMessageRequestParams,
@@ -16,7 +16,7 @@ from mcp.types import (
@pytest.mark.anyio
async def test_sampling_callback():
server = FastMCP("test")
server = MCPServer("test")
callback_return = CreateMessageResult(
role="assistant",
@@ -60,7 +60,7 @@ async def test_sampling_callback():
@pytest.mark.anyio
async def test_create_message_backwards_compat_single_content():
"""Test backwards compatibility: create_message without tools returns single content."""
server = FastMCP("test")
server = MCPServer("test")
# Callback returns single content (text)
callback_return = CreateMessageResult(
+15 -15
View File
@@ -5,7 +5,7 @@ import pytest
from mcp import Client
from mcp.client._memory import InMemoryTransport
from mcp.server import Server
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
from mcp.types import Resource
@@ -30,9 +30,9 @@ def simple_server() -> Server:
@pytest.fixture
def fastmcp_server() -> FastMCP:
"""Create a FastMCP server for testing."""
server = FastMCP("test")
def mcpserver_server() -> MCPServer:
"""Create an MCPServer server for testing."""
server = MCPServer("test")
@server.tool()
def greet(name: str) -> str:
@@ -58,40 +58,40 @@ async def test_with_server(simple_server: Server):
assert write_stream is not None
async def test_with_fastmcp(fastmcp_server: FastMCP):
"""Test creating transport with a FastMCP instance."""
transport = InMemoryTransport(fastmcp_server)
async def test_with_mcpserver(mcpserver_server: MCPServer):
"""Test creating transport with an MCPServer instance."""
transport = InMemoryTransport(mcpserver_server)
async with transport.connect() as (read_stream, write_stream):
assert read_stream is not None
assert write_stream is not None
async def test_server_is_running(fastmcp_server: FastMCP):
async def test_server_is_running(mcpserver_server: MCPServer):
"""Test that the server is running and responding to requests."""
async with Client(fastmcp_server) as client:
async with Client(mcpserver_server) as client:
assert client.server_capabilities is not None
async def test_list_tools(fastmcp_server: FastMCP):
async def test_list_tools(mcpserver_server: MCPServer):
"""Test listing tools through the transport."""
async with Client(fastmcp_server) as client:
async with Client(mcpserver_server) as client:
tools_result = await client.list_tools()
assert len(tools_result.tools) > 0
tool_names = [t.name for t in tools_result.tools]
assert "greet" in tool_names
async def test_call_tool(fastmcp_server: FastMCP):
async def test_call_tool(mcpserver_server: MCPServer):
"""Test calling a tool through the transport."""
async with Client(fastmcp_server) as client:
async with Client(mcpserver_server) as client:
result = await client.call_tool("greet", {"name": "World"})
assert result is not None
assert len(result.content) > 0
assert "Hello, World!" in str(result.content[0])
async def test_raise_exceptions(fastmcp_server: FastMCP):
async def test_raise_exceptions(mcpserver_server: MCPServer):
"""Test that raise_exceptions parameter is passed through."""
transport = InMemoryTransport(fastmcp_server, raise_exceptions=True)
transport = InMemoryTransport(mcpserver_server, raise_exceptions=True)
async with transport.connect() as (read_stream, _write_stream):
assert read_stream is not None
+2 -2
View File
@@ -1,12 +1,12 @@
import pytest
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
pytestmark = pytest.mark.anyio
async def test_list_tools_returns_all_tools():
mcp = FastMCP("TestTools")
mcp = MCPServer("TestTools")
# Create 100 tools with unique names
num_tools = 100
@@ -43,13 +43,13 @@ async def test_lifespan_cleanup_executed():
Path(startup_marker).unlink()
Path(cleanup_marker).unlink()
# Create a minimal MCP server using FastMCP that tracks lifecycle
# Create a minimal MCP server using MCPServer that tracks lifecycle
server_code = textwrap.dedent(f"""
import asyncio
import sys
from pathlib import Path
from contextlib import asynccontextmanager
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
STARTUP_MARKER = {escape_path_for_python(startup_marker)}
CLEANUP_MARKER = {escape_path_for_python(cleanup_marker)}
@@ -64,7 +64,7 @@ async def test_lifespan_cleanup_executed():
# This cleanup code now runs properly during shutdown
Path(CLEANUP_MARKER).write_text("cleaned up")
mcp = FastMCP("test-server", lifespan=lifespan)
mcp = MCPServer("test-server", lifespan=lifespan)
@mcp.tool()
def echo(text: str) -> str:
@@ -156,7 +156,7 @@ async def test_stdin_close_triggers_cleanup():
import sys
from pathlib import Path
from contextlib import asynccontextmanager
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
STARTUP_MARKER = {escape_path_for_python(startup_marker)}
CLEANUP_MARKER = {escape_path_for_python(cleanup_marker)}
@@ -171,7 +171,7 @@ async def test_stdin_close_triggers_cleanup():
# This cleanup code runs when stdin closes, enabling graceful shutdown
Path(CLEANUP_MARKER).write_text("cleaned up")
mcp = FastMCP("test-server", lifespan=lifespan)
mcp = MCPServer("test-server", lifespan=lifespan)
@mcp.tool()
def echo(text: str) -> str:
+3 -3
View File
@@ -1,13 +1,13 @@
import pytest
from mcp import types
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
@pytest.mark.anyio
async def test_resource_templates():
# Create an MCP server
mcp = FastMCP("Demo")
mcp = MCPServer("Demo")
# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
@@ -23,7 +23,7 @@ async def test_resource_templates():
# Get the list of resource templates using the underlying server
# Note: list_resource_templates() returns a decorator that wraps the handler
# The handler returns a ServerResult with a ListResourceTemplatesResult inside
result = await mcp._mcp_server.request_handlers[types.ListResourceTemplatesRequest](
result = await mcp._lowlevel_server.request_handlers[types.ListResourceTemplatesRequest](
types.ListResourceTemplatesRequest(params=None)
)
assert isinstance(result, types.ListResourceTemplatesResult)
+4 -4
View File
@@ -2,7 +2,7 @@
import pytest
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
from mcp.types import Icon
pytestmark = pytest.mark.anyio
@@ -19,7 +19,7 @@ async def test_icons_and_website_url():
)
# Create server with website URL and icon
mcp = FastMCP("TestServer", website_url="https://example.com", icons=[test_icon])
mcp = MCPServer("TestServer", website_url="https://example.com", icons=[test_icon])
# Create tool with icon
@mcp.tool(icons=[test_icon])
@@ -100,7 +100,7 @@ async def test_multiple_icons():
icon2 = Icon(src="data:image/png;base64,icon2", mime_type="image/png", sizes=["32x32"])
icon3 = Icon(src="data:image/png;base64,icon3", mime_type="image/png", sizes=["64x64"])
mcp = FastMCP("MultiIconServer")
mcp = MCPServer("MultiIconServer")
# Create tool with multiple icons
@mcp.tool(icons=[icon1, icon2, icon3])
@@ -122,7 +122,7 @@ async def test_multiple_icons():
async def test_no_icons_or_website():
"""Test that server works without icons or websiteUrl."""
mcp = FastMCP("BasicServer")
mcp = MCPServer("BasicServer")
@mcp.tool()
def basic_tool() -> str: # pragma: no cover
+3 -3
View File
@@ -1,7 +1,7 @@
import pytest
from mcp import Client
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
from mcp.types import (
ListResourceTemplatesResult,
TextResourceContents,
@@ -11,7 +11,7 @@ from mcp.types import (
@pytest.mark.anyio
async def test_resource_template_edge_cases():
"""Test server-side resource template validation"""
mcp = FastMCP("Demo")
mcp = MCPServer("Demo")
# Test case 1: Template with multiple parameters
@mcp.resource("resource://users/{user_id}/posts/{post_id}")
@@ -64,7 +64,7 @@ async def test_resource_template_edge_cases():
@pytest.mark.anyio
async def test_resource_template_client_interaction():
"""Test client-side resource template interaction"""
mcp = FastMCP("Demo")
mcp = MCPServer("Demo")
# Register some templated resources
@mcp.resource("resource://users/{user_id}/posts/{post_id}")
+3 -3
View File
@@ -3,16 +3,16 @@ import base64
import pytest
from mcp import Client, types
from mcp.server.fastmcp import FastMCP
from mcp.server.lowlevel import Server
from mcp.server.lowlevel.helper_types import ReadResourceContents
from mcp.server.mcpserver import MCPServer
pytestmark = pytest.mark.anyio
async def test_fastmcp_resource_mime_type():
async def test_mcpserver_resource_mime_type():
"""Test that mime_type parameter is respected for resources."""
mcp = FastMCP("test")
mcp = MCPServer("test")
# Create a small test image as bytes
image_bytes = b"fake_image_data"
@@ -7,14 +7,14 @@ with parameters like 'text/html;profile=mcp-app' which are valid per RFC 2045.
import pytest
from mcp import Client
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
pytestmark = pytest.mark.anyio
async def test_mime_type_with_parameters():
"""Test that MIME types with parameters are accepted (RFC 2045)."""
mcp = FastMCP("test")
mcp = MCPServer("test")
# This should NOT raise a validation error
@mcp.resource("ui://widget", mime_type="text/html;profile=mcp-app")
@@ -28,7 +28,7 @@ async def test_mime_type_with_parameters():
async def test_mime_type_with_parameters_and_space():
"""Test MIME type with space after semicolon."""
mcp = FastMCP("test")
mcp = MCPServer("test")
@mcp.resource("data://json", mime_type="application/json; charset=utf-8")
def data() -> str:
@@ -41,7 +41,7 @@ async def test_mime_type_with_parameters_and_space():
async def test_mime_type_with_multiple_parameters():
"""Test MIME type with multiple parameters."""
mcp = FastMCP("test")
mcp = MCPServer("test")
@mcp.resource("data://multi", mime_type="text/plain; charset=utf-8; format=fixed")
def data() -> str:
@@ -54,7 +54,7 @@ async def test_mime_type_with_multiple_parameters():
async def test_mime_type_preserved_in_read_resource():
"""Test that MIME type with parameters is preserved when reading resource."""
mcp = FastMCP("test")
mcp = MCPServer("test")
@mcp.resource("ui://my-widget", mime_type="text/html;profile=mcp-app")
def my_widget() -> str:
+2 -2
View File
@@ -2,7 +2,7 @@ from unittest.mock import AsyncMock, MagicMock
import pytest
from mcp.server.fastmcp import Context
from mcp.server.mcpserver import Context
from mcp.shared.context import RequestContext
pytestmark = pytest.mark.anyio
@@ -24,7 +24,7 @@ async def test_progress_token_zero_first_call():
)
# Create context with our mocks
ctx = Context(request_context=request_context, fastmcp=MagicMock())
ctx = Context(request_context=request_context, mcp_server=MagicMock())
# Test progress reporting
await ctx.report_progress(0, 10) # First call with 0
+3 -3
View File
@@ -2,12 +2,12 @@ import anyio
import pytest
from mcp import Client
from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
@pytest.mark.anyio
async def test_messages_are_executed_concurrently_tools():
server = FastMCP("test")
server = MCPServer("test")
event = anyio.Event()
tool_started = anyio.Event()
call_order: list[str] = []
@@ -48,7 +48,7 @@ async def test_messages_are_executed_concurrently_tools():
@pytest.mark.anyio
async def test_messages_are_executed_concurrently_tools_and_resources():
server = FastMCP("test")
server = MCPServer("test")
event = anyio.Event()
tool_started = anyio.Event()
call_order: list[str] = []
+4 -4
View File
@@ -2,7 +2,7 @@ from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from dataclasses import dataclass
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.mcpserver import Context, MCPServer
from mcp.server.session import ServerSession
@@ -19,7 +19,7 @@ class Database: # Replace with your actual DB type
# Create a named server
mcp = FastMCP("My App")
mcp = MCPServer("My App")
@dataclass
@@ -28,7 +28,7 @@ class AppContext:
@asynccontextmanager
async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]: # pragma: no cover
async def app_lifespan(server: MCPServer) -> AsyncIterator[AppContext]: # pragma: no cover
"""Manage application lifecycle with type-safe context"""
# Initialize on startup
db = await Database.connect()
@@ -40,7 +40,7 @@ async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]: # pragma:
# Pass lifespan to server
mcp = FastMCP("My App", lifespan=app_lifespan)
mcp = MCPServer("My App", lifespan=app_lifespan)
# Access type-safe lifespan context in tools
+1 -1
View File
@@ -3,7 +3,7 @@
Regression test for https://github.com/modelcontextprotocol/python-sdk/issues/973
"""
from mcp.server.fastmcp.resources import ResourceTemplate
from mcp.server.mcpserver.resources import ResourceTemplate
def test_template_matches_decodes_space():
+1 -1
View File
@@ -16,7 +16,7 @@ from starlette.applications import Starlette
from mcp.server.auth.provider import AuthorizeError, RegistrationError, TokenError
from mcp.server.auth.routes import create_auth_routes
from mcp.server.auth.settings import ClientRegistrationOptions, RevocationOptions
from tests.server.fastmcp.auth.test_auth_integration import MockOAuthProvider
from tests.server.mcpserver.auth.test_auth_integration import MockOAuthProvider
@pytest.fixture

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