fast-mcp-server
PRD: FastMCP Production-Ready Server
1. Purpose
Build a production-ready FastMCP server that is structured, configurable, testable, and ready for local, containerized, and Azure deployments. Include Neo4j connectivity as a tool and provide CI/CD scaffolding.
2. Goals
- Organize the project into a package-based structure.
- Provide environment-driven configuration (HOST/PORT, app name, Neo4j creds).
- Add structured logging (JSON).
- Add Neo4j tools: health check and query tool.
- Provide tests, Docker, Docker Compose, and Azure deployment templates.
- Provide CI workflow for tests and optional deployments.
3. Non-Goals
- Full production security hardening (secrets management, network policies).
- Domain-specific Neo4j schema or complex query library.
- Full monitoring/observability stack.
4. Target Environment
- Python 3.10.19
- FastMCP 2.14.5
- Neo4j 5.25.0
- Local dev on macOS, production on Azure (Container Apps or App Service)
5. Functional Requirements
5.1 Server
- Must start a FastMCP server with name from environment.
- Must bind to HOST and PORT from environment.
- MCP endpoint available at /mcp.
5.2 Tools
- greet(name: str) -> str returns "Hello, {name}!".
- neo4j_health() -> "ok" or "error" with exception string.
- neo4j_query(cypher: str, parameters: dict | None = None, limit: int = 50) -> list[dict]
- Limit capped to 1..1000.
- Return list of record dicts or [{"error": "..."}] on failure.
5.3 Configuration
- Read these variables:
- APP_NAME
- HOST
- PORT
- LOG_LEVEL
- NEO4J_URI
- NEO4J_USER
- NEO4J_PASSWORD
- Provide .env.example template.
5.4 Logging
- Emit JSON logs to stdout.
- Include time (UTC ISO), level, logger, message, and exc_info when present.
5.5 Tests
- Basic unit test for greet tool.
- Run with pytest.
5.6 Docker and Compose
- Dockerfile for app container.
- docker-compose.yml with app and Neo4j services.
- App uses Neo4j container via bolt://neo4j:7687.
5.7 Azure Deployment
- Azure Container Apps template (containerapp.yaml).
- Script to deploy Container Apps.
- App Service startup script.
- App Service appsettings.json template.
- Script to deploy App Service.
- GitHub Actions workflow for CI and optional deploy.
5.8 GitHub Secrets (Deploy)
Required for CI deploy jobs:
- AZURE_CREDENTIALS (service principal JSON)
- AZURE_RG
- AZURE_LOCATION
- ACR_LOGIN_SERVER
- ACR_USERNAME
- ACR_PASSWORD
App Service only:
- APP_SERVICE_NAME
Container Apps only:
- ACA_ENV
- ACA_APP_NAME
6. Project Structure
. ├─ app/ │ ├─ init.py │ ├─ config.py │ ├─ logging.py │ ├─ main.py │ └─ tools/ │ ├─ init.py │ ├─ greetings.py │ └─ neo4j.py ├─ tests/ │ └─ test_greetings.py ├─ requirements/ │ ├─ base.txt │ └─ dev.txt ├─ .env.example ├─ Dockerfile ├─ docker-compose.yml ├─ startup.sh ├─ requirements.txt ├─ server.py ├─ azure/ │ ├─ appsettings.json │ └─ containerapp.yaml ├─ scripts/ │ ├─ deploy_aca.sh │ └─ deploy_appservice.sh └─ .github/ └─ workflows/ └─ ci-deploy.yml
6.1 Quick Start
Local:
- Create a .env file from .env.example and adjust values as needed.
- Install deps: pip install -r requirements/dev.txt
- Run tests: pytest
- Start server: python -m app.main
- Open: http://127.0.0.1:8000/mcp
Docker:
- Build and run: docker compose up --build
- Open: http://127.0.0.1:8000/mcp
- Neo4j browser: http://127.0.0.1:7474
Azure App Service (manual):
- Set required environment variables and secrets for ACR.
- Run: bash scripts/deploy_appservice.sh
Neo4j env vars (required for Neo4j tools):
- NEO4J_URI
- NEO4J_USER
- NEO4J_PASSWORD
MCP client headers (stateless streamable-http):
- Accept: application/json, text/event-stream
- Content-Type: application/json
Postman import (stateless collection):
{
"info": {
"name": "FastMCP Neo4j (Stateless)",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "neo4j_health",
"request": {
"method": "POST",
"header": [
{ "key": "Accept", "value": "application/json, text/event-stream" },
{ "key": "Content-Type", "value": "application/json" }
],
"body": {
"mode": "raw",
"raw": "{\n \"jsonrpc\": \"2.0\",\n \"id\": \"h1\",\n \"method\": \"tools/call\",\n \"params\": {\n \"name\": \"neo4j_health\",\n \"arguments\": {}\n }\n}"
},
"url": {
"raw": "http://{{host}}:{{port}}/mcp",
"protocol": "http",
"host": ["{{host}}"],
"port": "{{port}}",
"path": ["mcp"]
}
}
},
{
"name": "neo4j_query",
"request": {
"method": "POST",
"header": [
{ "key": "Accept", "value": "application/json, text/event-stream" },
{ "key": "Content-Type", "value": "application/json" }
],
"body": {
"mode": "raw",
"raw": "{\n \"jsonrpc\": \"2.0\",\n \"id\": \"q1\",\n \"method\": \"tools/call\",\n \"params\": {\n \"name\": \"neo4j_query\",\n \"arguments\": {\n \"cypher\": \"MATCH (n) RETURN n LIMIT 5\",\n \"parameters\": {}\n }\n }\n}"
},
"url": {
"raw": "http://{{host}}:{{port}}/mcp",
"protocol": "http",
"host": ["{{host}}"],
"port": "{{port}}",
"path": ["mcp"]
}
}
}
],
"variable": [
{ "key": "host", "value": "127.0.0.1" },
{ "key": "port", "value": "8000" }
]
}
7. Architecture
7.1 Component Diagram (ASCII)
flowchart TB
App["FastMCP App
app/main.py
tools/*.py
config.py
logging.py"]
Neo4j["Neo4j DB
bolt://host:7687"]
MCP["/mcp endpoint"]
App <---> Neo4j App --> MCP
7.2 Runtime Flow (ASCII)
Start -> load Settings -> configure JSON logging -> create FastMCP -> register tools -> run(host, port)
7.3 Deployment Diagram (ASCII)
Local: Developer -> Python -> FastMCP -> /mcp
Docker: Developer -> Docker -> Container (FastMCP) -> Neo4j container
Azure Container Apps: GitHub Actions -> ACA -> Container (FastMCP)
Azure App Service: GitHub Actions -> App Service -> startup.sh -> FastMCP
8. Detailed Implementation Requirements
8.1 app/config.py
- Dataclass Settings with env defaults.
- get_settings() returns Settings.
8.2 app/logging.py
- JsonFormatter with ensure_ascii=True.
- configure_logging(level) sets root handler and level.
8.3 app/main.py
- create_app(settings) returns FastMCP with tools registered.
- main() loads settings and runs with host/port.
8.4 app/tools/neo4j.py
- Use neo4j.GraphDatabase.driver with cached driver.
- Health check uses "RETURN 1 AS ok".
- Query returns list of dicts, handles errors.
8.5 server.py
- Calls app.main.main for compatibility.
9. Security and Config
- No secrets stored in repo.
- .env.example is safe default.
- Azure app settings used to provide secrets in production.
10. Operational Considerations
- Logging is JSON for ingestion into Azure logging.
- Neo4j connectivity errors should not crash server on startup.
- Neo4j query tool is minimal and should be restricted in production.
11. Risks and Mitigations
- Unbounded queries: enforce limit cap.
- Credentials leakage: avoid committing .env, use Azure settings.
- Availability: allow container restarts via Azure.
12. Testing Plan
- Unit test for greet tool.
- Optional: add integration tests for Neo4j in docker-compose.
13. Acceptance Criteria
- Server runs with env HOST/PORT.
- /mcp endpoint responds.
- greet tool returns correct string.
- neo4j_health returns "ok" when DB reachable.
- neo4j_query returns rows for valid queries.
- docker-compose brings up app + neo4j.
- CI runs pytest.
- Azure templates and scripts are present.
14. Milestones
- Restructure project and add config/logging/tools.
- Add tests and split requirements.
- Add Docker and Compose.
- Add Azure templates and scripts.
- Add CI workflow.
15. Open Questions
- Final Neo4j schema and query patterns.
- Azure target: Container Apps vs App Service primary.
- Secrets management strategy (Key Vault, etc.).