Skip to content
dockstorePublic

About

Dockstore MCP Interface

Resources

Code of conduct

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Dockstore MCP Server

license

An MCP (Model Context Protocol) server that exposes Dockstore to AI assistants and other MCP clients.

Dockstore is a registry of bioinformatics tools and workflows described in CWL, WDL, Nextflow, and Galaxy. It serves them through the GA4GH Tool Registry Service (TRS) API and through Dockstore's own API. This server is a standalone process that sits in front of those APIs and speaks MCP, so it is deployed alongside the Dockstore webservice rather than inside it.

It is built on FastMCP 4 and ships as a container image.

Status: early. All of the tools work: the GA4GH TRS tools (get_trs_info through get_tool_descriptor_by_path) and the four Dockstore tools (search_entries, get_entry, get_version, and get_file).

Requirements

  • Python 3.11 or newer (the container image uses 3.13)
  • Docker, if you want to build or run the image

Quick start

make install          # create .venv and install the package plus dev dependencies
make test             # run the test suite
make run              # start the server on stdio

Or without make:

python3 -m venv .venv && .venv/bin/pip install -e '.[dev]'
.venv/bin/dockstore-mcp --help

Running the server

The server supports the two standard MCP transports.

stdio — the client launches the server as a subprocess. This is how desktop MCP clients normally work:

dockstore-mcp --transport stdio

HTTP — the server runs as a long-lived service, which is how it is deployed:

dockstore-mcp --transport http --host 0.0.0.0 --port 8000

Over HTTP it serves two paths:

Path Purpose
/mcp The MCP endpoint (stateless streamable HTTP)
/health Liveness probe, returns {"status": "ok", ...}

With a container

docker build -t dockstore/dockstore-mcp:local .
docker run --rm -p 8000:8000 \
  -e DOCKSTORE_MCP_DOCKSTORE_URL=https://qa.dockstore.org \
  dockstore/dockstore-mcp:local

The image defaults to the HTTP transport on port 8000 and runs as a non-root user. A docker-compose.yml is included for local runs against a Dockstore webservice on your machine:

DOCKSTORE_URL=http://host.docker.internal:8080 docker compose up --build

With an MCP client

To use a local checkout from a client that launches servers itself, point it at the entry point. For example, in Claude Desktop's claude_desktop_config.json:

{
  "mcpServers": {
    "dockstore": {
      "command": "/path/to/mcp/.venv/bin/dockstore-mcp",
      "env": { "DOCKSTORE_MCP_DOCKSTORE_URL": "https://dockstore.org" }
    }
  }
}

To connect to a running HTTP deployment instead, point the client at https://<host>/mcp. In Claude Code that is:

claude mcp add --transport http dockstore https://<host>/mcp

Configuration

Every option can be set with a DOCKSTORE_MCP_-prefixed environment variable, in a .env file (see .env.example), or with a command line flag. Flags win over the environment.

Variable Flag Default Meaning
DOCKSTORE_MCP_TRANSPORT --transport stdio stdio or http
DOCKSTORE_MCP_HOST --host 127.0.0.1 Interface to bind, HTTP only
DOCKSTORE_MCP_PORT --port 8000 Port to bind, HTTP only
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, 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 for the full list.

Tools

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 a page 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 one entry, with its versions and description limited by default.
get_version ✅ Retrieves one version of an entry, with its file paths limited by default.
get_file ✅ Retrieves one file belonging to a version, with its content limited by default.

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 other four are a chain too: search_entries yields entry identifiers, an entry yields its versions, and a version yields file paths. get_entry returns at most version_limit versions (20 by default), in the order Dockstore ranks them (the default version first), and at most description_limit characters of the description (5,000 by default); setting either limit to null returns them in full. get_version returns at most file_limit file paths (100 by default), the primary descriptor first; null returns them all. get_file returns at most content_limit characters of the file (50,000 by default); null returns the whole file.

