@@ -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