Spaces:
Running
Running
Jeremiah Lowin commited on
Commit ·
484479b
1
Parent(s): 925b34b
Update README.md
Browse files
README.md
CHANGED
|
@@ -52,16 +52,12 @@ FastMCP handles the complex protocol details and server management, letting you
|
|
| 52 |
|
| 53 |
---
|
| 54 |
|
| 55 |
-
###
|
| 56 |
|
| 57 |
-
FastMCP
|
| 58 |
|
| 59 |
-
|
| 60 |
|
| 61 |
-
**FastMCP v2 builds upon v1's foundation** and adds the advanced features listed above (Client, Proxy, Mounting, API Generation, and more).
|
| 62 |
-
|
| 63 |
-
* **Need just the basics?** Use FastMCP v1 (the official SDK).
|
| 64 |
-
* **Need advanced features like clients, proxies, or composing servers?** Use FastMCP v2 (this library).
|
| 65 |
|
| 66 |
---
|
| 67 |
|
|
@@ -69,24 +65,26 @@ FastMCP v1's core approach of using the `@tool`, `@resource`, `@prompt` decorato
|
|
| 69 |
## Table of Contents
|
| 70 |
|
| 71 |
- [Key Features:](#key-features)
|
| 72 |
-
- [
|
| 73 |
- [Installation](#installation)
|
| 74 |
- [Quickstart](#quickstart)
|
| 75 |
- [What is MCP?](#what-is-mcp)
|
| 76 |
-
- [Core Concepts
|
| 77 |
- [The `FastMCP` Server](#the-fastmcp-server)
|
| 78 |
- [Tools](#tools)
|
| 79 |
- [Resources](#resources)
|
| 80 |
- [Prompts](#prompts)
|
| 81 |
- [Context](#context)
|
| 82 |
- [Images](#images)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
- [Advanced Features](#advanced-features)
|
| 84 |
- [Proxy Servers](#proxy-servers)
|
| 85 |
- [Composing MCP Servers](#composing-mcp-servers)
|
| 86 |
- [OpenAPI \& FastAPI Generation](#openapi--fastapi-generation)
|
| 87 |
-
- [MCP Client](#mcp-client)
|
| 88 |
-
- [LLM Sampling](#llm-sampling)
|
| 89 |
-
- [Roots Access](#roots-access)
|
| 90 |
- [Running Your Server](#running-your-server)
|
| 91 |
- [Development Mode (Recommended for Building \& Testing)](#development-mode-recommended-for-building--testing)
|
| 92 |
- [Claude Desktop Integration (For Regular Use)](#claude-desktop-integration-for-regular-use)
|
|
@@ -166,7 +164,7 @@ The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) lets you bui
|
|
| 166 |
|
| 167 |
FastMCP provides a high-level, Pythonic interface for building and interacting with these servers.
|
| 168 |
|
| 169 |
-
## Core Concepts
|
| 170 |
|
| 171 |
These are the building blocks for creating MCP servers, using the familiar decorator-based approach.
|
| 172 |
|
|
@@ -339,6 +337,174 @@ def load_image_from_disk(path: str) -> Image:
|
|
| 339 |
```
|
| 340 |
FastMCP handles the conversion to/from the base64-encoded format required by the MCP protocol.
|
| 341 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 342 |
## Advanced Features
|
| 343 |
|
| 344 |
Building on the core concepts, FastMCP v2 introduces powerful features for more complex scenarios:
|
|
@@ -479,81 +645,6 @@ mcp_server = FastMCP.from_openapi(openapi_spec, client=http_client)
|
|
| 479 |
if __name__ == "__main__":
|
| 480 |
mcp_server.run()
|
| 481 |
```
|
| 482 |
-
|
| 483 |
-
### MCP Client
|
| 484 |
-
|
| 485 |
-
The `Client` class lets you interact with any MCP server (not just FastMCP ones) from Python code:
|
| 486 |
-
|
| 487 |
-
```python
|
| 488 |
-
from fastmcp import Client
|
| 489 |
-
|
| 490 |
-
async with Client("path/to/server") as client:
|
| 491 |
-
# Call a tool
|
| 492 |
-
result = await client.call_tool("weather", {"location": "San Francisco"})
|
| 493 |
-
print(result)
|
| 494 |
-
|
| 495 |
-
# Read a resource
|
| 496 |
-
res = await client.read_resource("db://users/123/profile")
|
| 497 |
-
print(res)
|
| 498 |
-
```
|
| 499 |
-
|
| 500 |
-
You can connect to servers using any supported transport protocol (Stdio, SSE, FastMCP, etc.). If you don't specify a transport, the `Client` class automatically attempts to detect an appropriate one from your connection string or server object.
|
| 501 |
-
|
| 502 |
-
#### LLM Sampling
|
| 503 |
-
|
| 504 |
-
Sampling is an MCP feature that allows a server to request a completion from the client LLM, enabling sophisticated use cases while maintaining security and privacy on the server.
|
| 505 |
-
|
| 506 |
-
```python
|
| 507 |
-
import marvin # Or any other LLM client
|
| 508 |
-
from fastmcp import Client, Context, FastMCP
|
| 509 |
-
from fastmcp.client.sampling import RequestContext, SamplingMessage, SamplingParams
|
| 510 |
-
|
| 511 |
-
# -- Create a server that requests LLM completions from the client
|
| 512 |
-
|
| 513 |
-
mcp = FastMCP("Sampling Example")
|
| 514 |
-
|
| 515 |
-
@mcp.tool()
|
| 516 |
-
async def generate_poem(topic: str, context: Context) -> str:
|
| 517 |
-
"""Generate a short poem about the given topic."""
|
| 518 |
-
response = await context.sample(
|
| 519 |
-
f"Write a short poem about {topic}",
|
| 520 |
-
system_prompt="You are a talented poet who writes concise, evocative verses."
|
| 521 |
-
)
|
| 522 |
-
return response.text
|
| 523 |
-
|
| 524 |
-
# -- Create a client that handles the sampling requests
|
| 525 |
-
|
| 526 |
-
async def sampling_handler(
|
| 527 |
-
messages: list[SamplingMessage],
|
| 528 |
-
params: SamplingParams,
|
| 529 |
-
ctx: RequestContext,
|
| 530 |
-
) -> str:
|
| 531 |
-
# Use your preferred LLM client to generate completions
|
| 532 |
-
return await marvin.say_async(
|
| 533 |
-
message=[m.content.text for m in messages if m.content.type == "text"],
|
| 534 |
-
instructions=params.systemPrompt,
|
| 535 |
-
)
|
| 536 |
-
|
| 537 |
-
# Connect them together
|
| 538 |
-
async with Client(mcp, sampling_handler=sampling_handler) as client:
|
| 539 |
-
result = await client.call_tool("generate_poem", {"topic": "autumn leaves"})
|
| 540 |
-
print(result.content[0].text)
|
| 541 |
-
```
|
| 542 |
-
|
| 543 |
-
#### Roots Access
|
| 544 |
-
|
| 545 |
-
FastMCP exposes the MCP roots functionality, allowing clients to specify which file system roots they can access. This creates a secure boundary for tools that need to work with files. Note that the server must account for client roots explicitly.
|
| 546 |
-
|
| 547 |
-
```python
|
| 548 |
-
from fastmcp import Client, RootsList
|
| 549 |
-
|
| 550 |
-
# Specify file roots that the client can access
|
| 551 |
-
roots = ["file:///path/to/allowed/directory"]
|
| 552 |
-
|
| 553 |
-
async with Client(mcp_server, roots=roots) as client:
|
| 554 |
-
# Now tools in the MCP server can access files in the specified roots
|
| 555 |
-
await client.call_tool("process_file", {"filename": "data.csv"})
|
| 556 |
-
```
|
| 557 |
## Running Your Server
|
| 558 |
|
| 559 |
Choose the method that best suits your needs:
|
|
|
|
| 52 |
|
| 53 |
---
|
| 54 |
|
| 55 |
+
### What's New in v2?
|
| 56 |
|
| 57 |
+
FastMCP 1.0 made it so easy to build MCP servers that it's now part of the [official Model Context Protocol Python SDK](https://github.com/modelcontextprotocol/python-sdk)! For basic use cases, you can use the upstream version by importing `mcp.server.fastmcp.FastMCP` (or installing `fastmcp=1.0`).
|
| 58 |
|
| 59 |
+
Based on how the MCP ecosystem is evolving, FastMCP 2.0 builds on that foundation to introduce a variety of new features (and more experimental ideas). It adds advanced features like proxying and composing MCP servers, as well as automatically generating them from OpenAPI specs or FastAPI objects. FastMCP 2.0 also introduces new client-side functionality like LLM sampling.
|
| 60 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
|
| 62 |
---
|
| 63 |
|
|
|
|
| 65 |
## Table of Contents
|
| 66 |
|
| 67 |
- [Key Features:](#key-features)
|
| 68 |
+
- [What's New in v2?](#whats-new-in-v2)
|
| 69 |
- [Installation](#installation)
|
| 70 |
- [Quickstart](#quickstart)
|
| 71 |
- [What is MCP?](#what-is-mcp)
|
| 72 |
+
- [Core Concepts](#core-concepts)
|
| 73 |
- [The `FastMCP` Server](#the-fastmcp-server)
|
| 74 |
- [Tools](#tools)
|
| 75 |
- [Resources](#resources)
|
| 76 |
- [Prompts](#prompts)
|
| 77 |
- [Context](#context)
|
| 78 |
- [Images](#images)
|
| 79 |
+
- [MCP Clients](#mcp-clients)
|
| 80 |
+
- [Client Methods](#client-methods)
|
| 81 |
+
- [Transport Options](#transport-options)
|
| 82 |
+
- [LLM Sampling](#llm-sampling)
|
| 83 |
+
- [Roots Access](#roots-access)
|
| 84 |
- [Advanced Features](#advanced-features)
|
| 85 |
- [Proxy Servers](#proxy-servers)
|
| 86 |
- [Composing MCP Servers](#composing-mcp-servers)
|
| 87 |
- [OpenAPI \& FastAPI Generation](#openapi--fastapi-generation)
|
|
|
|
|
|
|
|
|
|
| 88 |
- [Running Your Server](#running-your-server)
|
| 89 |
- [Development Mode (Recommended for Building \& Testing)](#development-mode-recommended-for-building--testing)
|
| 90 |
- [Claude Desktop Integration (For Regular Use)](#claude-desktop-integration-for-regular-use)
|
|
|
|
| 164 |
|
| 165 |
FastMCP provides a high-level, Pythonic interface for building and interacting with these servers.
|
| 166 |
|
| 167 |
+
## Core Concepts
|
| 168 |
|
| 169 |
These are the building blocks for creating MCP servers, using the familiar decorator-based approach.
|
| 170 |
|
|
|
|
| 337 |
```
|
| 338 |
FastMCP handles the conversion to/from the base64-encoded format required by the MCP protocol.
|
| 339 |
|
| 340 |
+
|
| 341 |
+
### MCP Clients
|
| 342 |
+
|
| 343 |
+
The `Client` class lets you interact with any MCP server (not just FastMCP ones) from Python code:
|
| 344 |
+
|
| 345 |
+
```python
|
| 346 |
+
from fastmcp import Client
|
| 347 |
+
|
| 348 |
+
async with Client("path/to/server") as client:
|
| 349 |
+
# Call a tool
|
| 350 |
+
result = await client.call_tool("weather", {"location": "San Francisco"})
|
| 351 |
+
print(result)
|
| 352 |
+
|
| 353 |
+
# Read a resource
|
| 354 |
+
res = await client.read_resource("db://users/123/profile")
|
| 355 |
+
print(res)
|
| 356 |
+
```
|
| 357 |
+
|
| 358 |
+
You can connect to servers using any supported transport protocol (Stdio, SSE, FastMCP, etc.). If you don't specify a transport, the `Client` class automatically attempts to detect an appropriate one from your connection string or server object.
|
| 359 |
+
|
| 360 |
+
#### Client Methods
|
| 361 |
+
|
| 362 |
+
The `Client` class exposes several methods for interacting with MCP servers.
|
| 363 |
+
|
| 364 |
+
```python
|
| 365 |
+
async with Client("path/to/server") as client:
|
| 366 |
+
# List available tools
|
| 367 |
+
tools = await client.list_tools()
|
| 368 |
+
|
| 369 |
+
# List available resources
|
| 370 |
+
resources = await client.list_resources()
|
| 371 |
+
|
| 372 |
+
# Call a tool with arguments
|
| 373 |
+
result = await client.call_tool("generate_report", {"user_id": 123})
|
| 374 |
+
|
| 375 |
+
# Read a resource
|
| 376 |
+
user_data = await client.read_resource("db://users/123/profile")
|
| 377 |
+
|
| 378 |
+
# Get a prompt
|
| 379 |
+
greeting = await client.get_prompt("welcome", {"name": "Alice"})
|
| 380 |
+
|
| 381 |
+
# Send progress updates
|
| 382 |
+
await client.progress("task-123", 50, 100) # 50% complete
|
| 383 |
+
|
| 384 |
+
# Basic connectivity testing
|
| 385 |
+
await client.ping()
|
| 386 |
+
```
|
| 387 |
+
|
| 388 |
+
These methods correspond directly to MCP protocol operations, making it easy to interact with any MCP-compatible server (not just FastMCP ones).
|
| 389 |
+
|
| 390 |
+
#### Transport Options
|
| 391 |
+
|
| 392 |
+
FastMCP supports various transport protocols for connecting to MCP servers:
|
| 393 |
+
|
| 394 |
+
```python
|
| 395 |
+
from fastmcp import Client
|
| 396 |
+
from fastmcp.client.transports import (
|
| 397 |
+
SSETransport,
|
| 398 |
+
PythonStdioTransport,
|
| 399 |
+
FastMCPTransport
|
| 400 |
+
)
|
| 401 |
+
|
| 402 |
+
# Connect to a server over SSE (common for web-based MCP servers)
|
| 403 |
+
async with Client(SSETransport("http://localhost:8000/mcp")) as client:
|
| 404 |
+
# Use client here...
|
| 405 |
+
|
| 406 |
+
# Connect to a Python script using stdio (useful for local tools)
|
| 407 |
+
async with Client(PythonStdioTransport("path/to/script.py")) as client:
|
| 408 |
+
# Use client here...
|
| 409 |
+
|
| 410 |
+
# Connect directly to a FastMCP server object in the same process
|
| 411 |
+
from your_app import mcp_server
|
| 412 |
+
async with Client(FastMCPTransport(mcp_server)) as client:
|
| 413 |
+
# Use client here...
|
| 414 |
+
```
|
| 415 |
+
|
| 416 |
+
Common transport options include:
|
| 417 |
+
- `SSETransport`: Connect to a server via Server-Sent Events (HTTP)
|
| 418 |
+
- `PythonStdioTransport`: Run a Python script and communicate via stdio
|
| 419 |
+
- `FastMCPTransport`: Connect directly to a FastMCP server object
|
| 420 |
+
- `WSTransport`: Connect via WebSockets
|
| 421 |
+
|
| 422 |
+
In addition, if you pass a connection string or `FastMCP` server object to the `Client` constructor, it will try to automatically detect the appropriate transport.
|
| 423 |
+
|
| 424 |
+
#### LLM Sampling
|
| 425 |
+
|
| 426 |
+
Sampling is an MCP feature that allows a server to request a completion from the client LLM, enabling sophisticated use cases while maintaining security and privacy on the server.
|
| 427 |
+
|
| 428 |
+
```python
|
| 429 |
+
import marvin # Or any other LLM client
|
| 430 |
+
from fastmcp import Client, Context, FastMCP
|
| 431 |
+
from fastmcp.client.sampling import RequestContext, SamplingMessage, SamplingParams
|
| 432 |
+
|
| 433 |
+
# -- SERVER SIDE --
|
| 434 |
+
# Create a server that requests LLM completions from the client
|
| 435 |
+
|
| 436 |
+
mcp = FastMCP("Sampling Example")
|
| 437 |
+
|
| 438 |
+
@mcp.tool()
|
| 439 |
+
async def generate_poem(topic: str, context: Context) -> str:
|
| 440 |
+
"""Generate a short poem about the given topic."""
|
| 441 |
+
# The server requests a completion from the client LLM
|
| 442 |
+
response = await context.sample(
|
| 443 |
+
f"Write a short poem about {topic}",
|
| 444 |
+
system_prompt="You are a talented poet who writes concise, evocative verses."
|
| 445 |
+
)
|
| 446 |
+
return response.text
|
| 447 |
+
|
| 448 |
+
@mcp.tool()
|
| 449 |
+
async def summarize_document(document_uri: str, context: Context) -> str:
|
| 450 |
+
"""Summarize a document using client-side LLM capabilities."""
|
| 451 |
+
# First read the document as a resource
|
| 452 |
+
doc_resource = await context.read_resource(document_uri)
|
| 453 |
+
doc_content = doc_resource[0].content # Assuming single text content
|
| 454 |
+
|
| 455 |
+
# Then ask the client LLM to summarize it
|
| 456 |
+
response = await context.sample(
|
| 457 |
+
f"Summarize the following document:\n\n{doc_content}",
|
| 458 |
+
system_prompt="You are an expert summarizer. Create a concise summary."
|
| 459 |
+
)
|
| 460 |
+
return response.text
|
| 461 |
+
|
| 462 |
+
# -- CLIENT SIDE --
|
| 463 |
+
# Create a client that handles the sampling requests
|
| 464 |
+
|
| 465 |
+
async def sampling_handler(
|
| 466 |
+
messages: list[SamplingMessage],
|
| 467 |
+
params: SamplingParams,
|
| 468 |
+
ctx: RequestContext,
|
| 469 |
+
) -> str:
|
| 470 |
+
"""Handle sampling requests from the server using your preferred LLM."""
|
| 471 |
+
# Extract the messages and system prompt
|
| 472 |
+
prompt = [m.content.text for m in messages if m.content.type == "text"]
|
| 473 |
+
system_instruction = params.systemPrompt or "You are a helpful assistant."
|
| 474 |
+
|
| 475 |
+
# Use your preferred LLM client to generate completions
|
| 476 |
+
return await marvin.say_async(
|
| 477 |
+
message=prompt,
|
| 478 |
+
instructions=system_instruction,
|
| 479 |
+
)
|
| 480 |
+
|
| 481 |
+
# Connect them together
|
| 482 |
+
async with Client(mcp, sampling_handler=sampling_handler) as client:
|
| 483 |
+
result = await client.call_tool("generate_poem", {"topic": "autumn leaves"})
|
| 484 |
+
print(result.content[0].text)
|
| 485 |
+
```
|
| 486 |
+
|
| 487 |
+
This pattern is powerful because:
|
| 488 |
+
1. The server can delegate text generation to the client LLM
|
| 489 |
+
2. The server remains focused on business logic and data handling
|
| 490 |
+
3. The client maintains control over which LLM is used and how requests are handled
|
| 491 |
+
4. No sensitive data needs to be sent to external APIs
|
| 492 |
+
|
| 493 |
+
#### Roots Access
|
| 494 |
+
|
| 495 |
+
FastMCP exposes the MCP roots functionality, allowing clients to specify which file system roots they can access. This creates a secure boundary for tools that need to work with files. Note that the server must account for client roots explicitly.
|
| 496 |
+
|
| 497 |
+
```python
|
| 498 |
+
from fastmcp import Client, RootsList
|
| 499 |
+
|
| 500 |
+
# Specify file roots that the client can access
|
| 501 |
+
roots = ["file:///path/to/allowed/directory"]
|
| 502 |
+
|
| 503 |
+
async with Client(mcp_server, roots=roots) as client:
|
| 504 |
+
# Now tools in the MCP server can access files in the specified roots
|
| 505 |
+
await client.call_tool("process_file", {"filename": "data.csv"})
|
| 506 |
+
```
|
| 507 |
+
|
| 508 |
## Advanced Features
|
| 509 |
|
| 510 |
Building on the core concepts, FastMCP v2 introduces powerful features for more complex scenarios:
|
|
|
|
| 645 |
if __name__ == "__main__":
|
| 646 |
mcp_server.run()
|
| 647 |
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 648 |
## Running Your Server
|
| 649 |
|
| 650 |
Choose the method that best suits your needs:
|