search_entries sends an Elasticsearch query to Dockstore's TRS extension, POST /api/ga4gh/v2/extended/tools/entry/_search, which searches the same index as the site's Search page. Keywords are ranked with the Search page's weights. The entry type, descriptor language, author, and EDAM facets (subject area, operation, and input and output data and formats) are filters. Keywords, author, and EDAM facets are written in Lucene query syntax and sent as query_string queries. Results can be sorted by relevance (with keywords, the square of the Elasticsearch score times the natural log of 1.05 plus the entry's indexed relevance), name, stars, last update, or execution count (the Search page's "Most Used"), and a call returns up to 200 of them (20 by default) along with the total number that matched. Each result carries the entry's categories and EDAM facets as the index files them, so they cost no extra request. Services are not indexed, so they cannot be searched for.

Entries and versions are identified by their GA4GH TRS identifiers, which every tool reports as id. An entry's is its path behind a prefix naming its kind (#workflow/github.com/org/repo/name, #notebook/…, #service/…), or its bare path for a tool or an apptool (quay.io/org/repo). A version's is its entry's TRS identifier and its name joined by a colon (#workflow/github.com/org/repo/name:v1.0).

get_entry takes an entry's TRS identifier and reads the entry from the webservice by its path. The prefix says which kind of entry the workflow endpoint should look for; an identifier with no prefix is looked for among tools first and apptools second, since the two share that form. It then fetches the categories the entry is filed under, from which it derives the entry's EDAM facets.

get_version takes a version's TRS identifier and asks the webservice to map it to Dockstore's own entry and version ids (GET /api/entries/mapTrsVersionId), which finds only published entries and versions that are not hidden. It then reads the version by those ids — from /api/containers/published/{id}/tags/{tagId} for a tool, falling back to /api/workflows/published/{id}/workflowVersions/{versionId} for everything else. Alongside that, it asks TRS (/api/ga4gh/trs/v2/tools/{id}/versions/{version_id}) which descriptor types the version has, and lists the files for each type from .../{type}/files. File paths are the relative paths TRS reports, merged across types, and the language is that of the first type whose listing includes a primary descriptor.

get_file takes a version's TRS identifier and a path from get_version. It lists the version's files from TRS the same way, finds the first descriptor type whose listing has the path, which says what kind of file it is, and then reads the file from .../{type}/descriptor/{relative_path}, with the path percent-encoded as one segment. That endpoint serves any of a version's files, not only descriptors.

Layout

src/dockstore_mcp/
├── __main__.py      command line entry point (`dockstore-mcp`)
├── api.py           HTTP client for the Dockstore webservice
├── casing.py        camelCase JSON -> snake_case models, for API-backed tools
├── config.py        settings, read from the environment
├── models.py        entry, version, and file types shared by the tools
├── server.py        server construction, /health route
└── tools/
    ├── __init__.py  registers every tool group
    ├── entries.py   get_entry, get_version, get_file
    ├── search.py    search_entries
    └── 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

Adding a tool

Add a module under src/dockstore_mcp/tools/ that exposes register(mcp: FastMCP, settings: Settings, api: DockstoreApi) -> None, and call it from register_all in tools/__init__.py. Group related tools in one module. The api argument is the shared HTTP client; reach Dockstore through it rather than opening a connection of your own, so that calls reuse the connection pool and the server can close it on shutdown.

Keep tool docstrings written for the model that will read them: say what the tool returns and when to reach for it. Note that FastMCP can also generate tools directly from an OpenAPI specification (FastMCP.from_openapi), which may be the right way to cover large parts of the Dockstore API.

Keeping in step with the webservice and UI2

This server is a client of the webservice. The tools call its REST and TRS endpoints and read their JSON, and search_entries sends queries to the Elasticsearch index that the webservice builds. search_entries also reproduces the Search page of UI2: its field boosts and path matching follow UI2's QueryBuilderService, and its relevance scoring is meant to match UI2's, so results come back in the order the site shows them.

When either repository changes something these tools depend on, update this one to match:

  • Webservice payloads or endpoints: update the affected tool and its model in models.py, and refresh the trimmed payloads in tests/fake_dockstore.py. The daily smoke tests (make smoke) run against dockstore.org and catch drift that the fake can't.
  • Index fields or categories: update the field lists at the top of tools/search.py. The search module's docstring explains how to add a new kind of category.
  • UI2's search boosts or scoring: carry the change over to _QUERY_FIELDS, _PATH_BOOST, or _RELEVANCE_SCRIPT in tools/search.py.

Development

make check      # lint, type check, and test
make format     # apply ruff formatting and safe fixes

Tests use FastMCP's in-memory client, so they exercise real tool dispatch without starting a server or opening a socket. Tools that call Dockstore are pointed at tests/fake_dockstore.py, which answers from trimmed copies of real payloads and records what it was asked, so a test can show that a field nobody wanted cost nothing.

Installing git-secrets

Dockstore uses git-secrets to help make sure that keys and private data stay out of the source tree. For information on installing it on your platform check https://github.com/awslabs/git-secrets#id6.

If you're on mac with homebrew use brew install git-secrets.

With git-secrets on your path, make install (or make git-hooks) registers the AWS patterns and points core.hookspath at git-hooks/, so the scan runs on every commit. CI runs git secrets --scan over the whole repository as well. False positives can be listed in .gitallowed.

License

Apache License 2.0. See LICENSE.

About

Dockstore MCP Interface

Resources

Code of conduct

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages