FastMCP

"""FastMCP Echo Server.""" from enum import Enum from pathlib import Path from typing import Dict, List, Literal, Optional, Annotated from mcp import GetPromptResult from mcp.server.fastmcp import FastMCP from mcp.server.fastmcp.exceptions import ValidationError from mcp.server.fastmcp.prompts.prompt_manager import Prompt from mcp.server.fastmcp.prompts.base import PromptArgument from mcp.types import TextContent, PromptMessage from pydantic import BaseModel, Field, EmailStr # Create server mcp = FastMCP("EchoPromptServer") # PROMPTS SETUP class MessageTaskInput(BaseModel): """ Input validation for echo task prompt. Attributes: name (str): Name of the user email (EmailStr): Email address of the user subscribe (bool): Whether the user wants to subscribe """ name: str = Field(..., min_length=1, max_length=100, description="Name of the user (str)") number: int = Field(...,description="your lucky number (int)") email: EmailStr = Field(..., description="Email address of the user (EmailStr)") subscribe: bool = Field(..., description="Whether the user wants to subscribe (bool)") EMAIL_TEMPLATE_SUBSCRIBE = """ Hello {name}, thanks for subscribing today. We'll send updates to {email}. {number} is your lucky number """ EMAIL_TEMPLATE_UNSUBSCRIBE = """ Hello {name}, you unsubscribed today. We will no longer send updates to {email}. {number} is your lucky number """ @mcp.prompt("basic") def basic_prompt( name: Annotated[str, Field(description="Name of the user (str)")], number: Annotated[int, Field(description="Lucky number (int)")], email: Annotated[EmailStr, Field(description="Contact email address (EmailStr|str)")], subscribe: Annotated[bool, Field(description="Whether to subscribe to updates (bool)")] ) -> GetPromptResult: """ Generate a text response using the provided input. Args: name (str): Name of the user. number (int): Lucky number. email (EmailStr): Email address of the user. subscribe (bool): Whether the user wants to subscribe. Returns: str: a message for the user. """ # Validate input using MessageTaskInput try: input_data = MessageTaskInput(name=name, number=number, email=email, subscribe=subscribe) if input_data.subscribe: prompt = EMAIL_TEMPLATE_SUBSCRIBE.format( name=input_data.name, email=input_data.email, number=input_data.number ) else: prompt = EMAIL_TEMPLATE_UNSUBSCRIBE.format( name=input_data.name, email=input_data.email, number=input_data.number ) prompt = prompt.strip() return GetPromptResult( description="py-code task execution template", messages=[ PromptMessage( role="user", content=TextContent(type="text", text=prompt), ), ], ) except ValidationError as e: return f"Validation error {e}" @mcp.prompt("basic_plus") def basic_plus_prompt( name: Annotated[ str, Field( description=MessageTaskInput.model_fields["name"].description, ), ], number: Annotated[ int, Field( description=MessageTaskInput.model_fields["number"].description, ), ], email: Annotated[ EmailStr, Field( description=MessageTaskInput.model_fields["email"].description, ), ], subscribe: Annotated[ bool, Field( description=MessageTaskInput.model_fields["subscribe"].description, ), ], ) -> GetPromptResult: """ A function that uses individual arguments, directly referencing the model for validation metadata. """ # Validate input using MessageTaskInput try: input_data = MessageTaskInput(name=name, number=number, email=email, subscribe=subscribe) if input_data.subscribe: prompt = EMAIL_TEMPLATE_SUBSCRIBE.format( name=input_data.name, email=input_data.email, number=input_data.number ) else: prompt = EMAIL_TEMPLATE_UNSUBSCRIBE.format( name=input_data.name, email=input_data.email, number=input_data.number ) prompt = prompt.strip() return GetPromptResult( description="py-code task execution template", messages=[ PromptMessage( role="user", content=TextContent(type="text", text=prompt), ), ], ) except ValidationError as e: return f"Validation error {e}" @mcp.prompt("typed") def types_prompt( input_data: Annotated[ MessageTaskInput, Field(description="Input containing: name (str), number (int), email (EmailStr), and subscribe (bool)") ] ) -> GetPromptResult: """ A function that uses the model class directly. Does not expose the types to the client. Args: input_data (MessageTaskInput): Input data containing: - name (str): Name of the user - number (int): Lucky number - email (EmailStr): Email address of the user - subscribe (bool): Whether to subscribe Returns: GetPromptResult: A result containing the formatted message for the user. """ if input_data.subscribe: prompt = EMAIL_TEMPLATE_SUBSCRIBE.format( name=input_data.name, email=input_data.email, number=input_data.number ) else: prompt = EMAIL_TEMPLATE_UNSUBSCRIBE.format( name=input_data.name, email=input_data.email, number=input_data.number ) prompt = prompt.strip() return GetPromptResult( description="py-code task execution template", messages=[ PromptMessage( role="user", content=TextContent(type="text", text=prompt), ), ], ) class ProjectStatus(BaseModel): """Represents the current status and priority of a project, along with assigned users. Attributes: task (str): The name of the task. status (str): The current status of the project (e.g., "In Progress", "Completed"). priority (int): A numeric priority level (e.g., 1 for high priority). assignees (List[str]): A list of usernames assigned to this project status. """ task: str status: str priority: int assignees: List[str] @mcp.prompt("mixed") def mixed( input_data: Annotated[ ProjectStatus, Field(description="Project status containing: task (str), status (str), priority (int), assignees (List[str])") ] ) -> GetPromptResult: """ A function that uses the model class directly. Does not expose the types to the client. Args: input_data (ProjectStatus): Project status containing: - task (str): Name of the task - status (str): Current project status - priority (int): Priority level - assignees (List[str]): List of assigned usernames Returns: GetPromptResult: A result containing the formatted status report. """ # Format the status report assignee_list = ", ".join(input_data.assignees) report = f""" Project Status Report -------------------- Task Name: {input_data.task} Status: {input_data.status} Priority Level: {input_data.priority} Assigned Team Members: {assignee_list} """ report = report.strip() return GetPromptResult( description="Project status report", messages=[ PromptMessage( role="user", content=TextContent(type="text", text=report), ), ], )