Skip to main content
Glama

MCP Everything

by s2005
llm_python.txt9.3 kB
Python MCP Server (python/mcp_server.py) Implementation Details ============================================================== 1. Overview ----------- This document describes the Python implementation of an MCP (Meta-Controller Protocol) server, located in `python/mcp_server.py`. It utilizes the `FastMCP` library from the Python MCP SDK. The server's primary purpose is to exercise and demonstrate various features of the MCP, serving as a comprehensive example. 2. Core Components & Handlers --------------------------- ### Server Initialization The server is an instance of `mcp.server.fast_mcp.FastMCP`. It's initialized within the `async def main()` function with the following key parameters: - **Name:** "python-mcp-everything" - **Version:** "0.1.0" - **Capabilities:** A dictionary specifying supported features: - `prompts: {}`: Indicates basic prompt handling is enabled. - `resources: {"subscribe": True}`: Indicates resource handling and subscriptions are enabled. - `logging: {}`: Indicates logging control features are enabled. - **Lifespan Manager (`lifespan`):** An `asynccontextmanager` named `app_lifespan` is provided. This manager handles the startup and shutdown of background tasks, specifically: - `notify_resource_updates`: For periodic resource update notifications. - `notify_log_messages`: For periodic log message emissions. ### Tools Tools are defined as functions decorated with `@server.tool()`. Input schemas for tool arguments are implicitly defined by Python type hints in the function signatures. Implemented tools include: - **`echo(message: str) -> str`**: Returns the input message prefixed with "Echo: ". - **`add(a: int, b: int) -> str`**: Returns a string describing the sum of two integers. - **`long_running_operation(duration: int = 10, steps: int = 5, ctx: Context = None) -> str`**: An async tool that simulates a long operation. It uses `ctx.report_progress(current_step, total_steps)` to send progress updates to the client. - **`print_env() -> str`**: Returns a JSON string containing all environment variables of the server. - **`sample_llm(prompt: str, max_tokens: int = 100, ctx: Context = None) -> str`**: An async tool that simulates an LLM call. It uses `ctx.create_message(messages=[UserMessage(...)], max_tokens=...)` to request a message generation from the client (acting as the LLM). It then extracts and returns the text content from the response. - **`get_tiny_image() -> list`**: Returns a list of content parts, including `TextContent` and an `ImageContent` part containing a base64 encoded tiny PNG image (defined by the `MCP_TINY_IMAGE` constant from `python/constants.py`). - **`annotated_message(message_type: str, include_image: bool = False) -> list`**: Returns a list of content parts (`TextContent` and optionally `ImageContent`) with custom annotations (dictionary format) for priority and audience, based on the `message_type` argument. The `Context` object (`ctx`), when provided by the SDK to a tool, allows interaction with the MCP client, such as reporting progress or creating messages. ### Resources The server manages a predefined list of static resources. - **Static Resource Definition:** Resources are defined in a module-level list called `ALL_RESOURCES`. Each resource is a dictionary specifying `uri`, `name`, `mime_type`, and either `text` (for text-based content) or `blob` (for base64 encoded binary content). - **Reading Individual Resources:** The `get_static_resource(resource_id: str, ctx: Context = None) -> dict` function, decorated with `@server.resource("test://static/resource/{resource_id}")`, handles requests for individual static resources. It looks up the resource by its URI (constructed from the `resource_id`) in the `ALL_RESOURCES` list and returns it, or raises a `ValueError` if not found. - **Listing Resources with Pagination:** The `list_all_static_resources(cursor: str | None, page_size: int, ctx: Context) -> tuple[list[dict], str | None]` function provides paginated listing of resources from `ALL_RESOURCES`. This handler is registered with the server using `server.set_list_resources_handler(list_all_static_resources, prefix="test://static/resource/")`. It uses base64 encoded cursors (representing the next start index) to manage pagination. - **Listing Resource Templates:** The `list_resource_templates_handler(ctx: Context = None) -> list` function, decorated with `@server.list_resource_templates_handler()`, returns a list of defined resource templates. Currently, it defines one template for accessing the static resources: `"test://static/resource/{resource_id}"`. ### Prompts Prompt handling allows clients to request pre-defined message structures. - **`PromptName` Enum:** A module-level `Enum` (`PromptName`) defines symbolic names for available prompts (e.g., `SIMPLE = "simple_prompt"`). - **Listing Prompts:** The `list_prompts_handler(ctx: Context = None) -> list` function, decorated with `@server.list_prompts_handler()`, returns a list of available prompt definitions. Each definition includes its `name` (from `PromptName.value`), `description`, and `arguments` schema. - **Getting Prompts:** The `get_prompt_handler(name: str, arguments: dict | None, ctx: Context) -> dict` function, decorated with `@server.get_prompt_handler()`, constructs and returns a specific prompt based on the requested `name` and provided `arguments`. - For `PromptName.SIMPLE.value`, it returns a single `UserMessage` with `TextContent`. - For `PromptName.COMPLEX.value`, it processes `temperature` and `style` arguments and returns a sequence of messages including `UserMessage` with `TextContent`, `AssistantMessage` with `TextContent`, and a `UserMessage` with `ImageContent` (using `MCP_TINY_IMAGE`). - It raises a `ValueError` for unknown prompt names. - **Message Construction:** Prompts are constructed as dictionaries containing a "messages" key, with a list of `UserMessage`, `AssistantMessage`, etc., objects. Content parts like `TextContent` and `ImageContent` are used within these messages. ### Subscriptions The server supports client subscriptions to resources and notifies them of updates. - **Subscribe/Unsubscribe Handlers:** - `subscribe_handler(uri: str, ctx: Context)`, decorated with `@server.subscribe_handler()`, adds the given `uri` to an internal `subscriptions` set and logs the event. - `unsubscribe_handler(uri: str, ctx: Context)`, decorated with `@server.unsubscribe_handler()`, removes the `uri` from the `subscriptions` set and logs the event. - **Periodic Resource Updates:** The `notify_resource_updates(server_ref: FastMCP)` async function runs as a background task. Every 5 seconds, it iterates through the active `subscriptions` and calls `await server_ref.notify_resource_updated(uri)` for each, signaling to the client that the resource may have changed. This task is managed by the `app_lifespan` context manager. ### Argument Completion The server provides completion suggestions for specific arguments. - **Completion Handler Definition:** The `completion_handler(ref: dict, argument: dict, ctx: Context = None) -> dict` function, decorated with `@server.completion_handler()`, is responsible for providing completions. - **`EXAMPLE_COMPLETIONS`:** A module-level dictionary `EXAMPLE_COMPLETIONS` stores lists of possible completion values for specific argument names (e.g., "style", "temperature", "resourceId"). - **Logic:** The handler retrieves the `argument.name` and `argument.value` (the partially typed value). If `argument.name` is a key in `EXAMPLE_COMPLETIONS`, it filters the corresponding list for items starting with `argument.value` (case-insensitive) and returns these as suggestions. The returned structure is `{"completion": {"values": [...], "has_more": False, "total": ...}}`. ### Logging Control The server allows clients to set the logging level and periodically sends log messages. - **Logging Level Setting:** The `set_logging_level_handler(level: str, ctx: Context)` function, decorated with `@server.set_logging_level_handler()`, allows clients to set the server's current `log_level`. It updates an internal `log_level` variable and notifies the client of the change. - **Periodic Log Messages:** - `LOG_LEVEL_ORDER` (list of strings) and `LOG_MESSAGES` (list of predefined log message dicts with "level" and "data") are defined at the module level. - `is_message_ignored(current_level_str, message_level_str)` is a helper function that determines if a message should be ignored based on the current `log_level` and the `LOG_LEVEL_ORDER`. - The `notify_log_messages(server_ref: FastMCP)` async function runs as a background task (managed by `app_lifespan`). Every 15 seconds, it randomly selects a message from `LOG_MESSAGES`. If the message's level is not ignored by the current `log_level`, it sends the message to the client using `await server_ref.notify_message(...)`. 3. Running the Server -------------------- The server is executed by running the Python script directly: `python python/mcp_server.py` Inside the script, after all definitions and registrations, `server.run()` is called within the `if __name__ == "__main__": asyncio.run(main())` block, which starts the FastMCP server and makes it listen for client connections over stdio.

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/s2005/mcp-everything'

If you have feedback or need assistance with the MCP directory API, please join our Discord server