Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

44 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

laser-mcp

RAG-powered MCP (Model Context Protocol) servers for the LASER disease modeling framework. Provides two servers that allow Claude and other MCP-compatible tools to search LASER documentation and generate model code.

Overview

Three MCP servers are provided:

Server Container Default Port Purpose
jenner-mcp jenner-mcp 9765 General LASER core documentation
jenner-measles-mcp jenner-measles-mcp 9766 Measles-specific documentation
jenner-generic-mcp jenner-generic-mcp 9767 laser-generic modeling documentation

Server toolsets differ by target:

  • jenner-mcp

    • search(query) — semantic search over the indexed LASER core documentation
    • generate_code(prompt) — generates laser-core Python code using retrieved context + GPT
  • jenner-measles-mcp

    • search(query) — semantic search over the indexed measles documentation
    • generate_code(prompt) — generates laser-measles Python code using retrieved context + GPT
    • version_info() — returns server version, model, and vectorstore metadata
  • jenner-generic-mcp

    • search(query) — semantic search over the indexed laser-generic documentation
    • generate_code(prompt) — generates laser-generic Python code (imports laser.generic) using retrieved context + GPT
    • version_info() — returns server version, model, and vectorstore metadata

Prerequisites

  • Python 3.11
  • Docker (with daemon running)
  • An OpenAI API key (for embeddings and code generation)
  • Documentation sources (all checked into this repo): laser.pdf (core), laser-measles.pdf (measles), and laser-generic.md (laser-generic, header **laser-generic version: X.Y.Z**)

Setup

1. Configure your API key

Create a .env file in the project root:

OPENAI_API_KEY=sk-...

2. Documentation sources

Each server indexes its own documentation source, all checked into this repo:

Server Source Format
jenner-mcp (core) laser.pdf PDF (version from cover Release X.Y.Z)
jenner-measles-mcp laser-measles.pdf PDF (version from cover Release X.Y.Z)
jenner-generic-mcp laser-generic.md Markdown (version from header **laser-generic version: X.Y.Z**)

laser.pdf and laser-measles.pdf are static PDFs updated manually. laser-generic.md is generated by the build-combined-doc.yml workflow in the laser-generic repo and lands here via an auto-PR — see How the RAG Pipelines Work for the full flow.

3. Build the vectorstores

The ingest step runs entirely in Docker — no local virtual environment needed.

make ingest-core       # laser.pdf          -> vectorstore/
make ingest-measles    # laser-measles.pdf  -> vectorstore_measles/
make ingest-generic    # laser-generic.md   -> vectorstore_generic/
make ingest-all        # all three

# Override a source path if it lives elsewhere:
make ingest-measles MEASLES_PDF=/path/to/laser-measles.pdf
make ingest-generic GENERIC_MD=/path/to/laser-generic.md

4. Start the servers

make run-all           # start all three servers as Docker daemons
# or individually:
make run-core
make run-measles
make run-generic

5. Register the servers with Claude Code

claude mcp add jenner-mcp --transport http "http://localhost:9765/mcp"
claude mcp add jenner-measles-mcp --transport http "http://localhost:9766/mcp"
claude mcp add jenner-generic-mcp --transport http "http://localhost:9767/mcp"

After registration, restart Claude Code. The following tools will be available:

  • mcp__jenner-mcp__search / mcp__jenner-mcp__generate_code
  • mcp__jenner-measles-mcp__search / mcp__jenner-measles-mcp__generate_code
  • mcp__jenner-generic-mcp__search / mcp__jenner-generic-mcp__generate_code

Note: If ports 9765/9766/9767 are unavailable, override with PORT_CORE, PORT_MEASLES, and PORT_GENERIC (e.g. make run-core PORT_CORE=8080) and update the URLs above accordingly.

Connecting to the deployed services

The setup above runs the MCP servers locally in Docker (the alpha tier — where you iterate). The same servers are also deployed in AKS at beta (staging) and prod (stable) tiers, which you can point any MCP client at directly without running anything on your own machine.

