Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4fc6271
Wire up get_trs_info and list_tool_classes against Dockstore's TRS API
denis-yuen Sep 22, 2026
3551d54
Copy push-confirmation and minimal-diff PR guidance from dockstore/do…
denis-yuen Sep 22, 2026
0c8876a
Potential fix for pull request finding 'Unused global variable'
denis-yuen Sep 24, 2026
2e2fc58
Add the remaining GA4GH TRS V2 tool, version, and file tools
denis-yuen Sep 23, 2026
3524c88
Send a dockstore-mcp/<git ref> User-Agent with TRS requests
denis-yuen Sep 23, 2026
505973c
Report totals from list_tools/search_tools and support notebooks
denis-yuen Sep 23, 2026
a2c1930
Add a summary option to list_tools and search_tools
denis-yuen Sep 23, 2026
62e6e69
Cap version names in list_tools/search_tools summaries
denis-yuen Sep 24, 2026
825c0f2
Add a summary option to list_tool_versions
denis-yuen Sep 24, 2026
118247a
Merge list_tool_classes into get_trs_info
denis-yuen Sep 24, 2026
cd2c9a0
Fold the TRS file tools into get_tool_descriptor_by_path
denis-yuen Sep 24, 2026
35dc77b
Fold hello into get_trs_info with a local_only option
denis-yuen Sep 24, 2026
f302dd4
Merge remote-tracking branch 'origin/develop' into feature/trim_tools
denis-yuen Sep 25, 2026
90eb58c
Fold get_tool_files into get_tool_version
denis-yuen Sep 25, 2026
71c36d3
Fold search_tools into list_tools
denis-yuen Sep 25, 2026
304d462
Fold list_tool_versions into get_tool
denis-yuen Sep 25, 2026
5efb5ce
Keep a version's metadata when its file listing fails
denis-yuen Sep 25, 2026
d161d1f
Mark which tools are implemented in the README's tool table
denis-yuen Sep 25, 2026
12f826c
Merge ToolDetail into Tool
denis-yuen Sep 25, 2026
e6ec87d
Call the project a prototype without search, not a scaffold
denis-yuen Sep 25, 2026
5f5c542
Report the git ref as the server's version when it is set
denis-yuen Sep 25, 2026
f0da6f0
Run CI and the release build on Ubuntu 26.04
denis-yuen Sep 25, 2026
6c162d6
Merge branch 'develop' into feature/trim_tools
denis-yuen Sep 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ DOCKSTORE_MCP_LOG_LEVEL=INFO

# The Dockstore instance whose APIs this server exposes.
DOCKSTORE_MCP_DOCKSTORE_URL=https://dockstore.org

# Git tag or ref reported in the User-Agent sent to Dockstore. Normally set at
# build time; left unset, the package version is used.
# DOCKSTORE_MCP_GIT_REF=
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
jobs:
test:
name: Test (Python ${{ matrix.python-version }})
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
strategy:
fail-fast: false
matrix:
Expand All @@ -34,7 +34,7 @@ jobs:

git-secrets:
name: git-secrets scan
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
steps:
- uses: actions/checkout@v7
- name: Install git-secrets
Expand All @@ -51,7 +51,7 @@ jobs:

docker:
name: Build image
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
steps:
- uses: actions/checkout@v7
- name: Build
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/deploy_tagged.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:

build:
needs: ci
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04

permissions:
id-token: write
Expand Down Expand Up @@ -55,6 +55,7 @@ jobs:
context: .
load: true
tags: quay.io/dockstore/dockstore-mcp:${{ steps.ref.outputs.sanitized }}
build-args: GIT_REF=${{ steps.ref.outputs.sanitized }}

# Test the exact image about to be published, not just the one CI built
- name: Smoke test
Expand Down
7 changes: 4 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ An MCP (Model Context Protocol) server, built on FastMCP 4, that exposes Docksto
assistants. It is a standalone process deployed alongside the Dockstore webservice,
talking to Dockstore's GA4GH Tool Registry Service (TRS) API and its own proprietary API.

**Status: scaffold.** Only the `hello` tool has a working body. The four Dockstore
**Status: prototype without search.** The GA4GH TRS tools in `trs.py` have working bodies. The four Dockstore
tools (`search_entries`, `get_entry`, `get_version`, `get_file`) are fully declared
(names, arguments, response models, docstrings) but each raises `NotImplementedError`
until wired up to the real Dockstore API.
Expand All @@ -31,7 +31,7 @@ Run a single test with pytest directly (no Makefile target for this):

```bash
.venv/bin/pytest tests/test_tools.py::test_search_takes_every_facet
.venv/bin/pytest -k "hello"
.venv/bin/pytest -k "trs_info"
```

