gtfs-scorecard
Provides a GitHub Marketplace Action to gate GTFS feed quality in CI and allows requesting a one-off score through GitHub issue templates.
GTFS Scorecard
Daily, plain-language GTFS quality scorecards for small transit agencies: see the current grade, the three things to fix, and why each one matters.

GTFS Scorecard is a daily data-quality service for small transit agencies and the program staff, maintainers, and vendors who support them. It publishes dated grades, prioritized fixes, history, program views, practitioner tools, and open data. It does not implement a competing GTFS validator. Correctness findings come from MobilityData's canonical validator.
Quickstart
Requires Python 3.12+, uv, and Java 17+ (the validator jar is downloaded automatically on first run).
cd pipeline
uv sync
uv run scorecard run --allThis fetches today's snapshot of every current configured feed, validates and
scores it, and writes artifacts to data/artifacts/<agency>/<date>.json plus a
latest.json and a cross-agency index.json. Retired aliases are excluded
from the batch; an explicit historical rescore writes a dated record without
recreating mutable current files. Re-running a day is idempotent. Checks (from
the repo root; mirrors the CI gate):
make verifyRun the web app locally
The frontend reads the JSON artifacts over HTTP. Serve the repo root and open
the page through http://, not by double-clicking the file:
cd .. # repo root, so data/artifacts/ is reachable
python3 -m http.server 8000
# then open http://localhost:8000/web/index.htmlOpening web/index.html as a file:// URL leaves the page stuck on
"Loading scorecards…": browsers block ES module loading and fetch over
file://, so the app never runs. Any static server works; the only requirement
is that data/artifacts/ sits one level above web/, which the
../data/artifacts fallback in web/src/app.js expects.
Related MCP server: grand-lyon-mcp
Where it fits
GTFS Scorecard is the evidence and triage layer:
Mobility Database and Transitland help identify public feeds and their sources or versions.
The MobilityData GTFS validator supplies canonical specification findings.
An agency, vendor, editor, or support program changes and publishes the feed through its existing workflow.
A 90-day GTFS Scorecard pilot is testing the final handoff: link an accepted action to the intended feed, run a comparable recheck, and preserve the result.
The California GTFS Quality Dashboard inspired the project's daily scorecard and support-program framing. GTFS Scorecard is independent and is not an official compliance determination.
Pilot agencies: Unitrans (ASUCD / City of
Davis) and Yolobus (Yolo County Transportation
District). Beyond the pilots, the registry contains more than 2,600 curated
feed records, mostly in the United States and Canada, plus reviewed canaries
across Europe, Asia-Pacific, and South America. Scoring is scheduled daily for
every registered feed, and the public status page reports the exact current
configured and published counts along with when the latest run completed. Read
the published total there rather than from this repository: automation stopped
committing generated data at the S3 cutover (see
docs/follow-ups.md), so what git carries is a fallback
snapshot that moves only when it is deliberately re-materialized from the live
corpus (last refreshed 2026-08-07),
with more than 2,100 numeric scorecards published. CI can only gate the
snapshot figure, because make verify runs offline. A feed record is not
always a distinct transit agency: regional feeds and modal variants are counted
separately while the identity registry is reconciled. A record the Mobility
Database has retired in favor of another is no longer one of them: it keeps
its dated artifacts and redirects its old URL, and only its successor publishes
a current grade, so one agency does not carry two
(docs/feed-supersessions.md). That leaves the published count lower than it
was, and right.
Live: gtfsscorecard.org — with the latest completed-run evidence at gtfsscorecard.org/status.
Status: Beta. The public scorecards and daily evidence service are live.
The remediation workflow is being tested and is not yet a proven service.
Realtime quality is scored only when a usable realtime feed is configured and
measured; otherwise it is shown neutrally as not yet measured. Any agency can
be added through registry/intake.yaml.
Use, adopt, or contribute
Check a feed: browse gtfsscorecard.org, or request a one-off score.
Track an agency: use the self-serve submission form, or follow the repository walkthrough to open a pull request.
Gate a feed in CI: add the GTFS Scorecard Marketplace Action to a feed repository.
Test what happens after the scorecard: read the remediation pilot request if you can take a finding through an accepted request and same-feed recheck.
Contribute: choose a bounded open issue or read CONTRIBUTING.md. Feed corrections, accessibility review, and practitioner feedback are useful without changing scoring code.
Get help, or fund the work: SUPPORT.md is the front door for both. Scoring is free for every agency and stays that way; the support page explains what running the service costs, what sponsorship would pay for, and what it never buys.
Report on every agency you support: the program rollups (
/program/<state>/) are free; the paid program report bundle packages a branded board report per agency into one archive.
What an agency gets
An overall grade from the categories that can be measured: correctness, freshness, rider experience completeness, and, when available, realtime quality.
"Top 3 things to fix", in plain language with effort hints. Findings are framed as fixes, never as failures.
For U.S. agencies only, an NTD GTFS-readiness read (published, valid, current, and
agency_idpresent) plus a neutral check of whetheragency_idhappens to equal the five-digit NTD ID. Equality is optional; RY2026 presence and the P-50 crosswalk are not.Trend history, one JSON artifact per agency per day.
An embeddable grade badge (
<agency>/badge.svg) the agency can put on its own developer page.
The scoring methodology, with citations to the California Transit Data
Guidelines v4.0 and the validator's rule taxonomy, is in
docs/rubric.md. Methodology changes are governed: a
validator-version bump must attach the shadow-run impact report from
scorecard canary before it lands (rubric.md, "Governed upgrades").
The grade, weights, thresholds, and fix order are GTFS Scorecard policy choices,
not an official MobilityData grade or a universal quality standard.
Feed sources and licenses are in
docs/feeds.md. Forward planning is split in two: the
infrastructure and scaling plan is in docs/roadmap.md, and
what the product becomes for its users is in
docs/product-roadmap.md.
What's on the site
Each agency gets a scorecard page, plus three companion pages written for the
different seats at an agency check-in: a board one-pager
(/agency/<id>/board/), a call-prep brief (/brief/), and, when comparable
finding-clearance records exist, a clearance log (/fixes/). Around those sit:
Coverage views — the coverage overview (
/pulse/), most common problems (/problems/), realtime reliability (/realtime/), optional-feature adoption and accessibility data coverage (/adoption/), a consumer feature finder with translation-language and accessibility filters (/app/#/?view=features), and worldwide agency and route maps (/map/,/routes/). U.S.-specific NTD readiness (/ntd/) and equity (/equity/) stay available as regional modules.Program pages (
/program/<state>/) for 46 states plus DC and named cohorts fromrollups.yaml, each with the fixes shared across the group.Practitioner tools — request a one-off score through GitHub or run it locally (
/try.html), check a feed before publishing (/check/), compare two agencies (/compare/), query the dataset with SQL in the browser (/query/), and put feed quality in a vendor contract (/procurement/).Board-ready outputs — each agency has a printable one-pager; see the live Unitrans example, or generate a self-contained, custom-branded offline report with the board-report tool.
A fix knowledge base (
/fix/<rule>/, one plain-language page per common validator finding) and the standards crosswalk (/crosswalk/).Machine-readable surfaces — the versioned read API (docs/api.md), a Parquet table for bulk SQL, per-agency badges and conformance marks, Atom change feeds, monthly citable dataset releases, and a read-only MCP server (docs/mcp.md).
The country controls describe only the current covered set. They are not a census of a country or region. The live evidence and readiness result for a bounded European GTFS beta are on the status page; the release gate and scope limits are in docs/global-expansion.md.
Use it in CI
Gate your own pipeline on feed quality with the published action. It scores the
feed, prints the grade and the top fixes in the job log, and fails the build if
the feed drops below min-grade or expires within min-days-to-expiry:
- uses: ChelseaKR/gtfs-scorecard@v1.5.1
with:
feed-url: https://your-agency.example/google_transit.zip
country: CA
min-grade: C
min-days-to-expiry: 14Pin a full release tag or a commit SHA, as above. The floating major @v1
still exists for consumers who already use it, but it is not recommended here
and these examples no longer use it: it is one mutable pointer that moves to
the newest v1.x.y on release day, so it changes what your workflow runs
without a commit or a diff on your side. v1.5.1 is the newest published
Action release, and docs/ci-action.md
says what it includes.
country is the feed's assigned ISO 3166-1 alpha-2 code; it defaults to US
for existing workflows. Both thresholds are optional; leave one blank to skip that check. Full input
reference and a complete workflow are in docs/ci-action.md.
Operating at scale
Beyond run, the CLI carries the commands the rollout plan needs:
scorecard sync --country US --state California # propose keyless, untracked
# Mobility Database entries
scorecard shards --count 4 # JSON fan-out plan for CI
scorecard reindex # rebuild index.json from disk
scorecard rollups # publish program rollup artifacts
scorecard render-site # crawlable static pages + sitemap
scorecard alerts --out digest.md # expiry/regression digest
scorecard notify # per-subscriber digest (dry run)Add --source-metadata-out <path> to scorecard sync for a source receipt
that accounts for every recognized Mobility Database Schedule row as excluded,
filtered, already tracked, duplicate, conflicted, or proposed for review. It
never edits the registry and does not treat a catalog proposal as permission to
republish.
notify builds a feed-health email for each opt-in subscriber in
subscriptions.yaml, containing only the agencies they
follow and only when one needs attention. It prints the emails by default; the
daily workflow sends them via SES once an operator verifies a sender, applies
the SES grant in infra/artifacts, and sets the SES_FROM repo variable.
The daily workflow fans agencies out across a parallel matrix and can mirror
artifacts to a CloudFront-backed S3 bucket once infra/artifacts is applied
(ADR 0002). Program rollups are configured in rollups.yaml as
named cohorts (a liaison's own agencies, a district, the whole state) and shown
at #/programs; an agency "needs attention" when its feed is expiring or its
grade regressed, not merely when it scores below a B. The published JSON is a
documented read API (docs/api.md); a flat catalog of every agency
(grade, score, feed URL, days-to-expiry, top fix) is served at /catalog.json
and /catalog.csv so a consumer needs one request, not one per agency.
Roadmap status: built vs deployed
The roadmap plans the path from two pilot feeds to a worldwide-capable service. The Year 1 software is built, tested, and mostly deployed; the deploy runbook walks through the AWS stacks and carries the current deployment status.
Roadmap piece | In the repo | State |
Mobility Database sync |
| run on demand |
Scheduled scoring run |
| daily schedule live in Actions; observed completion is on |
Expiry/regression alerts |
| applied and live; SES sender verified, digest sends daily |
Artifacts on S3 + CloudFront |
| applied and live; daily mirror on, site still serves from Pages |
Self-serve submission form |
| applied and live; submissions open reviewable pull requests |
Instant scoring |
| built; falls back to the issue-form path until applied (ADR 0029) |
Fan-out compute (Year 2) |
| built; apply when the daily run outgrows the Actions matrix |
The cohort drafted from the Mobility Database has grown well past the first
California pass: the manifest-backed registry now
carries more than 2,600 curated feed records, mostly across the US and Canada,
with a 760-record reviewed European cohort across 28 countries.
It now includes a geographically diverse reviewed canary cohort, scored daily
(a 2026-07 dedupe pass removed ~350 records that duplicated an already-listed
feed).
Add your agency
Any agency with a public GTFS feed can be added with one YAML block in
registry/intake.yaml and a pull request; the walkthrough is
docs/add-your-agency.md. The live web form at
web/submit.html does the same without YAML through the
deployed infra/submit endpoint; every submission still opens a pull request
for human review before publication.
What is free, and what is paid
Everything an agency needs for its own feed is free and stays free: its scorecard, the prioritized fixes, the history, the printable board one-pager, the self-contained board report it can hand to a board or attach to a grant application, the badge, the open data, and the read API. No account and no payment is involved anywhere in that path.
Two things cost money. A program that prepares packets for many agencies at once (a state DOT, a technical-assistance center, a feed vendor, a consultancy) can buy the program report bundle: a single archive holding a board report for every agency id it names, carrying the program's own name, logo, and accent color on each cover, refreshed monthly if it wants. A vendor, a consultancy, a program, or a researcher who needs the whole corpus over time can buy the scorecard history tables: every dated check and every finding as two Parquet tables with a data dictionary, provenance, and license, rebuilt monthly and licensed to one organization (ADR 0063, docs/history-tables.md). Plan sizes, prices, delivery terms, and the refund commitment live on the bundle page and the history tables page, which read them from the live plan data; they are not copied into this file, where they would go stale. A purchase buys no influence over grades, methodology, or which agencies are listed, and nothing was subtracted from the free tier to create either.
Support and sponsorship
The public scorecards, data, API, local pre-publish check, and request-backed one-off scoring remain free. The support page explains the project's infrastructure needs, what each GitHub Sponsors tier is sized to, and what sponsorship never buys; it does not advertise a payment rail that is not ready. Nothing is subtracted from the free tier to create anything else.
Standards conformance
This repo is governed by the shared portfolio standards vendored at
docs/standards/ (pinned to a tag — never edited locally;
see the integrity note in that directory's history). Per
docs/standards/README.md's conformance rule, every applicable standard is
declared here; none is silently skipped.
Standard | State | Standard document |
Code Quality | Applies (Python; TS/Node N/A — | |
Security & Supply-Chain | Applies (ASVS L1 shape: no auth, no PII store) | |
CI/CD | Applies | |
Observability | Applies — Tier B (frontend) + Tier C (batch pipeline); see ADR 0031 | |
Accessibility | Applies fully — civic content, self-declared WCAG 2.2 AAA (see docs/accessibility.md, docs/vpat.md) | |
Internationalization | Applies — civic transit data, public-facing; exemption path unavailable | |
Performance | Applies — the static frontend has blocking Lighthouse budgets on code changes; the scheduled data-refresh path retains its documented advisory exception | |
AI Evaluation | N/A — no LLM/model component: no model inference in any user-facing or decision-making path ( | |
AI Development Measurement | Applies — delivery and quality-debt outcomes are measured at repository level; local AI-tool telemetry is never a merge gate | |
Quality & Metrics | Applies (data-quality/lineage named for this repo explicitly) | |
Documentation | Applies | |
Release & Versioning | Applies — reusable Action tags ( | |
Responsible-Tech Framework | Applies (audits A-F; AI-governance rows N/A — no AI system) | |
Incident Response | Applies — deployed static site and scheduled pipeline; incidents use the shared severity, label, postmortem, and secret-leak conventions | |
Data Governance | Applies — public civic datasets, feed provenance, licenses, retention, and publication lineage are core product concerns |
Open gaps per standard, as of the most recent conformance audit, are tracked in docs/standards-conformance-gaps.md rather than restated here.
Observability
Tier B (frontend) + Tier C (batch pipeline) — not the
OBSERVABILITY-STANDARD's default Tier-A mapping for this repo's class;
see ADR 0031 for why. In short:
the deployed system is a scheduled Actions batch job plus a static site, not
a long-lived hosted service (infra/compute, the piece that would make this
Tier A, is built but not applied). Tier C's health/tracing/SLO controls are
N/A (no network surface to probe). For Tier B, every fresh site build passes a
blocking structural SEO check. Lighthouse gates code changes, and a weekly
synthetic run checks representative production routes. Build-time SEO reports
are retained for 14 days and production Lighthouse reports for 90 days.
The public site carries one first-party measurement script, web/src/measure.js,
with two separate blocks. The PostHog block
(ADR 0055) sends page views
and bundle checkout clicks to PostHog Cloud US with no cookie and no identifier
that outlives the browser tab, and is off unless the deploy carries a
POSTHOG_KEY. The Google Analytics 4 block
(ADR 0056) loads GA4 for the
measurement id in site-seo.json (measurement_ga4_id). GA4 records page views
and engagement with the query string and referrer path dropped. It sets the
first-party _ga cookies, which last up to two years, except in the EEA, the UK
and Switzerland, where analytics storage is denied and no cookie is set. Google
signals, ad personalization and ad storage are off everywhere. Both blocks load
nothing under Global Privacy Control or Do Not Track, or for a reader who used
the "Opt out of analytics" link in every page footer, which is remembered on
that device and also deletes the GA4 cookies. What they record is
stated at /about/#privacy and held by
the structural check. Neither is real-user monitoring: no Core Web Vitals are
collected. Search Console ownership verification and sitemap submission
remain external domain-owner tasks; this repository stores no Search Console
credentials or configuration. See the ADR and deploy runbook.
Versioning
SemVer. The public API surface is the published JSON schema
(schema_version), the GitHub Action's inputs (action.yml), and the CLI
(docs/api.md). pipeline/pyproject.toml's [project].version is the single
source of truth; CITATION.cff and server.json mirror it, and
pipeline/scripts/check_versions.py fails make verify if they drift.
Supported-version policy: latest major only — this is a single-deployment
civic tool, not a library with multiple consumers pinned to old majors.
This repo also produces releases: the marketplace GitHub Action (tagged
v1) and monthly citable dataset releases (dataset-release.yml). It carries
a publish workflow for the gtfs-scorecard Python package
(pypi-publish.yml) and an MCP server manifest (server.json).
gtfs-scorecard 1.5.1 is on PyPI,
and the MCP Registry lists io.github.ChelseaKR/gtfs-scorecard 1.5.1 with that
package. The v1.5.0 run of the workflow reached the upload under the package's
former name scorecard-pipeline, which PyPI refused as too similar to an
existing project, so nothing was uploaded for 1.5.0 and the distribution is
gtfs-scorecard from 1.5.1 on. A release tag starts the PyPI workflow, which
then waits for a reviewer to approve the upload; the manifest goes to the
registry only after that upload exists.
uvx gtfs-scorecard starts the MCP server and
uvx --from gtfs-scorecard scorecard runs the command-line tool; the import
package stays scorecard_pipeline. To run code on main that is not released
yet, install from the source tree instead:
uvx --from "git+https://github.com/ChelseaKR/gtfs-scorecard#subdirectory=pipeline" scorecard-mcpdocs/mcp.md has the client config and the publishing steps.
Run your own instance
A state DOT, national RTAP, or country program can fork this repo and stand up its own branded instance — own domain, own agency registry, own organization name — from config and a deploy, no code change: docs/fork-quickstart.md.
Layout
registry/ manifest-backed agency shards; add yours to intake.yaml
instance.example.yaml fork branding template; copy to instance.yaml to rebrand
rollups.yaml program rollups (portfolio views across many agencies)
pipeline/ Python pipeline: fetch -> validate -> score -> publish
web/ static frontend; reads only published JSON
infra/ Terraform: artifacts CDN, submission function, fan-out compute
docs/ feeds, rubric, roadmap, api, fixes/ (KB), decisions/ (ADRs)
data/ raw snapshots (ignored) and published artifacts (committed)Guardrails
Three rules hold everywhere in this project: every metric is published with a
plain-language explanation of what it means; accessibility (WCAG 2.2 AAA) is
non-negotiable in the web app; and an agency without a realtime feed is shown
neutrally, never shamed. Contributor and agent-facing build rules live in
CLAUDE.md; current direction beyond the shipped roadmap is worked in the
open as labeled notes in docs/ideation/.
Maintainer
Built and maintained by Chelsea Kelly-Reif, starting from the transit systems in Davis, California. Contributions and corrections are welcome; agencies can ask to be added or removed under the listing and removal policy.
Available Tools
9 toolscoverage_forA
Covered-set totals for one ISO country, or one subdivision inside it. A place this scorecard does not track is reported as not covered rather than as zero feeds: absence of coverage is not absence of transit data.
| Name | Required | Description | Default |
|---|---|---|---|
| country | Yes | ISO 3166-1 alpha-2 country code, e.g. US | |
| subdivision | No | Optional ISO 3166-2 code or subdivision name |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it does disclose one genuinely useful behavioral trait: untracked places are reported as 'not covered' rather than as zero, and absence of coverage is not evidence of absence of transit data. That is valuable output semantics beyond the schema, but nothing is said about read-only safety, permissions, or result shape.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, both earning their place: the first front-loads scope, the second front-loads the interpretation caveat. No filler, no repetition of the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter read tool with no output schema and no annotations, the description covers what is returned, the granularity options, and the crucial not-covered-vs-zero semantics. It stops short of saying whether the optional subdivision is required for subdivision-level output or what the totals are keyed on, but the gap is small.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters (country as ISO 3166-1 alpha-2, subdivision as ISO 3166-2 code or name) are already fully documented. The description's 'one ISO country, or one subdivision inside it' only restates that relationship without adding format or edge-case detail, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource ('Covered-set totals') and an explicit scope (one ISO country, or a subdivision inside it), which is concrete enough for an agent to know what comes back. It does not, however, contrast itself with the obviously related siblings coverage_stats or national_stats, so disambiguation must come from elsewhere.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The scope phrasing implies the use case (single-country / single-subdivision lookups), but there is no explicit when-to-use statement and no named alternative such as coverage_stats or national_stats for aggregate or comparative queries. Usage is inferable rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
coverage_statsC
Coverage-wide quality totals and portable country/subdivision rollups over the feeds this scorecard tracks.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full disclosure burden. It implies a read-only stats/aggregation operation but never confirms that, nor does it describe scope constraints, freshness, or the shape of results. 'Portable' is unexplained jargon rather than a behavioral trait.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no filler, which is appropriate for a zero-parameter tool. It is slightly dense with undefined terms ('portable', 'coverage-wide') but wastes no space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description must convey what comes back, and it only gestures at 'quality totals' and 'country/subdivision rollups' without defining the metrics or structure. Combined with no differentiation from overlapping siblings, an agent lacks enough to call this correctly with confidence.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the schema-based baseline of 4 applies. There is nothing for the description to clarify on the input side.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states the subject matter (coverage-wide quality totals plus country/subdivision rollups) but uses no clear verb and leans on undefined jargon like 'portable' and 'the feeds this scorecard tracks'. It does not distinguish itself from close siblings such as national_stats, get_rollup, or coverage_for, so an agent cannot confidently pick it over those.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance, no exclusions, and no mention of the sibling tools that clearly overlap (national_stats, get_rollup, coverage_for). The agent is left to guess which stats tool to call.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
explain_findingA
The fix recipe for one validator or scorecard notice code, its authoritative rule link, and, when a producing tool is named, that tool's fix path. A code with no written recipe returns the rule link alone and says so; nothing is described beyond what is written.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | Notice code, e.g. 'expired_calendar' | |
| tool | No | Optional producing-tool key: trillium, gtfs_builder, remix, passio, repo, or archive |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does disclose the important edge case: a code with no written recipe returns only the rule link and signals that fact, and nothing is invented beyond the written content. It omits auth, rate-limit, and pagination behavior, but the degradation contract is the disclosure an agent most needs here.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with what the tool returns before the empty-recipe caveat. Dense but each clause adds information; the closing hedge 'nothing is described beyond what is written' slightly repeats the no-recipe clause but usefully bounds expectations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema and no annotations, so the description must describe the return shape itself, and it does: recipe, rule link, optional tool fix path, and the partial-result case. Given a simple two-parameter lookup, this is complete enough for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both the 'code' example and the enumerated producing-tool keys are already documented in the schema. The description adds only marginal meaning by tying the 'tool' parameter to the returned fix path, which is the baseline expectation when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource precisely — the fix recipe, rule link, and optional producing-tool fix path for a notice code — so an agent knows it is a lookup keyed on a validator/scorecard code. It distinguishes itself somewhat from retrieval siblings like get_scorecard and get_evidence_packet by specifying the fix-recipe payload, though it never states the action verb outright.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied: you supply a notice code to learn how to fix it, and optionally a producing tool to get that tool's fix path. There is no explicit when-to-use vs. when-not, and no sibling is named as the alternative, so an agent must infer the trigger condition from the code parameter alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_evidence_packetB
The deterministic vendor remediation packet for one agency's latest scorecard: the producer contract, the work items with their acceptance tests, and the feed identity they were measured against.
| Name | Required | Description | Default |
|---|---|---|---|
| agency_id | Yes | Agency slug, e.g. 'unitrans' |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It usefully discloses that the packet is "deterministic" and tied to the "latest" scorecard (a current-snapshot rather than historical read), but says nothing about permissions, size, cost, or whether the packet is cached/stable across calls.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no filler, and the three packet contents are listed compactly after the colon. Dense but every clause carries information; it reads as a noun phrase rather than an instruction, which is a minor structural weakness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description must convey the return value, and it does list the packet's components reasonably well. However, it omits any guidance on invocation context or what the agent should do with the packet, leaving gaps for a tool whose output it must describe.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single parameter is documented with a concrete example ('unitrans'), so the schema already does the work. The description adds only the implicit scoping of 'one agency' and 'latest', which the schema does not restate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific artifact and enumerates its three components (producer contract, work items with acceptance tests, feed identity), so an agent can tell it apart from get_scorecard or explain_finding. It never states a verb like "return" and does not explicitly contrast itself with those siblings, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance and no named alternative among the eight siblings. The phrase "one agency's latest scorecard" hints that it is scoped to the current scorecard snapshot, but the agent is left to infer when this is preferable to get_scorecard, explain_finding, or coverage_for.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_historyA
One feed's dated grade and score history, with every measurement-contract boundary marked. A point marked comparable_with_previous: false was scored under a different rubric, scoring profile, validator, reader archive profile, or measured-category set, and the difference across it is not a change in the feed. Also reports findings that appeared or cleared between the two most recent snapshots, but only when those two are comparable.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max dated points (default and ceiling 120) | |
| since | No | Earliest snapshot date to include, YYYY-MM-DD | |
| agency_id | Yes | Agency slug, e.g. 'unitrans' |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does substantial work: it defines the comparable_with_previous flag, enumerates the five causes that make a point non-comparable (rubric, scoring profile, validator, reader archive profile, measured-category set), and warns that differences across such a boundary are not real feed changes. It also conditions the findings delta on comparability of the two most recent snapshots. Missing only operational details like pagination, auth, or rate limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with what the tool returns and then progressively detailing the comparability semantics. The middle sentence is dense but every clause adds necessary meaning. No filler or restatement of the name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema and no annotations, so the description must explain return semantics itself, and it does so well for the key field (comparable_with_previous) and for the conditional findings delta. It is only lightly incomplete in not sketching the overall response shape or pagination behavior for a 120-point feed history.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so limit, since, and agency_id are already fully documented in the schema (including the 120 default/ceiling and the YYYY-MM-DD format). The description adds no parameter-level meaning beyond that, which is the expected baseline when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource and scope ('One feed's dated grade and score history') plus the extra artifacts it returns (measurement-contract boundaries, appeared/cleared findings). An agent can tell it is a historical time-series tool. It does not, however, name or distinguish itself from any of the many sibling analytics tools (national_stats, get_rollup, get_scorecard), so it falls short of the top mark.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: the description makes clear this is the tool for dated trend/comparability analysis, and the 'only when those two are comparable' clause signals a precondition on interpreting the findings output. But there is no explicit when-to-use, when-not-to-use, or named alternative among the eight siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_rollupB
One program rollup: the cohort's shared fixes, grade distribution, and the members needing attention. Shared fixes describe work many feeds share; they are not a ranking of agencies.
| Name | Required | Description | Default |
|---|---|---|---|
| rollup_id | Yes | Rollup id, e.g. 'california' |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It does add a genuinely useful interpretive guard — shared fixes are not a ranking of agencies — which prevents a likely misreading of the output, but it says nothing about permissions, whether results are cached/live, or the shape of the response.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the resource and its contents, followed by one clarifying caveat. Nothing is redundant and the second sentence earns its place by heading off misinterpretation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no annotations, the description does the needed work by previewing the three returned sections. It is adequate for a simple single-record read, though a hint about what 'rollup_id' scopes (which cohort/program) would make it airtight.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single rollup_id parameter is fully documented in the schema with an example ('california'), so the description cannot add much. It correctly conveys that the tool operates on one rollup, matching the parameter's intent, which is the expected baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource (a single program rollup) and enumerates its payload: shared fixes, grade distribution, and members needing attention. This distinguishes it from aggregate siblings like national_stats or coverage_stats, though it never names an alternative to sharpen the contrast.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrasing 'One program rollup' implies singular retrieval keyed by rollup_id, but there is no explicit when-to-use, no exclusions, and no routing versus get_scorecard, national_stats, or coverage_stats. The agent must infer selection from the name alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_scorecardC
An agency's latest scorecard: overall grade, category scores and plain-language summaries, every finding with its fix and effort, top fixes, and NTD GTFS readiness.
| Name | Required | Description | Default |
|---|---|---|---|
| agency_id | Yes | Agency slug, e.g. 'unitrans' |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. 'Latest' hints at freshness, but nothing states that this is a read-only operation, whether results are cached, what happens for an unknown agency_id, or any auth requirement. Enumerating the payload partially compensates, but the core behavioral profile is absent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single efficient sentence with no filler; content is front-loaded. It is a content list rather than a purpose statement, so it is concise but not optimally structured for tool selection.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no output schema, listing the returned sections (grades, findings, fixes, NTD GTFS readiness) is genuinely useful. However, the description leaves out what the tool actually does, when to invoke it instead of siblings, and any read-only/freshness behavior — substantial gaps given no annotations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single parameter (agency_id) and the schema documents it at 100% coverage, including an example slug, so the baseline is 3. The description adds no meaning about the parameter at all — it never references the agency argument.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource (an agency's latest scorecard) but supplies no verb — it is a noun-phrase inventory of contents rather than a statement of what the tool does. An agent can infer retrieval, and 'scorecard' distinguishes it somewhat from siblings like get_history and get_rollup, but it never explicitly says 'fetch/retrieve a scorecard for an agency'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to use this tool versus the eight siblings (get_history, get_rollup, get_evidence_packet, explain_finding, etc.). No prerequisites, no exclusions, no indication of how it relates to rollup/history views.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
national_statsA
Legacy United States policy view: NTD GTFS readiness nationally and by state, plus the backwards-compatible covered-corpus stats member. Prefer coverage_stats for geography-neutral totals.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does disclose meaningful traits: it is a legacy/backwards-compatible view and contains a 'covered-corpus stats member' alongside the national/by-state data. For a zero-parameter read-only stats tool the risk surface is small, though the return shape (beyond a single phrase) and any error/deprecation behavior are not described.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, no filler, with the scope statement front-loaded and the alternative-plus-condition in the second sentence. The phrase 'backwards-compatible covered-corpus stats member' is jargon-heavy and slightly opaque, costing a point.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-param, no-output-schema stats tool, the description supplies what an agent needs: what data is returned, its geographic granularity, its legacy status, and the preferred alternative. Nothing critical is missing, though the return structure is only loosely characterized.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so per the rubric the baseline is 4. The description adds no parameter information because none exists to explain, and the empty schema is self-evident.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource and scope: 'NTD GTFS readiness nationally and by state,' which tells an agent exactly what data this tool surfaces. It also flags the tool as legacy and names the sibling it is not (coverage_stats), aiding differentiation. The framing phrase 'United States policy view' is vague, but the substantive clause carries the meaning.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Prefer coverage_stats for geography-neutral totals' gives an explicit alternative plus the condition that selects it, implying national_stats is for US-specific / by-state needs. It stops short of stating outright when this tool is the right choice or whether it is deprecated, but the routing guidance is clear and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_agenciesA
Search tracked transit agencies by name, id, ISO country, ISO subdivision or subdivision name, legacy state, or letter grade. Returns portable location, grade, score, expiry, and applicable readiness fields.
| Name | Required | Description | Default |
|---|---|---|---|
| grade | No | Letter grade A-F | |
| limit | No | Max results (default 20) | |
| query | No | Name fragment or exact agency id | |
| state | No | Legacy state/province-name filter; prefer subdivision | |
| country | No | ISO 3166-1 alpha-2 country code, e.g. CA | |
| subdivision | No | ISO 3166-2 code or subdivision name, e.g. CA-ON or Ontario |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It partially does so by disclosing the returned fields (portable location, grade, score, expiry, readiness), which is valuable given there is no output schema. But it says nothing about read-only nature, ordering, pagination beyond the schema's limit default, or auth requirements.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, zero filler, and the search scope is front-loaded before the return-value sentence. Every clause (filter dimensions, returned fields) carries distinct information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema, the description usefully enumerates the return payload, which is the main completeness risk. It falls slightly short on pagination/ordering and filter-combination behavior for a six-parameter search tool, but nothing critical for a correct call is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all six parameters including the 'prefer subdivision' hint. The description groups and names the same dimensions but adds no syntax, format, or interaction semantics (e.g., AND vs OR across filters) beyond what the schema provides; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Search) and resource (tracked transit agencies), then enumerates the searchable dimensions (name, id, ISO country, subdivision, legacy state, grade). This clearly separates it from stats/aggregation siblings such as national_stats, get_rollup, and get_scorecard, which return computed values rather than agency records.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the enumeration of filter dimensions, so an agent can infer this is the lookup tool for individual agencies. However, there is no explicit when-to-use versus alternatives (e.g., coverage_for or get_scorecard for aggregate views) and no guidance on combining filters or when results are exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
9 tool updates
v0.1.0- First observed
coverage_for - First observed
coverage_stats - First observed
explain_finding - First observed
get_evidence_packet - First observed
get_history - First observed
get_rollup - First observed
get_scorecard - First observed
national_stats - First observed
search_agencies
TDQS
Scored across 9 tools
Three geography/coverage tools overlap significantly: national_stats, coverage_stats, and coverage_for all report aggregate totals by region, and national_stats even instructs users to prefer coverage_stats. get_scorecard vs get_evidence_packet is clearer but still requires reading descriptions to distinguish grade reporting from remediation packets.
All names use uniform lower_snake_case, and most follow a verb_noun pattern (get_history, get_rollup, explain_finding, search_agencies). However, national_stats, coverage_stats, and coverage_for drop the verb and use noun/preposition forms, breaking the pattern for a third of the set.
Nine tools is a reasonable, well-scoped count for a scorecarding domain spanning agency, cohort, and national views. The slight over-provisioning comes from the redundant coverage/national stats trio rather than genuinely distinct capabilities.
The surface covers the full lifecycle: search, agency scorecard, history, finding explanation, remediation packet, cohort rollup, and geographic/national aggregates. No obvious operation is missing, though a bulk export or comparison tool would round it out.
Related MCP Connectors
MCP server providing access to the Scorecard API to evaluate and optimize LLM systems.
Read-only MCP server for ClassQuill, a tutoring-business-management platform.
Remote MCP server for deterministic educational practice-assessment score conversions.
Read-only MCP server for The Quiet Protocol's engines, benchmarks, proof, and business data.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceMCP server that provides tools for querying live transit data (stops, departures, routes, vehicles, alerts) from any WP GTFS Pro site, enabling AI assistants to answer rider questions.5 npmGPL 2.0
- AlicenseBqualityBmaintenanceLocal MCP server aggregating Métropole de Lyon open data services (transit, bike-sharing, parking, traffic, facilities, waste) behind 10 read-only tools for use with any stdio MCP client.10MIT
- AlicenseNot gradedqualityAmaintenanceEnables querying stops, routes, real-time arrivals, vehicle positions, and schedules from OneBusAway transit APIs via MCP, supporting STDIO or Streamable HTTP.291 npm1Apache 2.0
- FlicenseAqualityDmaintenanceA minimal MCP server for DataProbe data question answering and read-only SQL queries, supporting stdio and streamable HTTP modes.5-