Skip to content

Commit a60128a

Browse files
authored
Merge pull request #1 from neo-technology/v1
v1
2 parents 45e915b + ab2771a commit a60128a

File tree

17 files changed

+3113
-1
lines changed

17 files changed

+3113
-1
lines changed

.env.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
SANDBOX_API_KEY="<API_KEY>"
2+
3+
AUTH0_DOMAIN=""
4+
AUTH0_AUDIENCE=""
5+
AUTH0_CLIENT_ID=""
6+
AUTH0_CLIENT_SECRET=""
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
name: Deploy MCP Docker
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- development
8+
9+
jobs:
10+
set_environment:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Set up environment based on branch
15+
id: environment_check
16+
run: |
17+
SIMPLE_REF=$(echo ${GITHUB_REF#refs/heads/} | tr / -)
18+
19+
echo "env_name=${SIMPLE_REF}" >> $GITHUB_OUTPUT
20+
21+
outputs:
22+
env_name: ${{ steps.environment_check.outputs.env_name }}
23+
24+
build:
25+
runs-on: ubuntu-latest
26+
needs: [set_environment]
27+
permissions:
28+
id-token: write
29+
contents: read
30+
31+
environment:
32+
name: ${{ needs.set_environment.outputs.env_name }}
33+
34+
steps:
35+
- uses: actions/checkout@v4
36+
37+
- name: Configure AWS credentials
38+
uses: aws-actions/configure-aws-credentials@v4
39+
with:
40+
role-to-assume: ${{ vars.GH_OIDC_ROLE_ARN }}
41+
aws-region: ${{ vars.AWS_REGION }}
42+
43+
- name: Login into ECR
44+
id: login-ecr
45+
uses: aws-actions/amazon-ecr-login@v2
46+
47+
- name: Build, tag, and push docker image to Amazon ECR
48+
working-directory: ./mcp-server
49+
env:
50+
REGISTRY: ${{ steps.login-ecr.outputs.registry }}
51+
REPOSITORY: ${{ vars.MCP_ECR_REPOSITORY_NAME }}
52+
IMAGE_TAG: latest
53+
run: |
54+
docker build -t $REGISTRY/$REPOSITORY:$IMAGE_TAG .
55+
docker push $REGISTRY/$REPOSITORY:$IMAGE_TAG
56+
57+
- name: Deploy to Amazon ECS
58+
uses: brunocascio/[email protected]
59+
with:
60+
args: deploy ${{ vars.MCP_ECS_CLUSTER }} ${{ vars.MCP_ECS_SERVICE }}

.gitignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
venv
2+
*/venv
3+
*/.venv
4+
**/.env
5+
6+
# Mac/OSX
7+
.DS_Store
8+
9+
# Windows
10+
Thumbs.db
11+
12+
# Editors
13+
.vscode/
14+
.idea/
15+
*.iml

Dockerfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
FROM python:3.12-slim
2+
3+
ADD . /app
4+
WORKDIR /app
5+
6+
RUN pip install -r requirements.txt
7+
8+
CMD ["python", "src/sandbox_api_mcp_server/server.py"]

README.md

Lines changed: 252 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,252 @@
1-
# sandbox-mcp-server
1+
# Sandbox API MCP Server
2+
3+
## Overview
4+
5+
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.
6+
7+
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.
8+
9+
## Environment Variables
10+
11+
The server requires the following environment variables to be set for Auth0 authentication, which is used to secure the MCP tools and interact with the Sandbox API on behalf of the user:
12+
13+
* `AUTH0_DOMAIN`: Your Auth0 tenant domain (e.g., `your-tenant.auth0.com`).
14+
* `AUTH0_AUDIENCE`: The Audience for your Auth0 API (e.g., `https://your-tenant.auth0.com/api/v2/`).
15+
* `AUTH0_CLIENT_ID`: The Client ID of your Auth0 Application.
16+
* `AUTH0_CLIENT_SECRET`: The Client Secret of your Auth0 Application.
17+
* `SANDBOX_API_KEY`: Your Neo4j Sandbox API key. This is used by the underlying `neo4j-sandbox-api-client`.
18+
19+
You can set these variables directly in your environment or place them in a `.env` file in the project root.
20+
21+
## Running the Server
22+
23+
1. **Install dependencies:**
24+
It's recommended to use a virtual environment.
25+
```bash
26+
python -m venv .venv
27+
source .venv/bin/activate # On Windows use `.venv\\Scripts\\activate`
28+
pip install -r requirements.txt
29+
# Or using uv
30+
# uv pip install -r requirements.txt
31+
```
32+
33+
2. **Set environment variables:**
34+
Ensure the `.env` file is present in the `mcp-server` directory and populated with your Auth0 and Sandbox API credentials as described above.
35+
36+
3. **Run the FastAPI application:**
37+
The server can be started using Uvicorn:
38+
```bash
39+
uvicorn src.sandbox_api_mcp_server.server:run --factory --host 0.0.0.0 --port 9100
40+
```
41+
Alternatively, if you have `src` in your `PYTHONPATH` or are in the `mcp-server` directory:
42+
```bash
43+
python src/sandbox_api_mcp_server/server.py
44+
```
45+
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`).
46+
47+
## Using with MCP Clients (e.g., Claude Desktop)
48+
49+
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.
50+
51+
### Step 1: Install `mcp-remote` (if not already installed)
52+
53+
If you don't have `mcp-remote` (part of the `mcp-cli` package) installed globally, you can use `npx` to run it directly or install it:
54+
```bash
55+
npm install -g mcp-remote
56+
```
57+
58+
### Step 2: Run your FastAPI MCP Server
59+
60+
Ensure your FastAPI MCP server is running locally (e.g., on `http://localhost:9100` with the MCP endpoint at `http://localhost:9100/sse`):
61+
```bash
62+
python src/sandbox_api_mcp_server/server.py
63+
```
64+
Or using uvicorn directly:
65+
```bash
66+
uvicorn src.sandbox_api_mcp_server.server:run --factory --host 0.0.0.0 --port 9100
67+
```
68+
69+
70+
### Step 3: Run `mcp-remote`
71+
72+
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`):
73+
74+
```bash
75+
# If mcp-cli is installed globally
76+
mcp-remote http://localhost:9100/sse 8080
77+
78+
# Or using npx
79+
npx -y mcp-remote http://localhost:9100/sse 8080
80+
```
81+
`mcp-remote` will now listen on `localhost:8080` and proxy requests to your actual MCP server, handling the OAuth flow.
82+
83+
### Step 4: Configure Claude Desktop
84+
85+
1. **Locate Claude Desktop Configuration:**
86+
* **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
87+
* **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
88+
If the file doesn't exist, create it.
89+
90+
2. **Configure the MCP Server in Claude Desktop:**
91+
Edit `claude_desktop_config.json` to point to the local port where `mcp-remote` is listening (e.g., `8080`).
92+
93+
```json
94+
{
95+
"mcpServers": {
96+
"neo4j-sandbox-mcp-via-remote": {
97+
"command": "npx",
98+
"args": [
99+
"-y",
100+
"mcp-remote",
101+
"http://localhost:9100/sse",
102+
"8080"
103+
]
104+
}
105+
}
106+
}
107+
```
108+
**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.
109+
110+
3. **Restart Claude Desktop:**
111+
Quit and reopen Claude Desktop to load the new configuration.
112+
113+
4. **Authenticate via Browser:**
114+
When you first try to use a tool, `mcp-remote` should open a browser window for you to complete the Auth0 login. After successful authentication, Claude Desktop will be able to use the tools.
115+
116+
5. **Verify Connection:**
117+
Look for the MCP tools icon in Claude Desktop to confirm connection.
118+
119+
## Available MCP Tools
120+
121+
The following tools are exposed, derived from the FastAPI application's endpoints. The `operation_id` of each FastAPI route becomes the tool name.
122+
123+
---
124+
125+
### `list_sandboxes_for_user`
126+
- **Description**: List all running sandbox instances for the authenticated user.
127+
- **Input**: None
128+
- **Output**: `Dict` (JSON object containing a list of sandboxes)
129+
130+
---
131+
132+
### `start_new_sandbox`
133+
- **Description**: Starts a new sandbox instance for a specified use case.
134+
- **Input**:
135+
- `usecase` (str): The name of the use case for the sandbox (e.g., 'movies', 'blank').
136+
- **Output**: `Dict` (JSON object representing the newly started sandbox)
137+
138+
---
139+
140+
### `terminate_sandbox`
141+
- **Description**: Stops/terminates a specific sandbox instance.
142+
- **Input**:
143+
- `sandbox_hash_key` (str): The unique hash key identifying the sandbox.
144+
- **Output**: `Dict` (Typically an empty JSON object `{}` on success, or an error object)
145+
146+
---
147+
148+
### `extend_sandbox_lifetime`
149+
- **Description**: Extends the lifetime of a sandbox or all sandboxes for the user.
150+
- **Input**:
151+
- `sandbox_hash_key` (Optional[str]): Specific sandbox to extend. If None, all user's sandboxes are extended.
152+
- **Output**: `Dict` (JSON object with status of the extension)
153+
154+
---
155+
156+
### `get_sandbox_connection_details`
157+
- **Description**: Gets connection details for a specific sandbox.
158+
- **Input**:
159+
- `sandbox_hash_key` (str, path parameter): The unique hash key identifying the sandbox.
160+
- `verify_connect` (Optional[bool], query parameter, default: `False`): If true, verifies connection to the sandbox.
161+
- **Output**: `Dict` (JSON object containing connection details for the sandbox)
162+
163+
---
164+
165+
### `request_sandbox_backup`
166+
- **Description**: Requests a backup for a specific sandbox.
167+
- **Input**:
168+
- `sandbox_hash_key` (str, path parameter): The unique hash key identifying the sandbox.
169+
- **Output**: `Dict` (JSON object containing details of the backup request, possibly including a result ID)
170+
171+
---
172+
173+
### `get_backup_result`
174+
- **Description**: Retrieves the result of a specific backup task.
175+
- **Input**:
176+
- `result_id` (str, path parameter): The ID of the backup/upload task result.
177+
- **Output**: `Dict` (JSON object containing the status and details of the backup task)
178+
179+
---
180+
181+
### `list_sandbox_backups`
182+
- **Description**: Lists available backups for a specific sandbox.
183+
- **Input**:
184+
- `sandbox_hash_key` (str, path parameter): The unique hash key identifying the sandbox.
185+
- **Output**: `Dict` (JSON object containing a list of available backups)
186+
187+
---
188+
189+
### `get_sandbox_backup_download_url`
190+
- **Description**: Gets a download URL for a specific sandbox backup file.
191+
- **Input**:
192+
- `sandbox_hash_key` (str, path parameter): The unique hash key identifying the sandbox.
193+
- `key` (str, in request body): The S3 key of the backup file to download.
194+
- **Output**: `Dict` (JSON object containing the download URL)
195+
196+
---
197+
198+
### `upload_sandbox_to_aura`
199+
- **Description**: Uploads a sandbox backup to an Aura instance.
200+
- **Input**:
201+
- `sandbox_hash_key` (str): The unique hash key identifying the sandbox backup to upload.
202+
- `aura_uri` (str): The Aura instance URI (e.g., neo4j+s://xxxx.databases.neo4j.io).
203+
- `aura_password` (str): Password for the Aura instance.
204+
- `aura_username` (Optional[str], default: `'neo4j'`): Username for the Aura instance.
205+
- **Output**: `Dict` (JSON object containing details of the upload task, possibly including a result ID)
206+
207+
---
208+
209+
### `get_aura_upload_result`
210+
- **Description**: Retrieves the result of a specific Aura upload task.
211+
- **Input**:
212+
- `result_id` (str, path parameter): The ID of the Aura upload task result.
213+
- **Output**: `Dict` (JSON object containing the status and details of the Aura upload task)
214+
215+
---
216+
217+
### `get_schema`
218+
- **Description**: Retrieves the schema for a specific sandbox.
219+
- **Input**:
220+
- `hash_key` (str, query parameter): The hash key of the sandbox.
221+
- **Output**: `Dict` (JSON object containing the schema information)
222+
223+
---
224+
225+
### `read_query`
226+
- **Description**: Executes a read-only Cypher query on a sandbox.
227+
- **Input**:
228+
- `hash_key` (str): The hash key of the sandbox to query.
229+
- `query` (str): The Read Cypher query to execute.
230+
- `params` (Optional[Dict[str, Any]]): Optional parameters for the Cypher query.
231+
- **Output**: `Dict` (JSON object containing the query results)
232+
233+
---
234+
235+
### `write_query`
236+
- **Description**: Executes a write Cypher query on a sandbox.
237+
- **Input**:
238+
- `hash_key` (str): The hash key of the sandbox to query.
239+
- `query` (str): The Write Cypher query to execute.
240+
- `params` (Optional[Dict[str, Any]]): Optional parameters for the Cypher query.
241+
- **Output**: `Dict` (JSON object, typically empty or with summary information)
242+
243+
---
244+
245+
## Development
246+
247+
* The main FastAPI application logic is in `src/sandbox_api_mcp_server/server.py`.
248+
* API routes (which become MCP tools) are defined in `src/sandbox_api_mcp_server/sandbox/routes.py`.
249+
* Request/response models are primarily in `src/sandbox_api_mcp_server/sandbox/models.py` and `src/sandbox_api_mcp_server/models.py`.
250+
* Authentication logic is in `src/sandbox_api_mcp_server/auth.py`.
251+
* The project uses `uv` for dependency management (see `uv.lock`) and `pip` for installation (`requirements.txt`).
252+
* 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).

pyproject.toml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
[build-system]
2+
requires = ["hatchling"]
3+
build-backend = "hatchling.build"
4+
packages = ["src/sandbox_api_mcp_server"]
5+
6+
[project]
7+
name = "sandbox-api-mcp-server"
8+
version = "0.1.0"
9+
description = "Sandbox API tool for FastMCP"
10+
readme = "README.md"
11+
requires-python = ">=3.10"
12+
license = "MIT"
13+
authors = [
14+
{ name = "Rafal Janicki", email = "[email protected]" }
15+
]
16+
dependencies = [
17+
"fastmcp>=2.5.1",
18+
"python-dotenv>=1.1.0",
19+
"httpx>=0.28.1",
20+
"pydantic>=2.11.4",
21+
]
22+
classifiers = [
23+
"Programming Language :: Python :: 3",
24+
"Programming Language :: Python :: 3.10",
25+
"Programming Language :: Python :: 3.11",
26+
"Programming Language :: Python :: 3.12",
27+
"Programming Language :: Python :: 3.13",
28+
"License :: OSI Approved :: MIT License",
29+
"Operating System :: OS Independent",
30+
]
31+
32+
[project.scripts]
33+
sandbox-api-mcp-server = "sandbox_api_mcp_server:server.run"

requirements.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
cryptography~=45.0.0
2+
fastapi-mcp>=0.3.3
3+
httpx>=0.28.1,<1.0.0
4+
PyJWT>=2.10.1,<3.0.0
5+
python-dotenv>=1.1.0,<2.0.0
6+
pydantic>=2.11.4,<3.0.0

0 commit comments

Comments
 (0)