Skip to main content
Glama
README.md
# MGnify MCP Server

An MCP (Model Context Protocol) server exposing the [MGnify v2 (EBI Metagenomics) API](https://www.ebi.ac.uk/metagenomics/api/v2/) as **23 typed tools** an LLM can call directly. Ships with stdio transport for desktop clients and Streamable HTTP transport for Kubernetes deployments, plus health/metrics endpoints and an end-to-end evaluation harness.

## What it gives you

- **23 tools** covering biomes, studies, super-studies, samples, runs, analyses, typed annotations (taxonomies + pfams), genome catalogues, genomes, publications.
- **Two transports**: `stdio` (Claude Desktop, IDE clients) and HTTP Streamable at `/mcp` (web/k8s).
- **Production endpoints**: `/healthz` (liveness), `/readyz` (verifies upstream MGnify), `/metrics` (Prometheus text — per-tool call/error counters).
- **Resilient client**: retries on 5xx, surfaces 429 with `Retry-After`, clamps page sizes; passes through v2's clean `{count, items[]}` shape unchanged.
- **K8s manifests**: Deployment with proper probes, HPA, PDB, ConfigMap, optional Secret, Ingress with streaming-friendly nginx annotations, kustomize entrypoint.
- **Evaluation harness**: 10 verifiable questions, a fast fact-check script, and an LLM-driven runner that measures pass rate, tool calls, latency, tokens.
- **Perf benchmark** for capacity planning (p50/p95/p99 latency, throughput).

## Quick start (local stdio)

```bash
python3 -m venv .venv && source .venv/bin/activate
pip install -e .
cp .env.example .env
python scripts/smoke_test.py     # confirm upstream API works
mgnify-mcp                       # stdio MCP server
```

Add it to Claude Desktop's `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "mgnify": {
      "command": "/abs/path/to/.venv/bin/mgnify-mcp",
      "env": { "MG_BASE_URL": "https://www.ebi.ac.uk/metagenomics/api/v2" }

    }
  }
}
```

## Quick start (HTTP / Docker)

```bash
docker compose up --build
curl http://127.0.0.1:8173/healthz
curl http://127.0.0.1:8173/readyz
curl http://127.0.0.1:8173/metrics
```

MCP clients connect to `http://127.0.0.1:8173/mcp` over Streamable HTTP.

## Kubernetes deployment

```bash
# 1. Build & push image
make build push REGISTRY=your-registry TAG=v0.2.0

# 2. Point the deployment at it
( cd k8s && kustomize edit set image your-registry/mgnify-mcp=your-registry/mgnify-mcp:v0.2.0 )

# 3. Deploy
kubectl apply -k k8s/
kubectl rollout status deployment/mgnify-mcp

# 4. Verify
kubectl port-forward svc/mgnify-mcp 8173:80 &
curl http://127.0.0.1:8173/healthz
```

Manifests included: `deployment.yaml` (probes + non-root + read-only FS), `service.yaml`, `ingress.yaml` (streaming-friendly), `configmap.yaml`, `hpa.yaml` (CPU+memory autoscale 2→8), `pdb.yaml` (`minAvailable: 1`), `secret.yaml` (optional MG_API_KEY).

See `DEPLOYMENT.md` for the long-form runbook.

## Measuring effectiveness

Two complementary checks.

### 1. Fact check (fast, no LLM)

Confirms the 10 expected answers still match upstream MGnify. Run this on a schedule (CI cron) to catch silent staleness.

```bash
python evals/check_facts.py
```

### 2. End-to-end LLM evaluation

Drives a real Claude model against the running MCP server. The model must answer each question by composing tool calls. This is the headline quality metric — if a capable model can't reliably answer, the tools or descriptions are wrong.

```bash
export ANTHROPIC_API_KEY=sk-...
pip install -e '.[eval]'
# Server must be running on HTTP transport
python evals/run_eval.py \
  --server-url http://127.0.0.1:8173/mcp \
  --model claude-opus-4-7 \
  --report eval-report.json
```

