Skip to main content
Glama

NiChart DLMUSE MCP server

Hosts cbica/nichart_dlmuse (T1 MRI skull-strip + MUSE ROI segmentation) behind an MCP server on a GPU EC2 instance, so Claude Code can run segmentations remotely instead of every user needing a local GPU.

Why it's shaped this way

MCP tool arguments are JSON. A .nii.gz is tens of MB of binary, and segmentation takes ~1-2 minutes on GPU — too slow and too large for a single blocking tool call. So:

  • File transfer happens outside the MCP protocol, over a plain authenticated POST /upload endpoint. Only a small upload_id ever flows through an MCP tool argument.

  • Jobs are async: run_dlmuse_segmentation enqueues and returns immediately; get_job_status polls; get_job_result fetches the CSV inline plus download links for the mask files.

  • One worker, serialized: it's one shared GPU, so only one docker run executes at a time, queued behind an asyncio.Queue.

  • Bearer-token auth per team member on every endpoint except /healthz.

  • Private instance, no public web tier: the app binds only 127.0.0.1, and the security group opens nothing but SSH (22). Users reach it by SSH port-forwarding their laptop into that loopback port with their private key — there is no domain and nothing internet-facing to attack.

  • TLS is a self-signed cert, generated once on the instance, since a publicly-issued cert (Let's Encrypt, etc.) requires the instance to be reachable from the internet for domain validation, which this one isn't. Each user trusts that one cert on their laptop (see below).

  • Scans don't live forever: uploads and job outputs are deleted after RETENTION_HOURS (default 24h).

Architecture

Claude Code (laptop)                    SSH tunnel                  EC2 (private, SG: 22 only)
  │  ssh -i key.pem -L 8420:127.0.0.1:8420 user@instance ─────────────────►  │
  │                                                                          │
  │  1. curl https://127.0.0.1:8420/upload ─────(via tunnel)──────────►  MCP server :8420 (127.0.0.1, self-signed TLS)
  │  2. run_dlmuse_segmentation ────────────────(via tunnel)──────────►         │
  │  3. get_job_status (poll) ──────────────────(via tunnel)──────────►  asyncio job queue (1 worker)
  │  4. get_job_result ─────────────────────────(via tunnel)──────────►         │
                                                                   docker run --gpus all cbica/nichart_dlmuse

Repo layout

server/app.py     MCP tools (run_dlmuse_segmentation, get_job_status, get_job_result)
                  + HTTP routes (/upload, /download/{job_id}/{filename}, /healthz)
server/jobs.py    job queue/worker, docker invocation, root-owned-output cleanup
server/auth.py    bearer-token ASGI middleware
server/config.py  env-driven settings
deploy/           EC2 provisioning script (installs Docker, GPU toolkit, self-signed cert, systemd unit)

One-time EC2 setup

Requires an existing GPU EC2 instance (AWS Deep Learning AMI recommended — NVIDIA driver and Docker are usually already installed).

  1. Copy this repo onto the instance (git clone / scp -r).

  2. cp .env.example .env and fill in at least TOKENS — one name:token pair per team member, comma-separated. Generate tokens with openssl rand -hex 32.

  3. In the instance's security group: allow inbound 22 (SSH) only, restricted to your team's IPs or a bastion. Open nothing else — no 443, no 8420. The app binds 127.0.0.1 and is never reachable except through an SSH tunnel.

  4. Run the provisioning script:

    sudo ./deploy/setup_ec2.sh

    It's idempotent — installs Docker/nvidia-container-toolkit only if missing, pulls the DLMUSE image, creates a dedicated nichart-mcp service user, deploys the code to /opt/nichart-mcp, generates a self-signed TLS cert (SAN = 127.0.0.1/localhost), and installs the nichart-mcp systemd service.

  5. Verify, from the instance itself:

    curl --cacert /opt/nichart-mcp/tls/server.crt https://127.0.0.1:8420/healthz
  6. Copy /opt/nichart-mcp/tls/server.crt off the instance so you can hand it to each team member (e.g. scp -i key.pem ec2-user@<instance-ip>:/opt/nichart-mcp/tls/server.crt .).

To add or revoke a user later: edit TOKENS in /opt/nichart-mcp/.env on the instance, then sudo systemctl restart nichart-mcp.

Updating the code

Re-run sudo ./deploy/setup_ec2.sh from an updated checkout on the instance — it re-syncs /opt/nichart-mcp (leaving the existing TLS cert alone), reinstalls dependencies, and restarts the service.

Connecting from a laptop

Each team member needs: their SSH private key (for a Windows PuTTY .ppk key, convert it once with puttygen key.ppk -O private-openssh -o key.pem so the standard ssh client can use it), their bearer token, and the server.crt file from setup step 6.

1. Trust the self-signed cert once, so curl/Claude Code stop rejecting it:

  • macOS: security add-trusted-cert -d -r trustRoot -k ~/Library/Keychains/login.keychain-db server.crt

  • Linux: sudo cp server.crt /usr/local/share/ca-certificates/nichart-mcp.crt && sudo update-ca-certificates

  • Windows: certutil -addstore -f "ROOT" server.crt

2. Open the SSH tunnel (leave this running in a terminal while using Claude Code):

ssh -i key.pem -N -L 8420:127.0.0.1:8420 <ssh_user>@<instance-ip>

If the instance has no public IP and you only reach it through a bastion, add -J <bastion_user>@<bastion_host>.

3. Register the MCP server with Claude Code, once:

claude mcp add --transport http nichart-dlmuse https://127.0.0.1:8420/mcp \
  --header "Authorization: Bearer <their-token>"

Using it

With the tunnel open, ask Claude Code to segment a scan; it will:

  1. Upload the file (through the tunnel, so 127.0.0.1:8420 is correct even though the file is headed for the remote instance):

    curl -X POST -H "Authorization: Bearer <token>" \
      -F "file=@/path/to/scan.nii.gz" \
      https://127.0.0.1:8420/upload
    # -> {"upload_id": "..."}
  2. Call the run_dlmuse_segmentation tool with that upload_id -> gets a job_id.

  3. Poll get_job_status(job_id) until status == "done" (typically ~1-2 min on GPU).

  4. Call get_job_result(job_id) -> ROI volumes CSV inline, plus /download/{job_id}/{filename} links for the ICV and MUSE mask NIfTI files (fetch those from https://127.0.0.1:8420/download/... with the same bearer token, through the same tunnel).

Operating notes

  • GPU concurrency: one job runs at a time by design (single shared GPU). A busy team will see jobs queue; get_job_status reports queue_position.

  • Job state is in-memory: a systemctl restart nichart-mcp loses in-flight job records (the uploaded scan and any partial output on disk are unaffected, but you'd need to resubmit). Fine at small-team scale; if you outgrow it, swap the in-memory dict in server/jobs.py for Redis/RQ.

  • PHI: scans are real patient data. RETENTION_HOURS bounds how long they sit on disk, but confirm that's compatible with your data-handling requirements before pointing this at real patients. Consider enabling EBS encryption on the instance's volume if you haven't already.

  • The DLMUSE container runs as root inside (it hardcodes writes to /app/pipeline.log, so it can't run under --user). Its output ends up root-owned; server/jobs.py's cleanup falls back to a throwaway alpine container to force-remove those directories.

Local development

python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
cp .env.example .env   # fill in TOKENS
TOKENS=dev:devtoken DATA_DIR=/tmp/nichart-dev .venv/bin/python -m server.app

This runs the full server (auth, upload, job queue, MCP tools) locally. Actually running a segmentation still requires Docker with GPU access — on a machine without a GPU, jobs will fail at the docker run step but everything else (routing, auth, queueing, status/error reporting) is exercisable.

-
license - not tested
-
quality - not tested
-
maintenance - not tested

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Remote MCP server for RunComfy Serverless API (ComfyUI): deployments and async inference.

  • Cloud-hosted MCP server for durable AI memory

  • Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/euroso97/DLMUSE_MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server