Tier Core URL (jenner-mcp) Measles URL (jenner-measles-mcp) When to use
prod http://172.193.178.78/mcp https://jenner-laser-ingress.westus2.cloudapp.azure.com/mcp (TLS) Stable. Measles has a public HTTPS ingress with a Let's Encrypt cert — use that one.
beta http://48.192.48.32/mcp http://4.155.180.84/mcp Staging. New images land here first; use to validate changes before they go to prod.
legacy http://20.72.235.86/mcp http://48.192.9.70/mcp Older deployments kept around for backward compat. New clients should not use these.
alpha http://localhost:9765/mcp http://localhost:9766/mcp Whatever you're iterating on locally via the setup above.

Register with Claude Code

Naming convention: the bare names jenner-mcp and jenner-measles-mcp are used by register-local (the alpha tier — the canonical name every tool/prompt suite references). Beta and prod use explicit -beta and -prod suffixes so all three tiers can coexist without colliding in your MCP client config. If you'd rather have prod be your default jenner-mcp, register it by hand with the bare name (last example below) instead of running make register-prod.

# Prod (recommended for general use, registered with -prod suffix)
claude mcp add jenner-mcp-prod --transport http "http://172.193.178.78/mcp"
claude mcp add jenner-measles-mcp-prod --transport http "https://jenner-laser-ingress.westus2.cloudapp.azure.com/mcp"

# Beta (for testing changes before they ship to prod)
claude mcp add jenner-mcp-beta --transport http "http://48.192.48.32/mcp"
claude mcp add jenner-measles-mcp-beta --transport http "http://4.155.180.84/mcp"

# Prod under the bare name (if you don't want a local server and want prod to be the default)
claude mcp add jenner-mcp --transport http "http://172.193.178.78/mcp"
claude mcp add jenner-measles-mcp --transport http "https://jenner-laser-ingress.westus2.cloudapp.azure.com/mcp"

Or use the convenience make targets — they run the claude mcp add commands for you with the current URLs baked in:

make register-local     # register local Docker servers as jenner-mcp / jenner-measles-mcp (no suffix)
make register-beta      # register AKS beta servers as jenner-mcp-beta / jenner-measles-mcp-beta
make register-prod      # register AKS prod servers as jenner-mcp-prod / jenner-measles-mcp-prod

TLS coverage: Only the measles prod ingress (jenner-laser-ingress.westus2.cloudapp.azure.com) has a public TLS certificate. All other endpoints are plain HTTP — fine on a trusted network, not appropriate for public use.

Health check: curl -sS -o /dev/null -w "%{http_code}\n" "<mcp-url>" — a healthy MCP endpoint returns HTTP 406 (Not Acceptable, because curl doesn't send the MCP client's content negotiation headers). 200 would be wrong; connection-refused or 404 means the service is down or the URL is wrong.

IPs / hostnames are pinned in this README for discoverability. They're verified against kubectl get svc -n laser-ai on the laser-ai AKS cluster. If a row goes stale, the AKS topology is the source of truth — re-run the kubectl query and update this table.

Common Commands

make status            # show running containers
make logs-core         # tail logs for jenner-mcp
make logs-measles      # tail logs for jenner-measles-mcp
make stop-all          # stop and remove all containers

Run make help for the full reference.

Project Structure

laser-mcp/
├── main.py                # jenner-mcp server (core LASER)
├── main_measles.py        # jenner-measles-mcp server (measles)
├── main_generic.py        # jenner-generic-mcp server (laser-generic)
├── ingest.py              # vectorstore ingestion script
├── Dockerfile             # core server image
├── Dockerfile.measles     # measles server image
├── Dockerfile.generic     # laser-generic server image
├── Dockerfile.ingest      # ingest-only image
├── docker-compose.yml     # service definitions
├── Makefile               # all build/run/stop targets
├── requirements.txt       # Python dependencies
├── .env                   # API keys (not committed)
├── vectorstore/           # FAISS index for core LASER (generated)
├── vectorstore_measles/   # FAISS index for measles (generated)
├── vectorstore_generic/   # FAISS index for laser-generic (generated)
├── laser.pdf              # LASER core documentation
├── laser-measles.pdf      # measles documentation
├── laser-generic.md       # laser-generic documentation (combined markdown)
└── tests/                 # prompt test suites and validators

