Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
venv
.venv
*/venv
*/.venv
**/.env
Expand Down
7 changes: 4 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
FROM python:3.12-slim
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim

ADD . /app
WORKDIR /app

RUN pip install -r requirements.txt
# Install dependencies using UV
RUN uv sync --frozen --no-dev

CMD ["python", "src/sandbox_api_mcp_server/server.py"]
CMD ["uv", "run", "sandbox-api-mcp-server"]
139 changes: 112 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

This project provides a Model Context Protocol (MCP) server for interacting with the [Neo4j Sandbox API](https://sandbox.neo4j.com/). It allows language models or other MCP clients to easily launch, list, query, and perform other actions on Neo4j Sandbox instances using a standardized tool interface.

The server is built as a [FastAPI](https://fastapi.tiangolo.com/) application and uses the [FastAPI-MCP](https://fastapi-mcp.tadata.com/getting-started/welcome) library to expose its endpoints as MCP tools. Authentication with the Sandbox API is handled via Auth0, and the necessary Auth0 credentials must be configured through environment variables.
The server is built as a [FastAPI](https://fastapi.tiangolo.com/) application and uses [FastMCP](https://gofastmcp.com/) (v2.12.4) to expose its endpoints as MCP tools. FastMCP provides enterprise-grade OAuth 2.1 authentication with Auth0, along with backward compatibility for API key authentication. The necessary Auth0 credentials must be configured through environment variables.

## Environment Variables

Expand All @@ -15,38 +15,44 @@ The server requires the following environment variables to be set for Auth0 auth
* `AUTH0_CLIENT_ID`: The Client ID of your Auth0 Application.
* `AUTH0_CLIENT_SECRET`: The Client Secret of your Auth0 Application.
* `SANDBOX_API_KEY`: Your Neo4j Sandbox API key. This is used by the underlying `neo4j-sandbox-api-client`.
* `PORT` (optional): The port to run the server on. Defaults to `9100` if not set.

You can set these variables directly in your environment or place them in a `.env` file in the project root.

## Running the Server

1. **Install dependencies:**
It's recommended to use a virtual environment.
1. **Install UV (if not already installed):**
```bash
python -m venv .venv
source .venv/bin/activate # On Windows use `.venv\\Scripts\\activate`
pip install -r requirements.txt
# Or using uv
# uv pip install -r requirements.txt
```
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

2. **Set environment variables:**
Ensure the `.env` file is present in the `mcp-server` directory and populated with your Auth0 and Sandbox API credentials as described above.
# Windows
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
```

3. **Run the FastAPI application:**
The server can be started using Uvicorn:
2. **Install dependencies:**
UV will automatically create a virtual environment and install dependencies:
```bash
uvicorn src.sandbox_api_mcp_server.server:run --factory --host 0.0.0.0 --port 9100
uv sync
```
Alternatively, if you have `src` in your `PYTHONPATH` or are in the `mcp-server` directory:

3. **Set environment variables:**
Ensure the `.env` file is present in the project root and populated with your Auth0 and Sandbox API credentials as described above.

4. **Run the FastAPI application:**
The server can be started using UV:
```bash
python src/sandbox_api_mcp_server/server.py
uv run sandbox-api-mcp-server
```
This will typically start the server on `http://0.0.0.0:9100`. The MCP endpoint will be available at `http://0.0.0.0:9100/sse` (as configured in `server.py`).
This will start the server on `http://0.0.0.0:9100`. The MCP server is available at two transport endpoints:
- `http://0.0.0.0:9100/sse` - SSE transport (legacy, backward compatible)
- `http://0.0.0.0:9100/mcp` - Streamable HTTP transport (modern, recommended for production)

## Using with MCP Clients (e.g., Claude Desktop)

To use this MCP server with an MCP client, you need to configure the client to connect to the running FastAPI server. Given the OAuth2 flow used for authentication, **it is highly recommended to use `mcp-remote`** to bridge the connection. `mcp-remote` will handle the browser-based login and token passing to the MCP server.
To use this MCP server with an MCP client, you need to configure the client to connect to the running FastAPI server. This server uses **FastMCP 2.12.4** to expose FastAPI endpoints as MCP tools. Authentication is handled via Auth0 (OAuth2/JWT) and API keys at the FastAPI layer.

**It is recommended to use `mcp-remote`** to bridge the connection, especially if you need to handle OAuth token acquisition. `mcp-remote` can help manage authentication tokens for the HTTP requests to the server.

### Step 1: Install `mcp-remote` (if not already installed)

Expand All @@ -57,27 +63,37 @@ npm install -g mcp-remote

### Step 2: Run your FastAPI MCP Server

Ensure your FastAPI MCP server is running locally (e.g., on `http://localhost:9100` with the MCP endpoint at `http://localhost:9100/sse`):
```bash
python src/sandbox_api_mcp_server/server.py
```
Or using uvicorn directly:
Ensure your FastAPI MCP server is running locally (e.g., on `http://localhost:9100`):
```bash
uvicorn src.sandbox_api_mcp_server.server:run --factory --host 0.0.0.0 --port 9100
uv run sandbox-api-mcp-server
```

The server provides two MCP transport endpoints:
- `http://localhost:9100/sse` - SSE transport (backward compatible)
- `http://localhost:9100/mcp` - Streamable HTTP transport (recommended)


### Step 3: Run `mcp-remote`

In a new terminal, start `mcp-remote`, pointing it to your local MCP server's `/sse` endpoint and choosing a local port for `mcp-remote` to listen on (e.g., `8080`):
In a new terminal, start `mcp-remote`, pointing it to your local MCP server. You can choose either transport endpoint:

**Using SSE (legacy, backward compatible):**
```bash
# If mcp-cli is installed globally
mcp-remote http://localhost:9100/sse 8080

# Or using npx
npx -y mcp-remote http://localhost:9100/sse 8080
```

**Using Streamable HTTP (modern, recommended):**
```bash
# If mcp-cli is installed globally
mcp-remote http://localhost:9100/mcp 8080

# Or using npx
npx -y mcp-remote http://localhost:9100/mcp 8080
```
`mcp-remote` will now listen on `localhost:8080` and proxy requests to your actual MCP server, handling the OAuth flow.

### Step 4: Configure Claude Desktop
Expand All @@ -90,6 +106,7 @@ npx -y mcp-remote http://localhost:9100/sse 8080
2. **Configure the MCP Server in Claude Desktop:**
Edit `claude_desktop_config.json` to point to the local port where `mcp-remote` is listening (e.g., `8080`).

**Option A: Using SSE transport (backward compatible):**
```json
{
"mcpServers": {
Expand All @@ -105,6 +122,23 @@ npx -y mcp-remote http://localhost:9100/sse 8080
}
}
```

**Option B: Using Streamable HTTP transport (recommended):**
```json
{
"mcpServers": {
"neo4j-sandbox-mcp-via-remote": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"http://localhost:9100/mcp",
"8080"
]
}
}
}
```
**Note:** With `mcp-remote` handling the connection to your actual server and its authentication, the Claude Desktop configuration becomes simpler, primarily needing to know where `mcp-remote` is accessible.

3. **Restart Claude Desktop:**
Expand Down Expand Up @@ -244,9 +278,60 @@ The following tools are exposed, derived from the FastAPI application's endpoint

## Development

### Project Structure

* The main FastAPI application logic is in `src/sandbox_api_mcp_server/server.py`.
* API routes (which become MCP tools) are defined in `src/sandbox_api_mcp_server/sandbox/routes.py`.
* Request/response models are primarily in `src/sandbox_api_mcp_server/sandbox/models.py` and `src/sandbox_api_mcp_server/models.py`.
* Authentication logic is in `src/sandbox_api_mcp_server/auth.py`.
* The project uses `uv` for dependency management (see `uv.lock`) and `pip` for installation (`requirements.txt`).
* Consider using `hatch` or `poetry` for more robust dependency management and packaging if distributing this server. (The `pyproject.toml` suggests `hatch` might be intended for future use).
* Auth0 OAuth provider for FastMCP is in `src/sandbox_api_mcp_server/auth_provider.py`.

### Dependency Management

This project uses [UV](https://docs.astral.sh/uv/) for fast, reliable dependency management:

* **Adding dependencies**: `uv add <package-name>`
* **Removing dependencies**: `uv remove <package-name>`
* **Updating dependencies**: `uv lock --upgrade`
* **Running scripts**: `uv run <command>`

All dependencies are defined in `pyproject.toml` and locked in `uv.lock` for reproducible builds.

### FastMCP Configuration

The server includes a `fastmcp.json` configuration file for declarative deployment. You can run the server using:

```bash
fastmcp run fastmcp.json
```

This configuration defines the source, environment, and deployment settings for the FastMCP server.

### Authentication Architecture

The server implements authentication at the **FastAPI layer** via the `verify_auth` dependency, which supports:

1. **OAuth2/JWT Tokens via Auth0**
- Validates JWT tokens issued by Auth0
- Verifies token signature using JWKS public keys
- Checks audience, issuer, and other JWT claims
- MCP clients can use these tokens via standard `Authorization: Bearer <token>` headers

2. **API Key Authentication** (backward compatibility)
- Supports `Authorization: Bearer ApiKey <key>` header format
- Maintained in FastAPI routes via `Depends(verify_auth)`
- Ensures existing API consumers continue to work

**Note on MCP OAuth Support:**
Future versions may implement native MCP OAuth support via `OAuthAuthorizationServerProvider`, which would provide Dynamic Client Registration (DCR) compliance and seamless OAuth flows specifically designed for the MCP protocol. The current implementation leverages FastMCP's ability to convert FastAPI endpoints while maintaining the existing FastAPI authentication system.

### FastMCP Features

This server leverages [FastMCP 2.12.4](https://www.jlowin.dev/blog/fastmcp-2-12) features:

- **FastAPI Integration**: Seamless conversion of FastAPI endpoints to MCP tools via `FastMCP.from_fastapi()`
- **Route Filtering**: Excludes internal endpoints (like `/health`) from MCP tool exposure using `RouteMap` configurations
- **Authentication Compatibility**: Works with existing FastAPI authentication middleware (Auth0 JWT + API keys)
- **Dual Transport Support**: Provides both transport protocols for maximum compatibility
- **SSE** at `/sse` - Legacy transport for backward compatibility with existing clients
- **Streamable HTTP** at `/mcp` - Modern transport recommended for production deployments
25 changes: 25 additions & 0 deletions fastmcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"$schema": "https://gofastmcp.com/public/schemas/fastmcp.json/v1.json",
"source": {
"path": "src/sandbox_api_mcp_server/server.py",
"entrypoint": "mcp"
},
"environment": {
"python": ">=3.10",
"dependencies": [
"cryptography~=45.0.0",
"fastapi>=0.115.0",
"fastmcp>=2.12.4",
"httpx>=0.28.1",
"PyJWT>=2.10.1",
"python-dotenv>=1.1.0",
"pydantic>=2.11.4",
"uvicorn>=0.30.0"
]
},
"deployment": {
"transport": "http",
"port": 9100
}
}

14 changes: 9 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ packages = ["src/sandbox_api_mcp_server"]

[project]
name = "sandbox-api-mcp-server"
version = "0.1.0"
version = "1.1.0"
description = "Sandbox API tool for FastMCP"
readme = "README.md"
requires-python = ">=3.10"
Expand All @@ -14,10 +14,14 @@ authors = [
{ name = "Rafal Janicki", email = "[email protected]" }
]
dependencies = [
"fastmcp>=2.5.1",
"python-dotenv>=1.1.0",
"httpx>=0.28.1",
"pydantic>=2.11.4",
"cryptography~=45.0.0",
"fastapi>=0.115.0,<1.0.0",
"fastmcp>=2.12.4",
"httpx>=0.28.1,<1.0.0",
"PyJWT>=2.10.1,<3.0.0",
"python-dotenv>=1.1.0,<2.0.0",
"pydantic>=2.11.4,<3.0.0",
"uvicorn>=0.30.0,<1.0.0",
]
classifiers = [
"Programming Language :: Python :: 3",
Expand Down
6 changes: 0 additions & 6 deletions requirements.txt

This file was deleted.

4 changes: 2 additions & 2 deletions src/sandbox_api_mcp_server/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
import json
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
from cryptography.hazmat.primitives import serialization
from helpers import get_logger
from .helpers import get_logger
from jwt.algorithms import RSAAlgorithm
from fastapi import Request, HTTPException, status
from typing import Any
from models import Auth0Settings
from .models import Auth0Settings

logger = get_logger(__name__)

Expand Down
39 changes: 39 additions & 0 deletions src/sandbox_api_mcp_server/auth_provider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""
Auth0 authentication configuration for FastMCP.

This module documents the Auth0 authentication setup. The actual authentication
is handled at the FastAPI layer via the verify_auth dependency, which supports:
- OAuth2/JWT tokens from Auth0
- API Key authentication for backward compatibility

Future Enhancement:
Implement OAuthAuthorizationServerProvider for native FastMCP OAuth support.
This would provide DCR-compliant OAuth authentication directly in the MCP protocol.

The provider would need to implement:
- get_client() - Retrieve client information
- register_client() - Handle dynamic client registration
- authorize() - Handle OAuth authorization flow
- exchange_code() - Exchange authorization code for tokens
- refresh_token() - Refresh access tokens

Reference: https://github.com/modelcontextprotocol/python-sdk/blob/main/src/mcp/server/auth/provider.py
"""

from ..models import Auth0Settings


def get_auth0_settings():
"""
Get Auth0 settings for reference.

Authentication is currently handled by FastAPI's verify_auth dependency.
This function is provided for future OAuth provider implementation.

Returns
-------
Auth0Settings
Configured Auth0 settings
"""
return Auth0Settings()

2 changes: 1 addition & 1 deletion src/sandbox_api_mcp_server/sandbox/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from fastapi.responses import PlainTextResponse

from .models import StartSandboxBody, StopSandboxBody, ExtendSandboxBody, AuraUploadBody, BackupDownloadUrlBody, FastApiReadCypherQueryBody, FastApiWriteCypherQueryBody
from helpers import get_logger
from ..helpers import get_logger
from .service import call_sandbox_api, SandboxApiClient, get_sandbox_client

logger = get_logger(__name__)
Expand Down
4 changes: 2 additions & 2 deletions src/sandbox_api_mcp_server/sandbox/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from typing import Annotated, Optional, Dict, Any
from fastapi import HTTPException, status, Depends

from auth import verify_auth
from helpers import get_logger
from ..auth import verify_auth
from ..helpers import get_logger
from .models import FastApiReadCypherQueryResponse

MAX_RETRIES = 3
Expand Down
Loading