The pipeline ships a read-only Model Context Protocol server, so an MCP-capable assistant (Claude Desktop, Claude Code, and most agent frameworks) can answer questions like "why did my grade drop and what do I tell my vendor" grounded in the same published JSON the site serves.
There is no write surface and no key. Every tool is a read of
gtfsscorecard.org; the server is a thin, stdlib-only translation between
MCP's stdio framing and the public data contract in api.md.
From a checkout:
cd pipeline && uv syncClaude Desktop / Claude Code config:
{
"mcpServers": {
"gtfs-scorecard": {
"command": "uv",
"args": ["run", "--project", "/path/to/gtfs-scorecard/pipeline", "scorecard-mcp"]
}
}
}Point a fork or a local preview at itself with SCORECARD_BASE_URL.
| Tool | What it answers |
|---|---|
search_agencies |
"Which agencies in Ontario do you track?" Name, id, ISO country, ISO subdivision code or name, legacy state/province, and grade filters over the covered catalog. Results carry country, subdivision_code, and subdivision_name; an omitted historical country is returned as US. |
get_scorecard |
"How is Unitrans doing and what should they fix first?" Overall grade, category summaries, every finding with its plain-language fix, effort hint, and fix-guide link, plus NTD readiness. |
coverage_stats |
"What countries and subdivisions do you cover?" Covered-set quality totals plus portable country and subdivision rollups. Counts describe tracked public feeds, not every operator in a country. |
national_stats |
Legacy United States policy view retained for existing clients. Its ntd_readiness member is US-only; its historical stats member still describes the complete covered corpus. New clients should use coverage_stats for geography-neutral totals. |
search_agencies accepts country as an ISO 3166-1 alpha-2 code and
subdivision as either an ISO 3166-2 code or its practitioner-facing name.
The older state input remains available and also matches a portable
subdivision name, so existing prompts and clients keep working.
Results carry the same framing rules as the site: an unmeasured realtime category reads as not yet published, findings are framed as fixes, and every scorecard result names that it is a data-quality lens, not a compliance determination. NTD is never presented as a global standard: it remains an explicit United States policy overlay.
The repository carries a server.json manifest for the
official MCP Registry, naming the
server io.github.chelseakr/gtfs-scorecard. Publishing requires an interactive
GitHub login, so it is a one-time operator step:
brew install mcp-publisher # or download from modelcontextprotocol/registry releases
mcp-publisher login github # device-code flow, authorizes the io.github.chelseakr namespace
mcp-publisher publish # reads server.json at the repo rootAs of 2026-07-05, server.json carries no packages[] entry (see its
_meta["dev.chelseakr/gap"] note). An earlier revision declared
registryType: pypi, which was false: scorecard-pipeline has never been
published to PyPI, and the MCP registry schema's registryType enum (npm,
pypi, oci, nuget, mcpb) has no value for "installed from a git
subdirectory via uvx --from," which is what actually happens. Rather than
leave that false claim in a public registry listing, the packages entry was
removed; the registry listing is metadata-only until either scorecard-pipeline
is genuinely published to PyPI (tracked with the release-pipeline work) or the
schema adds a git-source registry type. Until then, use the "Install and
connect" recipe above (a local checkout), or the direct uvx invocation:
uvx --from git+https://github.com/ChelseaKR/gtfs-scorecard#subdirectory=pipeline scorecard-mcpThe Claude Connectors Directory is a separate, heavier bar (a remote server, a privacy policy, and a Team/Enterprise submission); per the cost guardrail it waits until remote hosting has a named user.
The protocol core (handle_request, call_tool) is pure over an injected
fetch function and covered by tests/test_mcp_server.py; the stdio loop in
main() is the only I/O. No SDK dependency, for the same reason the
submission Lambda is stdlib-only: the deployable surface stays small and the
tested core carries the logic.