Tests use FastMCP's in-memory `Client`/`FastMCP` pairing (see `tests/conftest.py`), so
Expand Down Expand Up @@ -94,7 +94,8 @@ back from the installed package's metadata at runtime (`importlib.metadata.versi
- `src/dockstore_mcp/tools/` — one module per cohesive tool group, each exposing
`register(mcp: FastMCP, settings: Settings) -> None`. `tools/__init__.py`'s
`register_all` calls each in turn; new tool modules must be added there.
- `hello.py` — smoke-test tool, implemented.
- `trs.py` — the GA4GH TRS tools, implemented. `get_trs_info(local_only=True)` doubles as a
smoke test that never contacts Dockstore.
- `search.py` — `search_entries`, the Dockstore Search page equivalent.
- `entries.py` — `get_entry` → `get_version` → `get_file`, a lookup chain: an
entry's `version_ids` feed `get_version`, whose `file_paths` feed `get_file`.
Expand Down
7 changes: 6 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ RUN pip install . \
# ---- runtime --------------------------------------------------------------
FROM python:3.13-alpine3.24

# Git tag or ref the image is built from, reported in the User-Agent sent to
# Dockstore. Left empty, the server falls back to the package version.
ARG GIT_REF=""

LABEL org.opencontainers.image.title="dockstore-mcp" \
org.opencontainers.image.description="Model Context Protocol server for Dockstore" \
org.opencontainers.image.url="https://dockstore.org" \
Expand All @@ -56,7 +60,8 @@ ENV PATH="/opt/venv/bin:${PATH}" \
DOCKSTORE_MCP_HOST=0.0.0.0 \
DOCKSTORE_MCP_PORT=8000 \
DOCKSTORE_MCP_PATH=/mcp \
DOCKSTORE_MCP_DOCKSTORE_URL=https://dockstore.org
DOCKSTORE_MCP_DOCKSTORE_URL=https://dockstore.org \
DOCKSTORE_MCP_GIT_REF=${GIT_REF}

USER dockstore
WORKDIR /home/dockstore
Expand Down
8 changes: 5 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ VENV ?= .venv
PY ?= $(VENV)/bin/python
PIP ?= $(VENV)/bin/pip
IMAGE ?= dockstore/dockstore-mcp:local
# Reported in the User-Agent the server sends to Dockstore.
GIT_REF ?= $(shell git describe --tags --always 2>/dev/null)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This git ref business is to hook-up the user agent version to the mcp version which we will also expose in Slack deploy messages and the footer


help: ## Show this help
@grep -hE '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-14s\033[0m %s\n", $$1, $$2}'
Expand Down Expand Up @@ -35,13 +37,13 @@ typecheck: ## Run the type checker
check: lint typecheck test ## Everything CI runs

run: ## Run the server over stdio
$(VENV)/bin/dockstore-mcp
DOCKSTORE_MCP_GIT_REF=$(GIT_REF) $(VENV)/bin/dockstore-mcp

run-http: ## Run the server over HTTP on port 8000
$(VENV)/bin/dockstore-mcp --transport http --port 8000
DOCKSTORE_MCP_GIT_REF=$(GIT_REF) $(VENV)/bin/dockstore-mcp --transport http --port 8000

docker-build: ## Build the container image
docker build -t $(IMAGE) .
docker build --build-arg GIT_REF=$(GIT_REF) -t $(IMAGE) .

docker-run: ## Run the container image on port 8000
docker run --rm -p 8000:8000 $(IMAGE)
Expand Down
57 changes: 33 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ MCP, so it is deployed alongside the Dockstore webservice rather than inside it.

