Skip to content

Commit 0ade000

Browse files
committed
Update project structure and dependencies; switch to UV for dependency management and server execution
1 parent 63cd2b7 commit 0ade000

File tree

10 files changed

+586
-128
lines changed

10 files changed

+586
-128
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
venv
1+
.venv
22
*/venv
33
*/.venv
44
**/.env

Dockerfile

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
FROM python:3.12-slim
1+
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim
22

33
ADD . /app
44
WORKDIR /app
55

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

8-
CMD ["python", "src/sandbox_api_mcp_server/server.py"]
9+
CMD ["uv", "run", "sandbox-api-mcp-server"]

README.md

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,29 +20,30 @@ You can set these variables directly in your environment or place them in a `.en
2020

2121
## Running the Server
2222

23-
1. **Install dependencies:**
24-
It's recommended to use a virtual environment.
23+
1. **Install UV (if not already installed):**
2524
```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-
```
25+
# macOS/Linux
26+
curl -LsSf https://astral.sh/uv/install.sh | sh
3227

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.
28+
# Windows
29+
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
30+
```
3531

36-
3. **Run the FastAPI application:**
37-
The server can be started using Uvicorn:
32+
2. **Install dependencies:**
33+
UV will automatically create a virtual environment and install dependencies:
3834
```bash
39-
uvicorn src.sandbox_api_mcp_server.server:run --factory --host 0.0.0.0 --port 9100
35+
uv sync
4036
```
41-
Alternatively, if you have `src` in your `PYTHONPATH` or are in the `mcp-server` directory:
37+
38+
3. **Set environment variables:**
39+
Ensure the `.env` file is present in the project root and populated with your Auth0 and Sandbox API credentials as described above.
40+
41+
4. **Run the FastAPI application:**
42+
The server can be started using UV:
4243
```bash
43-
python src/sandbox_api_mcp_server/server.py
44+
uv run sandbox-api-mcp-server
4445
```
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+
This will 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`).
4647

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

@@ -59,11 +60,7 @@ npm install -g mcp-remote
5960
6061
Ensure your FastAPI MCP server is running locally (e.g., on `http://localhost:9100` with the MCP endpoint at `http://localhost:9100/sse`):
6162
```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
63+
uv run sandbox-api-mcp-server
6764
```
6865
6966
@@ -244,9 +241,20 @@ The following tools are exposed, derived from the FastAPI application's endpoint
244241
245242
## Development
246243
244+
### Project Structure
245+
247246
* The main FastAPI application logic is in `src/sandbox_api_mcp_server/server.py`.
248247
* API routes (which become MCP tools) are defined in `src/sandbox_api_mcp_server/sandbox/routes.py`.
249248
* Request/response models are primarily in `src/sandbox_api_mcp_server/sandbox/models.py` and `src/sandbox_api_mcp_server/models.py`.
250249
* 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).
250+
251+
### Dependency Management
252+
253+
This project uses [UV](https://docs.astral.sh/uv/) for fast, reliable dependency management:
254+
255+
* **Adding dependencies**: `uv add <package-name>`
256+
* **Removing dependencies**: `uv remove <package-name>`
257+
* **Updating dependencies**: `uv lock --upgrade`
258+
* **Running scripts**: `uv run <command>`
259+
260+
All dependencies are defined in `pyproject.toml` and locked in `uv.lock` for reproducible builds.

pyproject.toml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ authors = [
1414
{ name = "Rafal Janicki", email = "[email protected]" }
1515
]
1616
dependencies = [
17-
"fastmcp>=2.5.1",
18-
"python-dotenv>=1.1.0",
19-
"httpx>=0.28.1",
20-
"pydantic>=2.11.4",
17+
"cryptography~=45.0.0",
18+
"fastapi-mcp>=0.3.3",
19+
"httpx>=0.28.1,<1.0.0",
20+
"PyJWT>=2.10.1,<3.0.0",
21+
"python-dotenv>=1.1.0,<2.0.0",
22+
"pydantic>=2.11.4,<3.0.0",
23+
"uvicorn>=0.30.0,<1.0.0",
2124
]
2225
classifiers = [
2326
"Programming Language :: Python :: 3",

requirements.txt

Lines changed: 0 additions & 6 deletions
This file was deleted.

src/sandbox_api_mcp_server/auth.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
import json
33
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
44
from cryptography.hazmat.primitives import serialization
5-
from helpers import get_logger
5+
from .helpers import get_logger
66
from jwt.algorithms import RSAAlgorithm
77
from fastapi import Request, HTTPException, status
88
from typing import Any
9-
from models import Auth0Settings
9+
from .models import Auth0Settings
1010

1111
logger = get_logger(__name__)
1212

src/sandbox_api_mcp_server/sandbox/routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from fastapi.responses import PlainTextResponse
66

77
from .models import StartSandboxBody, StopSandboxBody, ExtendSandboxBody, AuraUploadBody, BackupDownloadUrlBody, FastApiReadCypherQueryBody, FastApiWriteCypherQueryBody
8-
from helpers import get_logger
8+
from ..helpers import get_logger
99
from .service import call_sandbox_api, SandboxApiClient, get_sandbox_client
1010

1111
logger = get_logger(__name__)

src/sandbox_api_mcp_server/sandbox/service.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
from typing import Annotated, Optional, Dict, Any
66
from fastapi import HTTPException, status, Depends
77

8-
from auth import verify_auth
9-
from helpers import get_logger
8+
from ..auth import verify_auth
9+
from ..helpers import get_logger
1010
from .models import FastApiReadCypherQueryResponse
1111

1212
MAX_RETRIES = 3

src/sandbox_api_mcp_server/server.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import os
22
import uvicorn
33

4+
from anyio import get_cancelled_exc_class
45
from contextlib import asynccontextmanager
56
from dotenv import load_dotenv
67
from fastapi import FastAPI, Depends
78
from fastapi.middleware.cors import CORSMiddleware
89
from fastapi_mcp import AuthConfig, FastApiMCP
910
from uvicorn._types import ASGI3Application, ASGIReceiveCallable, ASGISendCallable, Scope
1011
from starlette.middleware.base import BaseHTTPMiddleware
11-
from auth import fetch_jwks_public_key, verify_auth
12-
from models import Auth0Settings
13-
from sandbox.routes import get_sandbox_api_router
14-
from helpers import get_logger
12+
from .auth import fetch_jwks_public_key, verify_auth
13+
from .models import Auth0Settings
14+
from .sandbox.routes import get_sandbox_api_router
15+
from .helpers import get_logger
1516

1617
logger = get_logger(__name__)
1718

@@ -71,6 +72,23 @@ async def dispatch(self, request, call_next):
7172
return response
7273

7374

75+
def close_on_double_start(app):
76+
async def wrapped(scope, receive, send):
77+
start_sent = False
78+
79+
async def check_send(message):
80+
nonlocal start_sent
81+
if message["type"] == "http.response.start":
82+
if start_sent:
83+
raise get_cancelled_exc_class()()
84+
start_sent = True
85+
await send(message)
86+
87+
await app(scope, receive, check_send)
88+
89+
return wrapped
90+
91+
7492
def run():
7593
app = FastAPI(title="SandboxApiMCP", lifespan=lifespan)
7694
app.include_router(get_sandbox_api_router())

0 commit comments

Comments
 (0)