Updating a Vectorstore

When a documentation source changes, replace the source file in this repo and re-ingest. The run-* targets rebuild the Docker images, so the updated vectorstore is picked up automatically.

# Core: replace laser.pdf, then
make ingest-core   && make run-core

# Measles: replace laser-measles.pdf, then
make ingest-measles && make run-measles

# laser-generic: replace laser-generic.md, then
make ingest-generic && make run-generic

The docs version is extracted automatically during ingest — from the PDF cover (Release X.Y.Z) for core/measles, and from the markdown header (**laser-generic version: X.Y.Z**) for laser-generic — and recorded in <vectorstore>/ingest_metadata.json, surfaced by each server's version_info.

How the RAG Pipelines Work

Each server indexes its own documentation source. The flow is the same for all three: source file → Docker ingest → FAISS vectorstore → server image.

Core (jenner-mcp)

laser.pdf is a static PDF checked into this repo. Update it by replacing the file.

laser-core/
  (PDF export of LASER core documentation)
        │
laser-mcp/
  laser.pdf  ──────────────────────────────→ make ingest-core
                                                    │
                                          vectorstore/ (FAISS)
                                                    │
                                          jenner-mcp (Docker)

The docs version is extracted from the PDF cover (Release X.Y.Z) during ingest.

Measles (jenner-measles-mcp)

laser-measles.pdf is a static PDF checked into this repo. Update it by replacing the file.

laser-measles/
  (PDF export of laser-measles documentation)
        │
laser-mcp/
  laser-measles.pdf  ──────────────────────→ make ingest-measles
                                                    │
                                       vectorstore_measles/ (FAISS)
                                                    │
                                       jenner-measles-mcp (Docker)

The docs version is extracted from the PDF cover (Release X.Y.Z) during ingest.

laser-generic (jenner-generic-mcp)

laser-generic.md is a generated artifact produced by the build-combined-doc.yml GitHub Actions workflow in the laser-generic repo. The workflow runs make docs-jenner, which:

  1. Executes every docs/**/*.ipynb notebook via nbconvert (into dist/executed_nbs/).
  2. Builds the MkDocs HTML site from docs/*.md pages, the API reference (mkdocstrings over src/**/*.py docstrings), and the executed notebooks.
  3. Flattens the rendered site + executed notebooks into a single combined markdown via docs/concat_mkdocs.py.
  4. Opens an auto-PR in this repo that copies the result to laser-generic.md (branch auto/sync-laser-generic-doc).
laser-generic/
  docs/**/*.ipynb    ─→ nbconvert --execute ─→ dist/executed_nbs/
                                                       │
  docs/*.md          ──────────────────────────────────┤
  src/**/*.py                                          │
   (docstrings)       ─→ mkdocs build                  │
                              │                        │
                       dist/site/ (HTML)               │
                              │                        │
                              └──────→ concat_mkdocs.py ← (executed nbs)
                                              │
                                    dist/combined_mkdocs.md    ← auto-PR handoff
                                              │
laser-mcp/                                    │
  laser-generic.md  ←──────────────────────┘
        │
  make ingest-generic
        │
  vectorstore_generic/ (FAISS)
        │
  jenner-generic-mcp (Docker)

The docs version comes from the **laser-generic version: X.Y.Z** header in the combined markdown, which reflects laser.generic.__version__ at CI build time.

To refresh after a laser-generic docs or code change:

  1. Trigger build-combined-doc.yml in the laser-generic repo (workflow dispatch).
  2. Merge the auto-PR into this repo.
  3. make ingest-generic && make run-generic

About

Model Context Protocol Server for LASER

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages