- builds the FastAPI app, wraps it with FastMCP, mounts MCP HTTP/SSE endpoints, registers resources and prompts, and starts uvicorn.
- requirements.txt - Python dependencies.
This project uses main.py as the main entry point.
The FastAPI app provides the HTTP API, documentation pages, and health check. FastMCP wraps the FastAPI app and exposes MCP tools, resources, and prompts through the MCP endpoint.
main.py
|
|-- FastAPI app
| |-- HTTP routes
| |-- Swagger UI
| |-- ReDoc
| |-- health check
|
|-- FastMCP
|-- MCP tools
|-- MCP resources
|-- MCP prompts
|-- /mcp endpointImportant folders:
app/mcp/mcp_tools/ # MCP tools and FastAPI route logic
app/mcp/mcp_prompts/ # MCP prompt templates
app/mcp/mcp_resources/ # MCP resource definitions
tests/mcp/ # MCP test suite
example_llm_client/ # Example Gemini / LLM client- Python 3.14+
- Virtual environment.
- npm inspector below.
python -m venv .venv
# Mac or Gitbash
source .venv/bin/activate
# Windows powershell:
.venv\Scripts\activate
python -m pip install -r requirements.txt
# or use UV:
uv syncThe project includes an example environment file called .env.example.
Create a local .env file from .env.example, then add your Gemini configuration:
GEMINI_API_KEY=your_api_key_here
GEMINI_MODEL=gemini-2.5-flash
MCP_SERVER_URL=http://localhost:8003/mcpYou can get a Gemini API key from Google AI Studio.
The .env file is ignored by git, so your API key should stay local and should not be committed.
# start the server
# with Python
python -m main
# with UV (recommended)
uv run main.py
# with just
just runTo run test curl commands see app/docs/curl_testing/mcp_curl_test_examples.md.
You'll see:
- Swagger UI: http://localhost:8003/docs
- ReDoc: http://localhost:8003/redoc
MCP endpoints served by FastMCP:
- streamable-http: http://localhost:8003/mcp
Each endpoint returns JSON like:
- { "result": , "operation": "..." } or { "error": "..." } for invalid input.
-H "Content-Type: application/json"
-H "Authorization: Bearer <TOKEN>"Our server doesn't require auth yet, we can omit the Authorization header.
The API includes rate limiting middleware for HTTP and MCP endpoints.
- Limit: 50 requests per client IP every 3600 seconds.
- Storage: request timestamps are tracked in memory and expired records are cleared.
- Exceeded limit: returns
429 Too Many Requestswith aRetry-Afterheader. - Missing client IP: returns
400 Bad Request.
- Start the server as above.
- Point your MCP client to the process.
// Example VS Code .vscode/mcp.json entry:
{
"servers": {
"UnitConverter": {
"command": "python",
"args": ["main.py"]
}
}
}- From the MCP client, list artifacts. You should see:
- Tools: celsius_to_fahrenheit, fahrenheit_to_celsius, kilometers_to_miles, miles_to_kilometers
- Resources: resource://unit_reference, resource://troubleshooting_guide
- Prompts: explain_conversion, api_usage
- explore everything (tools, resources, prompts) in a browser.
- with the server already running on http://localhost:8003
# If env error appears
npx @modelcontextprotocol/inspector@latest -e DUMMY=1 --url http://localhost:8003/mcp --transport streamable-httpRun the test suite:
python -m pytest -vOr with UV:
uv run pytest -vOr with just:
just testAdd new MCP tools here:
app/mcp/mcp_tools/Add new MCP prompts here:
app/mcp/mcp_prompts/Add new MCP resources here:
app/mcp/mcp_resources/Add or update MCP tests here:
tests/mcp/Add or update example LLM client code here:
example_llm_client/For detailed contribution guidelines, see CONTRIBUTION.md.
- Parse error (-32700)
- Invalid request (-32600)
- Method not found (-32601)
- Invalid params (-32602)
- Internal error (-32603)
To run test curl commands see app/docs/curl_testing/mcp_curl_test_examples.md.
macOS/Linux (bash/zsh)
- The examples above will work as-is.
# Windows PowerShell
curl -Method POST http://localhost:8003/mcp/ ` -Headers @{ "Content-Type"="application/json" }`
-Body '{"jsonrpc":"2.0","method":"prompts/list","params":{},"id":1}'Windows CMD
curl -s -X POST http://localhost:8003/mcp/ -H "Content-Type: application/json" -d "{\"jsonrpc\":\"2.0\",\"method\":\"prompts/list\",\"params\":{},\"id\":1}"This project uses just to simplify common tasks like running the server and tests.
# Using UV (Any platform)
uv tool install rust-just# Using WinGet (Native)
winget install --id Casey.Just --exact
# Using Scoop
scoop install just
# Using Chocolatey
choco install just# Using Homebrew (macOS)
brew install justOnce installed, simply run just in your terminal to see all available commands.