README Documentation
MCP (Multi-Capability Proxy) Server
This project implements a simple MCP server using Flask. The server can host multiple "tools," where each tool exposes functionalities by calling external REST APIs.
Project Structure
.
├── mcp_server.py # Main Flask application, loads tools and routes requests
├── config.py # Configuration for tools (e.g., API base URLs)
├── requirements.txt # Python dependencies
├── tools/ # Directory for tool implementations
│ ├── __init__.py # Makes 'tools' a Python package
│ └── example_tool.py # An example tool implementation
└── README.md # This file
Setup and Running
-
Clone the repository (if applicable) or ensure all files are in place.
-
Create a virtual environment (recommended):
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install dependencies:
pip install -r requirements.txt
-
Run the server:
python mcp_server.py
The server will start, by default on
http://127.0.0.1:5001
. It will also create thetools
directory and a basicexample_tool.py
if they don't exist upon first run (though they are included in this setup).
Using the MCP Server
The server exposes the following endpoints:
GET /
: Lists all available tools and their descriptions.GET /<tool_name>/<action>?param1=value1¶m2=value2
: Executes an action for a specific tool using GET. Parameters are passed as query strings.POST /<tool_name>/<action>
: Executes an action for a specific tool using POST. Parameters should be sent as a JSON body.
Example: Interacting with example_tool
The example_tool
interacts with https://jsonplaceholder.typicode.com
.
-
List available tools:
curl http://127.0.0.1:5001/
This will show
example_tool
and its available actions. -
Get all posts (using
example_tool
):curl http://127.0.0.1:5001/example_tool/get_posts
-
Get a specific post by ID (using
example_tool
):curl http://127.0.0.1:5001/example_tool/get_post_by_id?id=1
-
Create a new post (using
example_tool
):curl -X POST -H "Content-Type: application/json" \ -d '{"data": {"title": "My New Post", "body": "This is the content.", "userId": 1}}' \ http://127.0.0.1:5001/example_tool/create_post
Adding New Tools
- Create a new Python file in the
tools/
directory (e.g.,my_new_tool.py
). - Implement the
execute(action, params)
function:- This function will receive the
action
name (string) andparams
(dictionary) from the request. - It should contain the logic to call the external API based on the action and params.
- It must return a JSON-serializable dictionary or list.
- This function will receive the
- Implement the
get_tool_description()
function:- This function should return a dictionary describing the tool, including its name, a general description, and a dictionary of available actions with their descriptions and parameters. See
tools/example_tool.py
for a template.
- This function should return a dictionary describing the tool, including its name, a general description, and a dictionary of available actions with their descriptions and parameters. See
- (Optional) Add configuration for your new tool in
config.py
and import it into your tool file. - Restart the MCP server. It will automatically detect and load the new tool.
Example structure for a new tool (tools/my_new_tool.py
):
import requests
# from config import MY_NEW_TOOL_CONFIG # If you have config
# MY_API_BASE_URL = MY_NEW_TOOL_CONFIG.get("BASE_URL", "default_url_if_any")
def execute(action, params=None):
if params is None:
params = {}
if action == "some_action":
# api_key = params.get("api_key")
# some_id = params.get("id")
# response = requests.get(f"{MY_API_BASE_URL}/endpoint/{some_id}?key={api_key}")
# response.raise_for_status()
# return response.json()
return {"message": f"Action 'some_action' executed with params: {params}"}
elif action == "another_action":
# data_payload = params.get("data")
# response = requests.post(f"{MY_API_BASE_URL}/other_endpoint", json=data_payload)
# response.raise_for_status()
# return response.json()
return {"message": f"Action 'another_action' executed with data: {params.get('data')}"}
else:
return {"error": f"Action '{action}' not found in my_new_tool"}
def get_tool_description():
return {
"name": "My New Tool",
"description": "This tool does new and exciting things.",
"actions": {
"some_action": {
"description": "Performs some action that requires an ID.",
"params": {"id": "string (required)", "api_key": "string (optional)"},
"method": "GET", # Or POST, PUT, DELETE
"path_template": "/endpoint/{id}"
},
"another_action": {
"description": "Performs another action that requires a data payload.",
"params": {"data": "object (required in body)"},
"method": "POST",
"path_template": "/other_endpoint"
}
}
}
This provides a flexible way to extend the MCP server's capabilities.