greet
Generate personalized greetings using the FrankfurterMCP server to demonstrate middleware functionality and API integration.
Instructions
A simple greeting tool to demonstrate middleware functionality.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| name | No |
Implementation Reference
- src/frankfurtermcp/server.py:386-395 (handler)The 'greet' tool handler function - an async method that accepts an optional 'name' parameter and returns a greeting message. Uses get_response_content() helper to format the response.
async def greet( self, ctx: Context, name: str | None = None, ): """A simple greeting tool to demonstrate middleware functionality.""" greeting_name = name if name else "World" greeting_message = f"Hello, {greeting_name} from Frankfurter MCP!" await ctx.info(f"Greeting generated: {greeting_message}") return self.get_response_content(response=greeting_message) - src/frankfurtermcp/server.py:75-82 (registration)Tool registration entry in the class 'tools' list - declares 'greet' as the function name with tags ['greet', 'hello-world'] and annotations.
{ "fn": "greet", "tags": ["greet", "hello-world"], "annotations": { "readOnlyHint": True, "openWorldHint": True, }, }, - src/frankfurtermcp/mixin.py:37-72 (helper)The register_features() method in MCPMixin that iterates through the tools list and registers each tool with FastMCP using mcp.tool() decorator.
def register_features(self, mcp: FastMCP) -> FastMCP: """Register tools, resources, and prompts with the given FastMCP instance. Args: mcp (FastMCP): The FastMCP instance to register features with. Returns: FastMCP: The FastMCP instance with registered features. """ # Register tools for tool in self.tools: assert "fn" in tool, "Tool metadata must include the 'fn' key." tool_copy = copy.deepcopy(tool) fn_name = tool_copy.pop("fn") fn = getattr(self, fn_name) mcp.tool(**tool_copy)(fn) logger.debug(f"Registered MCP tool: {fn_name}") # Register resources for res in self.resources: # pragma: no cover assert "fn" in res and "uri" in res, "Resource metadata must include 'fn' and 'uri' keys." res_copy = copy.deepcopy(res) fn_name = res_copy.pop("fn") uri = res_copy.pop("uri") fn = getattr(self, fn_name) mcp.resource(uri, **res_copy)(fn) logger.debug(f"Registered MCP resource at URI: {uri}") # Register prompts for pr in self.prompts: # pragma: no cover assert "fn" in pr, "Prompt metadata must include the 'fn' key." pr_copy = copy.deepcopy(pr) fn_name = pr_copy.pop("fn") fn = getattr(self, fn_name) mcp.prompt(**pr_copy)(fn) logger.debug(f"Registered MCP prompt: {fn_name}") return mcp - src/frankfurtermcp/mixin.py:74-134 (helper)The get_response_content() helper method in MCPMixin that converts response data to a ToolResult format. Used by the greet handler to format its output.
def get_response_content( self, response: Any, http_response: httpx.Response | None = None, include_metadata: bool = EnvVar.MCP_SERVER_INCLUDE_METADATA_IN_RESPONSE, cached_response: bool = False, ) -> ToolResult: """Convert response data to a ToolResult format with optional metadata. Args: response (Any): The response data to convert. http_response (httpx.Response): The HTTP response object for header extraction. include_metadata (bool): Whether to include metadata in the response. cached_response (bool): Indicates if the response was served from cache, which will be reflected in metadata. Returns: ToolResult: The ToolResult enclosing the TextContent representation of the response along with metadata if requested. """ literal_text = "text" text_content: TextContent | None = None structured_content: dict[str, Any] | None = None if isinstance(response, TextContent): # pragma: no cover text_content = response structured_content = {"result": response.text} elif isinstance(response, (str, int, float, complex, bool, type(None))): # pragma: no cover text_content = TextContent(type=literal_text, text=str(response)) structured_content = {"result": response} elif isinstance(response, list): # pragma: no cover text_content = TextContent(type=literal_text, text=json.dumps(response)) structured_content = {"result": response} elif isinstance(response, dict): structured_content = response elif isinstance(response, BaseModel): structured_content = response.model_dump() else: # pragma: no cover raise TypeError( f"Unsupported data type: {type(response).__name__}. " "Only str, int, float, complex, bool, dict, list, and Pydantic BaseModel types are supported." ) if text_content is not None: tool_result = ToolResult(content=[text_content], structured_content=structured_content) elif structured_content is not None: tool_result = ToolResult(content=structured_content) else: assert False, ( "Unreachable code reached in get_response_content. " "Both text_content and structured_content should not have been None." ) if include_metadata: tool_result.meta = { AppMetadata.PACKAGE_NAME: ResponseMetadata( version=AppMetadata.package_metadata["Version"], api_url=HttpUrl(self.frankfurter_api_url) if http_response else None, api_status_code=http_response.status_code if http_response else None, api_bytes_downloaded=http_response.num_bytes_downloaded if http_response else None, api_elapsed_time=http_response.elapsed.microseconds if http_response else None, cached_response=cached_response, ).model_dump(), } return tool_result