Reports pass rate, average latency per question, average tool calls used, and tokens consumed. Treat <90% pass rate as a regression.

### 3. Latency / throughput benchmark

For capacity planning before bumping replicas or HPA targets:

```bash
python scripts/perf_test.py \
  --server-url http://127.0.0.1:8173/mcp \
  --tool mgnify_list_studies \
  --concurrency 20 --requests 200
```

Reports p50/p95/p99 latency, throughput (req/s), error rate. Most latency comes from the upstream MGnify API (~1–2s typical), so set readiness/liveness timeouts accordingly.

## Tool catalogue

Biomes (1) · Studies (5) · Super-studies (2) · Samples (3) · Runs (3) · Analyses (3) · Genome catalogues & genomes (4) · Publications (2). All named `mgnify_*` with Pydantic-validated inputs.

List them at runtime:
```bash
python -c "import asyncio; from mgnify_mcp.server import mcp; \
  print('\n'.join(t.name for t in asyncio.run(mcp.list_tools())))"
```

## Environment variables

| Var | Default | Purpose |
|---|---|---|
| `MG_BASE_URL` | `https://www.ebi.ac.uk/metagenomics/api/v2` | Upstream MGnify API |
| `MG_API_KEY` | _(empty)_ | Optional bearer token |
| `MCP_TRANSPORT` | `stdio` | `stdio` or `http` |
| `MCP_HOST` | `0.0.0.0` | HTTP bind host |
| `MCP_PORT` | `8173` | HTTP bind port |
| `MCP_CORS_ORIGINS` | `*` | Comma-separated allowed origins |
| `LOG_LEVEL` | `info` | uvicorn log level |

## Endpoints

- `POST /mcp` — Streamable HTTP MCP transport
- `GET /healthz` — Liveness (always 200 if the process is alive)
- `GET /readyz` — Readiness (verifies upstream MGnify reachable)
- `GET /metrics` — Prometheus text (`mgnify_mcp_tool_calls_total`, `mgnify_mcp_tool_errors_total`, `mgnify_mcp_uptime_seconds`)

## Project layout

```
mgnify_mcp/         # the server package
  server.py         # FastMCP server + FastAPI wrapper
  mgnify_client.py  # HTTP client with retries against MGnify v2 OpenAPI surface
  schemas.py        # Pydantic input schemas
evals/              # evaluation harness
  questions.xml     # 10 verifiable Q&A pairs
  check_facts.py    # direct-API fact check (no LLM)
  run_eval.py       # LLM-driven E2E eval
scripts/
  smoke_test.py     # quick upstream-API sanity check
  perf_test.py      # latency / throughput benchmark
  build-and-push.sh, deploy.sh
k8s/                # Deployment, Service, Ingress, HPA, PDB, ConfigMap, Secret
```

## License

See `LICENSE` (if present) or the repository hosting service.

TDQS

A3.6/5.0

Scored across 23 tools

Disambiguation5/5

Every tool targets a distinct entity or relationship: list/get variants for studies, samples, runs, analyses, genomes, catalogues, publications, biomes, and super-studies. Where multiple tools list analyses, their scoping (all, by study, by run) is explicit in descriptions, so an agent should not confuse them.

Naming Consistency4/5

The set consistently uses the mgnify_ prefix and snake_case, with list_X/get_X for most resources. The relational endpoints (mgnify_study_analyses, mgnify_sample_runs) and the single mgnify_analysis_annotations deviate from the list/get convention, but the pattern is still predictable.

Tool Count4/5

23 tools is above the typical sweet spot, but the domain spans many entity types and each tool maps to a distinct API operation. It is slightly heavy but not bloated.

Completeness5/5

The read-only domain is covered end-to-end: every core entity has a list and get tool, and relationship tools allow traversal from super-studies/studies to samples to runs to analyses, plus genome catalogues and publications. No obvious dead ends or missing operations for the stated browse/search purpose.

Maintenance

ActivityInactive
ResponsivenessNo issues