It is built on [FastMCP](https://gofastmcp.com) 4 and ships as a container image.

> **Status: scaffold.** `hello`, `get_trs_info`, and `list_tool_classes` have working
> bodies; the other four Dockstore tools are declared — names, arguments, and response
> shapes — but each one raises `NotImplementedError` until it is wired up to the
> Dockstore API.
> **Status: prototype without search.** The GA4GH TRS tools (`get_trs_info` through
> `get_tool_descriptor_by_path`) have working bodies; the other four Dockstore tools are
> declared — names, arguments, and response shapes — but each one raises
> `NotImplementedError` until it is wired up to the Dockstore API.

## Requirements

Expand Down Expand Up @@ -116,29 +116,39 @@ over the environment.
| `DOCKSTORE_MCP_PATH` | `--path` | `/mcp` | Path the MCP endpoint is served from |
| `DOCKSTORE_MCP_LOG_LEVEL` | `--log-level` | `INFO` | Logging verbosity |
| `DOCKSTORE_MCP_DOCKSTORE_URL` | `--dockstore-url` | `https://dockstore.org` | Dockstore instance whose APIs are exposed |
| `DOCKSTORE_MCP_GIT_REF` | | package version | Version in the `dockstore-mcp/<ref>` User-Agent |

The container image overrides the first four so that it listens on `0.0.0.0:8000` out of
the box. It also sets a few `FASTMCP_*` variables so that a deployed server logs plainly
and does not check PyPI for updates on startup; see the
[FastMCP settings](https://gofastmcp.com) for the full list.
the box, and sets `DOCKSTORE_MCP_GIT_REF` from its `GIT_REF` build argument, which the
release workflow and `make docker-build` fill in with the git tag or ref being built. It
also sets a few `FASTMCP_*` variables so that a deployed server logs plainly and does not
check PyPI for updates on startup; see the [FastMCP settings](https://gofastmcp.com) for
the full list.

## Tools

| Tool | Description |
| ------------------- | ------------------------------------------------------------------------------------- |

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is most useful for a breakdown of what the tools are and what they do

| `hello` | Greets the caller and reports the Dockstore instance and server version. No I/O. |
| `get_trs_info` | Describes this instance's GA4GH TRS API: identifiers, version, and operator. |
| `list_tool_classes` | Lists the tool classes (e.g. `Workflow`) this instance's TRS API sorts entries into. |
| `search_entries` | Searches entries by keyword and facet, the equivalent of the site's Search page. |
| `get_entry` | Retrieves the requested fields of one entry. |
| `get_version` | Retrieves the requested fields of one version of an entry. |
| `get_file` | Retrieves the requested fields of one file belonging to a version. |

`get_trs_info` and `list_tool_classes` call Dockstore's GA4GH TRS V2 API directly. The
last four are scaffolding and are not implemented yet. They are a chain: `search_entries`
yields entry identifiers, an entry yields version identifiers, and a version yields file
paths. Each lookup takes a list of fields so that a caller can ask for a name and a date
without also pulling down a README or a whole descriptor.
| Tool | Implemented | Description |
| ----------------------------- | ----------- | ------------------------------------------------------------------------------------ |
| `get_trs_info` | ✅ | Reports instance and version; unless `local_only`, also TRS info and tool classes. |
| `list_tools` | ✅ | Lists one page of TRS tools, optionally filtered by name, class, language, etc. |
| `get_tool` | ✅ | Retrieves one TRS tool by id, with all of its versions in full or summarized. |
| `get_tool_version` | ✅ | Retrieves one version of a TRS tool: authors, images, languages, optionally files. |
| `get_tool_descriptor_by_path` | ✅ | Fetches a version's primary descriptor, or any file get_tool_version lists, by path. |
| `search_entries` | ❌ | Searches entries by keyword and facet, the equivalent of the site's Search page. |
| `get_entry` | ❌ | Retrieves the requested fields of one entry. |
| `get_version` | ❌ | Retrieves the requested fields of one version of an entry. |
| `get_file` | ❌ | Retrieves the requested fields of one file belonging to a version. |

The TRS tools, from `get_trs_info` to `get_tool_descriptor_by_path`, call Dockstore's GA4GH
TRS V2 API directly. They form a chain: `list_tools` yields tool ids, a
tool yields version names, and `get_tool_version` with `files` yields the paths that
`get_tool_descriptor_by_path` takes. Pass `summary` to `list_tools` to get
each tool's id, languages, and version names without its full README and version details.

The last four are scaffolding and are not implemented yet. They are a chain too:
`search_entries` yields entry identifiers, an entry yields version identifiers, and a
version yields file paths. Each lookup takes a list of fields so that a caller can ask
for a name and a date without also pulling down a README or a whole descriptor.

## Layout

Expand All @@ -152,9 +162,8 @@ src/dockstore_mcp/
└── tools/
├── __init__.py registers every tool group
├── entries.py get_entry, get_version, get_file
├── hello.py the hello tool
├── search.py search_entries
└── trs.py get_trs_info, list_tool_classes
└── trs.py get_trs_info and the other GA4GH TRS tools
tests/ pytest suite, using FastMCP's in-memory client
Dockerfile two-stage build of the deployable image
```
Expand Down
20 changes: 20 additions & 0 deletions src/dockstore_mcp/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
from pydantic import Field, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict

from dockstore_mcp import __version__

Transport = Literal["stdio", "http"]
LogLevel = Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]

Expand Down Expand Up @@ -52,6 +54,14 @@ class Settings(BaseSettings):
description="Base URL of the Dockstore instance whose APIs this server exposes.",
)

git_ref: str | None = Field(
default=None,
description=(
"Git tag or ref this server was built from, e.g. '1.21.0'; set at build time. "
"Falls back to the package version."
),
)

@field_validator("dockstore_url")
@classmethod
def _strip_trailing_slash(cls, value: str) -> str:
Expand All @@ -74,6 +84,16 @@ def api_url(self) -> str:
"""Base URL of the instance's proprietary Dockstore API."""
return f"{self.dockstore_url}/api"

@property
def server_version(self) -> str:
"""Version this server reports: the git ref it was built from, else the package version."""
return self.git_ref or __version__

@property
def user_agent(self) -> str:
"""User-Agent sent with every request to Dockstore, e.g. 'dockstore-mcp/1.21.0'."""
return f"dockstore-mcp/{self.server_version}"


@lru_cache(maxsize=1)
def get_settings() -> Settings:
Expand Down
Loading
Loading