How to run stringdb-link — locally, in Docker, and behind a reverse proxy — plus the MCP
client wiring. Configuration values referenced here are defined in
configuration.md.
Two console scripts ship with the package (pyproject.toml → [project.scripts]):
| Script | Module | Purpose |
|---|---|---|
stringdb-link |
stringdb_link.cli:main |
The CLI: server, mcp, config, validate-config, health, version. |
stringdb-mcp |
mcp_server:main |
Direct stdio MCP entry point (Claude Desktop and other stdio hosts). |
This server is tri-modal — it can serve REST only, MCP only, or both from one process.
| Mode | Command | Serves |
|---|---|---|
unified (default) |
stringdb-link server --transport unified --port 8000 |
FastAPI REST and MCP over Streamable HTTP at /mcp |
http |
stringdb-link server --transport http --port 8000 |
FastAPI REST only |
stdio |
stringdb-link mcp (or python mcp_server.py) |
MCP over stdio |
Important
MCP clients need unified. --transport http does not expose /mcp. This is the
usual cause of a "server added but no tools" symptom behind the router.
Make targets wrap the common cases:
make dev # unified, 127.0.0.1:8000, --reload
make mcp-serve-http # unified, 0.0.0.0:8000 (container / proxied form)
make mcp-serve # stdio| Path | Purpose |
|---|---|
GET /health |
Root-level probe. Required by the MCP Transport Standard v1 conformance probe and used by the Docker health check. |
GET /api/health |
Detailed health, including upstream STRING reachability. |
GET /api/version |
Version metadata. |
stringdb-link health performs the check from the CLI.
Compose files live in ../docker/; see ../docker/README.md
for the image internals and file-by-file breakdown.
make docker-build # docker compose -f docker/docker-compose.yml build
make docker-up # start
make docker-logs # tail
make docker-down # stop| File | Use |
|---|---|
docker/docker-compose.yml |
Base / development stack. |
docker/docker-compose.dev.yml |
Hot-reload overlay. |
docker/docker-compose.prod.yml |
Production: Gunicorn, digest-pinned image, resource limits, no published ports. |
docker/docker-compose.npm.yml |
Production behind an external Nginx Proxy Manager network. |
Environment templates: ../.env.example (local),
../.env.docker.example (container),
../.env.npm.example (proxied production).
The container follows the fleet's Container & Deployment Hardening Standard v1: non-root,
read-only root filesystem, all capabilities dropped, no-new-privileges, resource limits,
digest-pinned base image, and CI image scanning. Release metadata is pinned in
../container-release.json.
The backend is unauthenticated by design. The genefoundry-router (or your own reverse
proxy) is the trust boundary and owns edge auth. Two consequences:
- Never publish the container port directly. In production, bind loopback or expose the
port only on the proxy's internal network (
docker-compose.prod.ymlpublishes nothing). - Add the public hostname to
ALLOWED_HOSTS, e.g.ALLOWED_HOSTS=["stringdb-link.genefoundry.org","localhost","127.0.0.1","::1"]. The Host guard takes exact values; wildcards are rejected. A proxied deployment that works onlocalhostbut fails through the proxy is nearly always this.
TLS terminates at the proxy. Set ALLOWED_ORIGINS only if a browser origin must reach the
server directly; it is empty by default, which still admits non-browser clients (no Origin
header).
Hosted (Streamable HTTP):
claude mcp add --transport http stringdb https://stringdb-link.genefoundry.org/mcpLocal (Streamable HTTP), after make dev:
claude mcp add --transport http stringdb http://127.0.0.1:8000/mcpClaude Desktop (stdio) — claude_desktop_config.json:
{
"mcpServers": {
"stringdb-link": {
"command": "stringdb-link",
"args": ["mcp"],
"env": {
"STRINGDB_API__RATE_LIMIT_PER_SECOND": "1.0"
}
}
}
}Behind genefoundry-router the server is mounted under the stringdb namespace and its
tools surface as stringdb_<tool> — see architecture.md.
../SECURITY.md documents the vulnerability-reporting process and one
outstanding operator action: GitHub secret scanning and push protection are repository
settings, not workflow files, so they cannot be enabled from a pull request. An admin must
enable them with gh api -X PATCH repos/berntpopp/stringdb-link … (exact command in
SECURITY.md). Code scanning (CodeQL) is already wired via
.github/workflows/security.yml.