3333 - [ Context] ( #context )
3434 - [ Completions] ( #completions )
3535 - [ Elicitation] ( #elicitation )
36+ - [ Sampling] ( #sampling )
37+ - [ Logging and Notifications] ( #logging-and-notifications )
3638 - [ Authentication] ( #authentication )
3739 - [ Running Your Server] ( #running-your-server )
3840 - [ Development Mode] ( #development-mode )
@@ -207,48 +209,57 @@ def query_db() -> str:
207209
208210Resources 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:
209211
212+ <!-- snippet-source examples/snippets/servers/basic_resource.py -->
210213``` python
211214from mcp.server.fastmcp import FastMCP
212215
213- mcp = FastMCP(" My App " )
216+ mcp = FastMCP(name = " Resource Example " )
214217
215218
216- @mcp.resource (" config://app" , title = " Application Configuration" )
217- def get_config () -> str :
218- """ Static configuration data"""
219- return " App configuration here"
219+ @mcp.resource (" file://documents/{name} " )
220+ def read_document (name : str ) -> str :
221+ """ Read a document by name."""
222+ # This would normally read from disk
223+ return f " Content of { name} "
220224
221225
222- @mcp.resource (" users://{user_id} /profile" , title = " User Profile" )
223- def get_user_profile (user_id : str ) -> str :
224- """ Dynamic user data"""
225- return f " Profile data for user { user_id} "
226+ @mcp.resource (" config://settings" )
227+ def get_settings () -> str :
228+ """ Get application settings."""
229+ return """ {
230+ "theme": "dark",
231+ "language": "en",
232+ "debug": false
233+ }"""
226234```
235+ _ Full example: [ examples/snippets/servers/basic_resource.py] ( https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_resource.py ) _
236+ <!-- /snippet-source -->
227237
228238### Tools
229239
230240Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects:
231241
242+ <!-- snippet-source examples/snippets/servers/basic_tool.py -->
232243``` python
233- import httpx
234244from mcp.server.fastmcp import FastMCP
235245
236- mcp = FastMCP(" My App " )
246+ mcp = FastMCP(name = " Tool Example " )
237247
238248
239- @mcp.tool (title = " BMI Calculator " )
240- def calculate_bmi ( weight_kg : float , height_m : float ) -> float :
241- """ Calculate BMI given weight in kg and height in meters """
242- return weight_kg / (height_m ** 2 )
249+ @mcp.tool (description = " Add two numbers " )
250+ def add ( a : int , b : int ) -> int :
251+ """ Add two numbers together. """
252+ return a + b
243253
244254
245- @mcp.tool (title = " Weather Fetcher" )
246- async def fetch_weather (city : str ) -> str :
247- """ Fetch current weather for a city"""
248- async with httpx.AsyncClient() as client:
249- response = await client.get(f " https://api.weather.com/ { city} " )
250- return response.text
255+ @mcp.tool (description = " Get weather for a city" )
256+ def get_weather (city : str , unit : str = " celsius" ) -> str :
257+ """ Get weather for a city."""
258+ # This would normally call a weather API
259+ return f " Weather in { city} : 22° { unit[0 ].upper()} "
251260```
261+ _ Full example: [ examples/snippets/servers/basic_tool.py] ( https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_tool.py ) _
262+ <!-- /snippet-source -->
252263
253264#### Structured Output
254265
@@ -375,26 +386,26 @@ def get_temperature(city: str) -> float:
375386
376387Prompts are reusable templates that help LLMs interact with your server effectively:
377388
389+ <!-- snippet-source examples/snippets/servers/basic_prompt.py -->
378390``` python
379391from mcp.server.fastmcp import FastMCP
380- from mcp.server.fastmcp.prompts import base
381392
382- mcp = FastMCP(" My App " )
393+ mcp = FastMCP(name = " Prompt Example " )
383394
384395
385- @mcp.prompt (title = " Code Review" )
386- def review_code (code : str ) -> str :
387- return f " Please review this code: \n\n { code} "
396+ @mcp.prompt (description = " Generate a summary" )
397+ def summarize (text : str , max_words : int = 100 ) -> str :
398+ """ Create a summarization prompt."""
399+ return f " Summarize this text in { max_words} words: \n\n { text} "
388400
389401
390- @mcp.prompt (title = " Debug Assistant" )
391- def debug_error (error : str ) -> list[base.Message]:
392- return [
393- base.UserMessage(" I'm seeing this error:" ),
394- base.UserMessage(error),
395- base.AssistantMessage(" I'll help debug that. What have you tried so far?" ),
396- ]
402+ @mcp.prompt (description = " Explain a concept" )
403+ def explain (concept : str , audience : str = " general" ) -> str :
404+ """ Create an explanation prompt."""
405+ return f " Explain { concept} for a { audience} audience "
397406```
407+ _ Full example: [ examples/snippets/servers/basic_prompt.py] ( https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_prompt.py ) _
408+ <!-- /snippet-source -->
398409
399410### Images
400411
@@ -419,28 +430,30 @@ def create_thumbnail(image_path: str) -> Image:
419430
420431The Context object gives your tools and resources access to MCP capabilities:
421432
422- <!-- snippet-source examples/servers/everything/src/everything/server .py#L37-L54 -->
433+ <!-- snippet-source examples/snippets/ servers/tool_progress .py -->
423434``` python
424- # Tool with context for logging and progress
425- @mcp.tool (description = " A tool that demonstrates logging and progress" , title = " Progress Tool" )
426- async def tool_with_progress (message : str , ctx : Context, steps : int = 3 ) -> str :
427- await ctx.info(f " Starting processing of ' { message} ' with { steps} steps " )
428-
429- # Send progress notifications
430- for i in range (steps):
431- progress_value = (i + 1 ) / steps
432- await ctx.report_progress(
433- progress = progress_value,
434- total = 1.0 ,
435- message = f " Processing step { i + 1 } of { steps} " ,
436- )
437- await ctx.debug(f " Completed step { i + 1 } " )
435+ from mcp.server.fastmcp import Context, FastMCP
436+
437+ mcp = FastMCP(name = " Progress Example" )
438438
439- return f " Processed ' { message} ' in { steps} steps "
440439
441- # Simple tool for basic functionality
440+ @mcp.tool (description = " Demonstrates progress reporting" )
441+ async def long_running_task (task_name : str , ctx : Context, steps : int = 5 ) -> str :
442+ """ Execute a task with progress updates."""
443+ await ctx.info(f " Starting: { task_name} " )
444+
445+ for i in range (steps):
446+ progress = (i + 1 ) / steps
447+ await ctx.report_progress(
448+ progress = progress,
449+ total = 1.0 ,
450+ message = f " Step { i + 1 } / { steps} " ,
451+ )
452+ await ctx.debug(f " Completed step { i + 1 } " )
453+
454+ return f " Task ' { task_name} ' completed "
442455```
443- _ Full example: [ examples/servers/everything/src/everything/server .py] ( https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/servers/everything/src/everything/server .py#L37-L54 ) _
456+ _ Full example: [ examples/snippets/ servers/tool_progress .py] ( https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/ servers/tool_progress .py ) _
444457<!-- /snippet-source -->
445458
446459### Completions
@@ -473,8 +486,10 @@ async def use_completion(session: ClientSession):
473486```
474487
475488Server implementation:
489+
490+ <!-- snippet-source examples/snippets/servers/completion.py -->
476491``` python
477- from mcp.server import Server
492+ from mcp.server.fastmcp import FastMCP
478493from mcp.types import (
479494 Completion,
480495 CompletionArgument,
@@ -483,72 +498,167 @@ from mcp.types import (
483498 ResourceTemplateReference,
484499)
485500
486- server = Server(" example-server" )
501+ mcp = FastMCP(name = " Example" )
502+
487503
504+ @mcp.resource (" github://repos/{owner} /{repo} " )
505+ def github_repo (owner : str , repo : str ) -> str :
506+ """ GitHub repository resource."""
507+ return f " Repository: { owner} / { repo} "
488508
489- @server.completion ()
509+
510+ @mcp.prompt (description = " Code review prompt" )
511+ def review_code (language : str , code : str ) -> str :
512+ """ Generate a code review."""
513+ return f " Review this { language} code: \n { code} "
514+
515+
516+ @mcp.completion ()
490517async def handle_completion (
491518 ref : PromptReference | ResourceTemplateReference,
492519 argument : CompletionArgument,
493520 context : CompletionContext | None ,
494521) -> Completion | None :
522+ """ Provide completions for prompts and resources."""
523+
524+ # Complete programming languages for the prompt
525+ if isinstance (ref, PromptReference):
526+ if ref.name == " review_code" and argument.name == " language" :
527+ languages = [" python" , " javascript" , " typescript" , " go" , " rust" ]
528+ return Completion(
529+ values = [lang for lang in languages if lang.startswith(argument.value)],
530+ hasMore = False ,
531+ )
532+
533+ # Complete repository names for GitHub resources
495534 if isinstance (ref, ResourceTemplateReference):
496535 if ref.uri == " github://repos/{owner} /{repo} " and argument.name == " repo" :
497- # Use context to provide owner-specific repos
498- if context and context.arguments:
499- owner = context.arguments.get(" owner" )
500- if owner == " modelcontextprotocol" :
501- repos = [" python-sdk" , " typescript-sdk" , " specification" ]
502- # Filter based on partial input
503- filtered = [r for r in repos if r.startswith(argument.value)]
504- return Completion(values = filtered)
536+ if context and context.arguments and context.arguments.get(" owner" ) == " modelcontextprotocol" :
537+ repos = [" python-sdk" , " typescript-sdk" , " specification" ]
538+ return Completion(values = repos, hasMore = False )
539+
505540 return None
506541```
542+ _ Full example: [ examples/snippets/servers/completion.py] ( https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/completion.py ) _
543+ <!-- /snippet-source -->
507544### Elicitation
508545
509546Request additional information from users during tool execution:
510547
548+ <!-- snippet-source examples/snippets/servers/elicitation.py -->
511549``` python
512- from mcp.server.fastmcp import FastMCP, Context
513- from mcp.server.elicitation import (
514- AcceptedElicitation,
515- DeclinedElicitation,
516- CancelledElicitation,
517- )
518550from pydantic import BaseModel, Field
519551
520- mcp = FastMCP( " Booking System " )
552+ from mcp.server.fastmcp import Context, FastMCP
521553
554+ mcp = FastMCP(name = " Elicitation Example" )
522555
523- @mcp.tool ()
524- async def book_table (date : str , party_size : int , ctx : Context) -> str :
525- """ Book a table with confirmation"""
526556
527- # Schema must only contain primitive types (str, int, float, bool)
528- class ConfirmBooking (BaseModel ):
529- confirm: bool = Field(description = " Confirm booking?" )
530- notes: str = Field(default = " " , description = " Special requests" )
557+ class BookingPreferences (BaseModel ):
558+ """ Schema for collecting user preferences."""
531559
532- result = await ctx.elicit(
533- message = f " Confirm booking for { party_size} on { date} ? " , schema = ConfirmBooking
560+ checkAlternative: bool = Field(description = " Would you like to check another date?" )
561+ alternativeDate: str = Field(
562+ default = " 2024-12-26" ,
563+ description = " Alternative date (YYYY-MM-DD)" ,
534564 )
535565
536- match result:
537- case AcceptedElicitation(data = data):
538- if data.confirm:
539- return f " Booked! Notes: { data.notes or ' None' } "
540- return " Booking cancelled"
541- case DeclinedElicitation():
542- return " Booking declined"
543- case CancelledElicitation():
544- return " Booking cancelled"
566+
567+ @mcp.tool (description = " Book a restaurant table" )
568+ async def book_table (
569+ date : str ,
570+ time : str ,
571+ party_size : int ,
572+ ctx : Context,
573+ ) -> str :
574+ """ Book a table with date availability check."""
575+ # Check if date is available
576+ if date == " 2024-12-25" :
577+ # Date unavailable - ask user for alternative
578+ result = await ctx.elicit(
579+ message = (f " No tables available for { party_size} on { date} . " " Would you like to try another date?" ),
580+ schema = BookingPreferences,
581+ )
582+
583+ if result.action == " accept" and result.data:
584+ if result.data.checkAlternative:
585+ return f " ✅ Booked for { result.data.alternativeDate} "
586+ return " ❌ No booking made"
587+ return " ❌ Booking cancelled"
588+
589+ # Date available
590+ return f " ✅ Booked for { date} at { time} "
545591```
592+ _ Full example: [ examples/snippets/servers/elicitation.py] ( https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/elicitation.py ) _
593+ <!-- /snippet-source -->
546594
547595The ` elicit() ` method returns an ` ElicitationResult ` with:
548596- ` action ` : "accept", "decline", or "cancel"
549597- ` data ` : The validated response (only when accepted)
550598- ` validation_error ` : Any validation error message
551599
600+ ### Sampling
601+
602+ Tools can interact with LLMs through sampling (generating text):
603+
604+ <!-- snippet-source examples/snippets/servers/sampling.py -->
605+ ``` python
606+ from mcp.server.fastmcp import Context, FastMCP
607+ from mcp.types import SamplingMessage, TextContent
608+
609+ mcp = FastMCP(name = " Sampling Example" )
610+
611+
612+ @mcp.tool (description = " Uses sampling to generate content" )
613+ async def generate_poem (topic : str , ctx : Context) -> str :
614+ """ Generate a poem using LLM sampling."""
615+ prompt = f " Write a short poem about { topic} "
616+
617+ result = await ctx.session.create_message(
618+ messages = [
619+ SamplingMessage(
620+ role = " user" ,
621+ content = TextContent(type = " text" , text = prompt),
622+ )
623+ ],
624+ max_tokens = 100 ,
625+ )
626+
627+ if result.content.type == " text" :
628+ return result.content.text
629+ return str (result.content)
630+ ```
631+ _ Full example: [ examples/snippets/servers/sampling.py] ( https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/sampling.py ) _
632+ <!-- /snippet-source -->
633+
634+ ### Logging and Notifications
635+
636+ Tools can send logs and notifications through the context:
637+
638+ <!-- snippet-source examples/snippets/servers/notifications.py -->
639+ ``` python
640+ from mcp.server.fastmcp import Context, FastMCP
641+
642+ mcp = FastMCP(name = " Notifications Example" )
643+
644+
645+ @mcp.tool (description = " Demonstrates logging at different levels" )
646+ async def process_data (data : str , ctx : Context) -> str :
647+ """ Process data with comprehensive logging."""
648+ # Different log levels
649+ await ctx.debug(f " Debug: Processing ' { data} ' " )
650+ await ctx.info(" Info: Starting processing" )
651+ await ctx.warning(" Warning: This is experimental" )
652+ await ctx.error(" Error: (This is just a demo)" )
653+
654+ # Notify about resource changes
655+ await ctx.session.send_resource_list_changed()
656+
657+ return f " Processed: { data} "
658+ ```
659+ _ Full example: [ examples/snippets/servers/notifications.py] ( https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/notifications.py ) _
660+ <!-- /snippet-source -->
661+
552662### Authentication
553663
554664Authentication can be used by servers that want to expose tools accessing protected resources.
0 commit comments