Created
May 20, 2025 19:56
-
-
Save runekaagaard/959d0bcf9a6425a78882a0c93bbb0f5b to your computer and use it in GitHub Desktop.
Minimal vanilla mcp server in python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys, json, inspect | |
from typing import get_type_hints | |
## MCP Server "Framework" ## | |
TOOLS, TOOL_DEFINITIONS = {}, [] | |
def tool(f): | |
TOOLS[f.__name__] = f | |
TOOL_DEFINITIONS.append(tool_definition(f)) | |
return f | |
def write(data): | |
data["jsonrpc"] = "2.0" | |
print(json.dumps(data), flush=True) | |
def tool_definition(func): | |
type_hints = get_type_hints(func) | |
properties, required = {}, [] | |
type_map = {int: "integer", str: "string", float: "number", bool: "boolean", list: "array", dict: "object"} | |
for name, param in inspect.signature(func).parameters.items(): | |
if param.default is inspect.Parameter.empty: | |
required.append(name) | |
properties[name] = {"title": name, "type": type_map[type_hints[name]]} | |
return { | |
"name": func.__name__, | |
"description": (inspect.getdoc(func) or "").strip(), | |
"inputSchema": { | |
"properties": properties, | |
"required": required, | |
"type": "object" | |
} | |
} | |
def initialize(title, data): | |
return { | |
"id": data["id"], | |
"result": { | |
"protocolVersion": "2024-11-05", | |
"capabilities": { | |
"tools": {} | |
}, | |
"serverInfo": { | |
"name": title, | |
"version": "1.0" | |
} | |
} | |
} | |
def tools_list(data): | |
return {"id": data["id"], "result": {"tools": TOOL_DEFINITIONS}} | |
def tools_call(data): | |
try: | |
tool_func = TOOLS[data["params"]["name"]] | |
result, is_error = tool_func(**data["params"]["arguments"]), False | |
except Exception as e: | |
result, is_error = e, True | |
return { | |
"id": data["id"], | |
"result": { | |
"content": [{ | |
"type": "text", | |
"text": str(result), | |
}], | |
"isError": is_error | |
} | |
} | |
def run(title): | |
for line in sys.stdin: | |
try: | |
data = json.loads(line) | |
except json.JSONDecodeError: | |
continue | |
method = data["method"] | |
if method == "initialize": | |
write(initialize(title, data)) | |
elif method == "tools/list": | |
write(tools_list(data)) | |
elif method == "tools/call": | |
write(tools_call(data)) | |
## Example MCP server ## | |
@tool | |
def addition(num1: int, num2: int): | |
"""Addition of two numbers.""" | |
return num1 + num2 | |
@tool | |
def subtraction(num1: int, num2: int): | |
"""Subtraction of two numbers.""" | |
return num1 - num2 | |
@tool | |
def multiplication(num1: int, num2: int): | |
"""Multiplication of two numbers.""" | |
return num1 * num2 | |
@tool | |
def division(num1: float, num2: float): | |
"""Division of two numbers.""" | |
if num2 == 0: | |
raise ValueError("Cannot divide by zero") | |
return num1 / num2 | |
run("Basic math") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment