A production-ready MCP server for Neo4j databases with Azure support.
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\":
Tools (3)
greetReturns a greeting message for the provided name.neo4j_healthChecks the health status of the Neo4j database connection.neo4j_queryExecutes a Cypher query against the connected Neo4j database.Environment Variables
NEO4J_URIrequiredThe URI for the Neo4j database connection.NEO4J_USERrequiredThe username for the Neo4j database.NEO4J_PASSWORDrequiredThe password for the Neo4j database.APP_NAMEThe name of the application.HOSTThe host address to bind the server.PORTThe port to bind the server.LOG_LEVELThe logging level for the application.Configuration
{"mcpServers": {"fast-mcp": {"command": "python", "args": ["-m", "app.main"], "env": {"NEO4J_URI": "bolt://localhost:7687", "NEO4J_USER": "neo4j", "NEO4J_PASSWORD": "password"}}}}