@@ -99,12 +99,14 @@ from mcp.server.fastmcp import FastMCP
9999# Create an MCP server
100100mcp = FastMCP("Demo")
101101
102+
102103# Add an addition tool
103104@mcp.tool()
104105def add(a: int, b: int) -> int:
105106 """Add two numbers"""
106107 return a + b
107108
109+
108110# Add a dynamic greeting resource
109111@mcp.resource("greeting://{name}")
110112def get_greeting(name: str) -> str:
@@ -139,34 +141,42 @@ The FastMCP server is your core interface to the MCP protocol. It handles connec
139141
140142```python
141143# Add lifespan support for startup/shutdown with strong typing
144+ from contextlib import asynccontextmanager
142145from dataclasses import dataclass
143146from typing import AsyncIterator
144- from mcp.server.fastmcp import FastMCP
147+
148+ from fake_database import Database # Replace with your actual DB type
149+
150+ from mcp.server.fastmcp import Context, FastMCP
145151
146152# Create a named server
147153mcp = FastMCP("My App")
148154
149155# Specify dependencies for deployment and development
150156mcp = FastMCP("My App", dependencies=["pandas", "numpy"])
151157
158+
152159@dataclass
153160class AppContext:
154- db: Database # Replace with your actual DB type
161+ db: Database
162+
155163
156164@asynccontextmanager
157165async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
158166 """Manage application lifecycle with type-safe context"""
167+ # Initialize on startup
168+ db = await Database.connect()
159169 try:
160- # Initialize on startup
161- await db.connect()
162170 yield AppContext(db=db)
163171 finally:
164172 # Cleanup on shutdown
165173 await db.disconnect()
166174
175+
167176# Pass lifespan to server
168177mcp = FastMCP("My App", lifespan=app_lifespan)
169178
179+
170180# Access type-safe lifespan context in tools
171181@mcp.tool()
172182def query_db(ctx: Context) -> str:
@@ -180,11 +190,17 @@ def query_db(ctx: Context) -> str:
180190Resources are how you expose data to LLMs. They're similar to GET endpoints in a REST API - they provide data but shouldn't perform significant computation or have side effects:
181191
182192```python
193+ from mcp.server.fastmcp import FastMCP
194+
195+ mcp = FastMCP("My App")
196+
197+
183198@mcp.resource("config://app")
184199def get_config() -> str:
185200 """Static configuration data"""
186201 return "App configuration here"
187202
203+
188204@mcp.resource("users://{user_id}/profile")
189205def get_user_profile(user_id: str) -> str:
190206 """Dynamic user data"""
@@ -196,10 +212,17 @@ def get_user_profile(user_id: str) -> str:
196212Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects:
197213
198214```python
215+ import httpx
216+ from mcp.server.fastmcp import FastMCP
217+
218+ mcp = FastMCP("My App")
219+
220+
199221@mcp.tool()
200222def calculate_bmi(weight_kg: float, height_m: float) -> float:
201223 """Calculate BMI given weight in kg and height in meters"""
202- return weight_kg / (height_m ** 2)
224+ return weight_kg / (height_m**2)
225+
203226
204227@mcp.tool()
205228async def fetch_weather(city: str) -> str:
@@ -214,16 +237,22 @@ async def fetch_weather(city: str) -> str:
214237Prompts are reusable templates that help LLMs interact with your server effectively:
215238
216239```python
240+ from mcp.server.fastmcp import FastMCP, types
241+
242+ mcp = FastMCP("My App")
243+
244+
217245@mcp.prompt()
218246def review_code(code: str) -> str:
219247 return f"Please review this code:\n\n{code}"
220248
249+
221250@mcp.prompt()
222- def debug_error(error: str) -> list[Message]:
251+ def debug_error(error: str) -> list[types. Message]:
223252 return [
224- UserMessage("I'm seeing this error:"),
225- UserMessage(error),
226- AssistantMessage("I'll help debug that. What have you tried so far?")
253+ types. UserMessage("I'm seeing this error:"),
254+ types. UserMessage(error),
255+ types. AssistantMessage("I'll help debug that. What have you tried so far?"),
227256 ]
228257```
229258
@@ -235,6 +264,9 @@ FastMCP provides an `Image` class that automatically handles image data:
235264from mcp.server.fastmcp import FastMCP, Image
236265from PIL import Image as PILImage
237266
267+ mcp = FastMCP("My App")
268+
269+
238270@mcp.tool()
239271def create_thumbnail(image_path: str) -> Image:
240272 """Create a thumbnail from an image"""
@@ -250,6 +282,9 @@ The Context object gives your tools and resources access to MCP capabilities:
250282```python
251283from mcp.server.fastmcp import FastMCP, Context
252284
285+ mcp = FastMCP("My App")
286+
287+
253288@mcp.tool()
254289async def long_task(files: list[str], ctx: Context) -> str:
255290 """Process multiple files with progress tracking"""
@@ -322,16 +357,19 @@ from mcp.server.fastmcp import FastMCP
322357
323358mcp = FastMCP("Echo")
324359
360+
325361@mcp.resource("echo://{message}")
326362def echo_resource(message: str) -> str:
327363 """Echo a message as a resource"""
328364 return f"Resource echo: {message}"
329365
366+
330367@mcp.tool()
331368def echo_tool(message: str) -> str:
332369 """Echo a message as a tool"""
333370 return f"Tool echo: {message}"
334371
372+
335373@mcp.prompt()
336374def echo_prompt(message: str) -> str:
337375 """Create an echo prompt"""
@@ -343,20 +381,21 @@ def echo_prompt(message: str) -> str:
343381A more complex example showing database integration:
344382
345383```python
346- from mcp.server.fastmcp import FastMCP
347384import sqlite3
348385
386+ from mcp.server.fastmcp import FastMCP
387+
349388mcp = FastMCP("SQLite Explorer")
350389
390+
351391@mcp.resource("schema://main")
352392def get_schema() -> str:
353393 """Provide the database schema as a resource"""
354394 conn = sqlite3.connect("database.db")
355- schema = conn.execute(
356- "SELECT sql FROM sqlite_master WHERE type='table'"
357- ).fetchall()
395+ schema = conn.execute("SELECT sql FROM sqlite_master WHERE type='table'").fetchall()
358396 return "\n".join(sql[0] for sql in schema if sql[0])
359397
398+
360399@mcp.tool()
361400def query_data(sql: str) -> str:
362401 """Execute SQL queries safely"""
@@ -378,20 +417,27 @@ For more control, you can use the low-level server implementation directly. This
378417from contextlib import asynccontextmanager
379418from typing import AsyncIterator
380419
420+ from fake_database import Database # Replace with your actual DB type
421+
422+ from mcp.server import Server
423+
424+
381425@asynccontextmanager
382426async def server_lifespan(server: Server) -> AsyncIterator[dict]:
383427 """Manage server startup and shutdown lifecycle."""
428+ # Initialize resources on startup
429+ db = await Database.connect()
384430 try:
385- # Initialize resources on startup
386- await db.connect()
387431 yield {"db": db}
388432 finally:
389433 # Clean up on shutdown
390434 await db.disconnect()
391435
436+
392437# Pass lifespan to server
393438server = Server("example-server", lifespan=server_lifespan)
394439
440+
395441# Access lifespan context in handlers
396442@server.call_tool()
397443async def query_db(name: str, arguments: dict) -> list:
@@ -406,14 +452,15 @@ The lifespan API provides:
406452- Type-safe context passing between lifespan and request handlers
407453
408454```python
409- from mcp.server.lowlevel import Server, NotificationOptions
410- from mcp.server.models import InitializationOptions
411455import mcp.server.stdio
412456import mcp.types as types
457+ from mcp.server.lowlevel import NotificationOptions, Server
458+ from mcp.server.models import InitializationOptions
413459
414460# Create a server instance
415461server = Server("example-server")
416462
463+
417464@server.list_prompts()
418465async def handle_list_prompts() -> list[types.Prompt]:
419466 return [
@@ -422,18 +469,16 @@ async def handle_list_prompts() -> list[types.Prompt]:
422469 description="An example prompt template",
423470 arguments=[
424471 types.PromptArgument(
425- name="arg1",
426- description="Example argument",
427- required=True
472+ name="arg1", description="Example argument", required=True
428473 )
429- ]
474+ ],
430475 )
431476 ]
432477
478+
433479@server.get_prompt()
434480async def handle_get_prompt(
435- name: str,
436- arguments: dict[str, str] | None
481+ name: str, arguments: dict[str, str] | None
437482) -> types.GetPromptResult:
438483 if name != "example-prompt":
439484 raise ValueError(f"Unknown prompt: {name}")
@@ -443,14 +488,12 @@ async def handle_get_prompt(
443488 messages=[
444489 types.PromptMessage(
445490 role="user",
446- content=types.TextContent(
447- type="text",
448- text="Example prompt text"
449- )
491+ content=types.TextContent(type="text", text="Example prompt text"),
450492 )
451- ]
493+ ],
452494 )
453495
496+
454497async def run():
455498 async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
456499 await server.run(
@@ -462,12 +505,14 @@ async def run():
462505 capabilities=server.get_capabilities(
463506 notification_options=NotificationOptions(),
464507 experimental_capabilities={},
465- )
466- )
508+ ),
509+ ),
467510 )
468511
512+
469513if __name__ == "__main__":
470514 import asyncio
515+
471516 asyncio.run(run())
472517```
473518
@@ -476,18 +521,21 @@ if __name__ == "__main__":
476521The SDK provides a high-level client interface for connecting to MCP servers:
477522
478523```python
479- from mcp import ClientSession, StdioServerParameters
524+ from mcp import ClientSession, StdioServerParameters, types
480525from mcp.client.stdio import stdio_client
481526
482527# Create server parameters for stdio connection
483528server_params = StdioServerParameters(
484- command="python", # Executable
485- args=["example_server.py"], # Optional command line arguments
486- env=None # Optional environment variables
529+ command="python", # Executable
530+ args=["example_server.py"], # Optional command line arguments
531+ env=None, # Optional environment variables
487532)
488533
534+
489535# Optional: create a sampling callback
490- async def handle_sampling_message(message: types.CreateMessageRequestParams) -> types.CreateMessageResult:
536+ async def handle_sampling_message(
537+ message: types.CreateMessageRequestParams,
538+ ) -> types.CreateMessageResult:
491539 return types.CreateMessageResult(
492540 role="assistant",
493541 content=types.TextContent(
@@ -498,17 +546,22 @@ async def handle_sampling_message(message: types.CreateMessageRequestParams) ->
498546 stopReason="endTurn",
499547 )
500548
549+
501550async def run():
502551 async with stdio_client(server_params) as (read, write):
503- async with ClientSession(read, write, sampling_callback=handle_sampling_message) as session:
552+ async with ClientSession(
553+ read, write, sampling_callback=handle_sampling_message
554+ ) as session:
504555 # Initialize the connection
505556 await session.initialize()
506557
507558 # List available prompts
508559 prompts = await session.list_prompts()
509560
510561 # Get a prompt
511- prompt = await session.get_prompt("example-prompt", arguments={"arg1": "value"})
562+ prompt = await session.get_prompt(
563+ "example-prompt", arguments={"arg1": "value"}
564+ )
512565
513566 # List available resources
514567 resources = await session.list_resources()
@@ -522,8 +575,10 @@ async def run():
522575 # Call a tool
523576 result = await session.call_tool("tool-name", arguments={"arg1": "value"})
524577
578+
525579if __name__ == "__main__":
526580 import asyncio
581+
527582 asyncio.run(run())
528583```
529584
0 commit comments