cambridge-open-data-ma-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@cambridge-open-data-ma-mcpcompare FY2027 salaries vs operating budget by department"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
cambridge-open-data-ma-ai
An MCP server, a Skill, and tutorials for asking an AI agent to discover, fetch, cross-reference, and infer insights from the Cambridge MA Open Data Portal — a Socrata portal with 280+ public datasets (budget, public safety, permitting, GIS/parcels, public health, schools, and more).
Ask a natural-language question about Cambridge civic data and get back a grounded answer built from real cross-dataset analysis, not a single-table lookup. Public dataset reads and catalog search work with no credentials at all.
What is in the box
The server —
cambridge_data.mcp, exposed as thecambridge-open-data-ma-mcpconsole script, an 8-tool / 4-resource FastMCP (v1) server. It wraps the same library the CLIs call, so the harness and the CLI never drift (one source of truth).The Skill —
.claude/skills/cambridge-open-data/SKILL.md, the operational playbook: the discover → fetch → cross-reference → infer workflow, plus the gotchas that stop a naive answer.The tutorials —
docs/, five worked analyses that are also the test-suite of real use-cases (below), each reproducible from the repo'sData provenancesection.
The server and the Skill are two views of one system — the machine interface (tools the agent can call) and the cognitive interface (the when/why and the judgment the tools deliberately can't encode). They version as a unit.
Related MCP server: CKAN MCP Server
Install
uv is the recommended runner. From a clone of this repo:
uv sync # install dependencies
uv run scripts/refresh_catalog.py # pull the 280+ dataset index (seconds)
uv run scripts/mcp_smoke.py # end-to-end checkThe smoke test drives the live server and, with a populated cache, reports 14/14. It needs the catalog plus the three raw datasets the coverage and cross-reference checks exercise:
uv run scripts/fetch_dataset.py 9qm7-wbdc # building permits — the coverage audit
uv run scripts/fetch_dataset.py ixg8-tyau # salaries — the cross-dataset SQL
uv run scripts/fetch_dataset.py 5bn4-5wey # operating budget — the wrong-name errorOn a fresh clone without that cache the cache-dependent checks skip (not fail) with a how-to
banner, and the run still exits 0 — a skip is not a failure. The cache is gitignored and rebuildable;
the data/raw/*.parquet files can also be copied from the local-data-experiments repo.
Register the MCP server
The server is the universal part — any MCP-aware harness can use it. The commands below write the server's config for that harness.
Harness | Register |
opencode (TUI / Desktop / Web) |
|
Claude Code |
|
Cursor |
|
Cline / Roo (VS Code) | add a stdio MCP server in settings: command |
The shareable registration is opencode.json at the repo root — copy it and the key is
cambridge-open-data-ma-ai.
Deliver the Skill
The Skill is a .claude/skills/ artifact, read natively by Claude Code and omp (drop the
.claude/skills/cambridge-open-data/ folder into the project or ~/.claude/skills/). For every
other harness the Skill is delivered by pasting SKILL.md into that harness's rules / agent /
instructions, because only those harnesses read the .claude/skills/ contract. The server is the
part that works everywhere.
Worked use-cases (the docs/ tutorials)
Budget — FY2027 salary vs. operating budget, cross-referenced by department (
ixg8-tyau⋈5bn4-5wey).Parking tickets — the recent-window trap: the portal cannot answer "tickets paid vs. issued, revenue lost" for the full history.
Privately owned public spaces — 28 spaces, 13 governing special permits, found by spatial discovery across the Open Space and PUD zoning layers.
Property profile, 80 Thorndike St — address + the building-permit era gap (current datasets start 2018-07).
First Street Garage / East End House — three distinct legal instruments; a headline finding that a childcare commitment was never fulfilled (existence is not delivery).
See docs/ for the full tutorials and the gotchas that make the answers trustworthy.
Configuration
secrets and per-machine state live in .env — copy .env.template and fill in. The four
CAM_OPEN_DATA_* credentials are optional; two storage overrides
(CAM_OPEN_DATA_CACHE_DIR, CAM_OPEN_DATA_REPORTS_DIR) default to <repo>/data and
<repo>/docs/reports. The opencode key and the cambridge:// resource namespace are not
environment variables — they are a client-side label, not a secret.
License
MIT — see LICENSE.
Available Tools
8 toolscoverage_auditC
Automated field-population audit: scan every field of a cached dataset and return the least-populated first -- the automated version of 'check field population before trusting a total'. This is how you discover, up front, that a 'complete-looking' column is really a recent window. Use it instead of hand-checking fields one at a time.
| Name | Required | Description | Default |
|---|---|---|---|
| top | No | ||
| threshold | No | ||
| dataset_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description carries the whole burden. It discloses the ordering of results (least-populated first) and that it operates on cached datasets, but never states that it is a read-only operation, whether it scans the full dataset (cost/latency implications of 'every field'), or what a 'complete-looking' result actually means in terms of the threshold. For an unannotated tool this leaves too much unstated.
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?
The core capability is front-loaded in the first clause, which is good. The remaining sentences are padded with quoted colloquial framing ('the automated version of ...', 'complete-looking') that restates the same idea rather than adding new 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?
An output schema exists, so return-value explanation is legitimately omitted, and the read-only nature of an 'audit' is implied. But with no annotations and zero parameter documentation, the definition does not give an agent enough to invoke it correctly — particularly how 'top' and 'threshold' shape results — which is the main completeness gap for a three-parameter tool.
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 0% and all three parameters ('dataset_id', 'top', 'threshold') carry only titles and defaults. The description's 'least-populated first' hints at ordering and hence at 'top', but it never explains that 'top' is a result count or what 'threshold' (default 99) measures — a percentage cutoff, a minimum coverage, or something else. With three undocumented parameters, the description needed to compensate and does not.
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 gives a concrete verb and resource: scan every field of a cached dataset and return them ordered by population, least-populated first. An agent can tell this is a dataset-wide coverage audit rather than a query or a fetch. It does not differentiate itself from the sibling 'field_coverage', which sounds like an adjacent capability, so it falls 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?
It supplies a clear motivating scenario ('check field population before trusting a total') and rules out the manual alternative ('instead of hand-checking fields one at a time'). However, it never names a sibling tool as the alternative or states when this should be skipped in favor of 'field_coverage' or 'describe_dataset', so routing among siblings remains inferred.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
describe_datasetA
Full schema and coverage profile for one dataset. Returns the machine field names (query with these, not the display names), their types, display names, tags, update cadence, and -- when the dataset is cached -- the row count and the dataset's own earliest/latest date (the era-gap signal: a zero result for an old date may mean the dataset predates it, not that nothing happened). Set probe=true to also get coverage_flags: fields that are only partly populated -- the recent-window traps to check before trusting any total or rate.
| Name | Required | Description | Default |
|---|---|---|---|
| probe | No | ||
| dataset_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description carries the full behavioral burden, and it does disclose a lot: the returned metadata, that row count and date range exist only when the dataset is cached, and the interpretive pitfall of zero results for dates predating the data. What it omits is equally material — whether this is read-only (implied but unstated), the cost of probe=true, and whether an invalid or uncached dataset errors versus returning a partial profile.
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?
Purpose is front-loaded in the first clause, and every subsequent sentence adds distinct information rather than restating. The long em-dash parentheticals pack in real value but make the middle of the description harder to parse on a first read.
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 an output schema present, the description is not obliged to enumerate return values, yet it does so with interpretive context the schema cannot convey (era-gap, recent-window traps). The remaining gap isoperational: where dataset_id comes from and whether probe is expensive, both of which matter 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 0%, so the description must supply all parameter meaning. probe is handled well — explicitly opt-in, default off, and tied to a named output (coverage_flags). dataset_id is never discussed: no format, no hint that it comes from search_datasets, no indication of what a bad identifier does.
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 opens with a concrete verb-and-resource statement: schema plus coverage profile for exactly one dataset. It implicitly separates itself from search_datasets and fetch_dataset by framing itself as the metadata/schema lookup, and the aside about querying with machine field names rather than display names signals its role in the workflow. It never names a sibling explicitly, so full differentiation is left to inference.
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 context is clear: call this to learn the machine field names before querying, and set probe=true when partial coverage could distort a total or rate. The era-gap warning explains the practical consequence of ignoring it. It stops short of naming alternatives (e.g. field_coverage, coverage_audit) or stating when this tool is the wrong choice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fetch_datasetA
Pull every row of a dataset via the SODA API and cache it as Parquet (data/raw/.parquet), so it can be cross-referenced in SQL. Supports a server-side $where filter and $select projection. Re-running overwrites the cache; check describe_dataset's cached/fetched_at first to avoid re-pulling time-sensitive data unnecessarily. Large datasets (millions of rows) take time; prefer a $where filter when a subset suffices.
| Name | Required | Description | Default |
|---|---|---|---|
| where | No | ||
| select | No | ||
| dataset_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations supplied, the description carries the burden and does well: it discloses the overwrite-on-rerun semantics, the exact cache path, and the latency risk for multi-million-row datasets. It does not mention authentication/app-token requirements, rate limits, or what happens on a mid-fetch failure, so it stops short of full behavioral disclosure.
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?
Four sentences, front-loaded with the core action and side effect before the optional filtering and performance caveats. Every sentence carries distinct information, though the parenthetical path and the latency note could be tightened slightly.
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?
An output schema exists, so return shape need not be explained, and the description covers the caching model, overwrite risk, filtering options, and cost profile. Missing pieces are auth expectations and failure/partial-cache behavior, which matter for a network-backed fetch that writes to disk.
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 0%, so the description must compensate. It explains that 'where' is a server-side filter and 'select' is a projection, which is real added meaning over the bare string types, but it gives no SODA/SoQL syntax, no quoting rules, and no examples. dataset_id is left entirely implicit.
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 and resource (pull every row of a dataset), names the transport (SODA API), and the concrete side effect (cache as Parquet at data/raw/<id>.parquet) plus the downstream reason (SQL cross-referencing). This clearly separates it from describe_dataset (metadata) and query (SQL execution) among the siblings.
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?
Explicit routing guidance: check describe_dataset's cached/fetched_at before re-running, and prefer a $where filter when only a subset is needed. It gives both a prerequisite check and a condition for narrowing scope, which is exactly the when-to-use/when-not information an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
field_coverageA
Probe how ONE field is actually populated across a cached dataset -- the defence against the recent-window trap. Reports the populated fraction and, for populated rows, the date range they span, and states a warning when the pattern looks like a recent operational window rather than the full history (e.g. a 'balance' field only filled for the last year). Always run this before summing or rate-computing over a field. The field must be a machine name from columns_field_name; a display name raises an actionable error listing the real fields.
| Name | Required | Description | Default |
|---|---|---|---|
| field | Yes | ||
| dataset_id | Yes | ||
| date_field | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description carries the full burden, and it does well: it discloses what the tool computes (populated fraction, date span), that it emits a warning on recent-window patterns, and that a display name produces an actionable error listing real field names. It never states read-only status or cost/latency characteristics, which are the remaining behavioral gaps.
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?
It is front-loaded with the core action and the 'recent-window trap' framing, then the return shape, then the imperative usage rule, then the input constraint. Each sentence carries information, though the parenthetical balance example and the framing clause make it slightly denser than strictly necessary.
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?
An output schema exists, so return values need not be explained, yet the description still covers the key ones and adds the error contract. Completeness is only weakened by the undocumented 'date_field' parameter and by not clarifying how dataset_id is obtained (e.g. via list_cached_datasets).
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 0%, so the description must compensate. It richly documents 'field' (must be a machine name from columns_field_name, display names error out) and implies 'dataset_id' must reference a cached dataset, but 'date_field' is never mentioned at all, leaving one of three parameters with no semantics anywhere.
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 verb and resource: probe how ONE field is populated across a cached dataset, and it explicitly reports the populated fraction plus the date range of populated rows. The capitalized 'ONE field' scopes it clearly against the dataset-level sibling coverage_audit, so an agent can tell them apart without opening either schema.
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?
It gives an explicit trigger: 'Always run this before summing or rate-computing over a field', which tells the agent exactly when this tool is required. It does not name when-not-to-use cases or point to a specific alternative for whole-dataset checks, so it stops short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_cached_datasetsA
List the dataset ids whose rows are cached locally in data/raw/. Only cached datasets can be queried in SQL or audited for coverage; use fetch_dataset to pull one that is not yet cached.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden and does well by disclosing the local cache path and the downstream constraint that only cached datasets can be queried or audited. It does not explicitly state read-only behavior, ordering, or edge cases such as an empty cache, but for a simple listing operation the key behavioral context is present.
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?
The description is two front-loaded sentences with no redundant wording. The core behavior is stated first, followed by the useful dependency and alternative tool.
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-parameter listing tool with an output schema, the description supplies everything needed to select and invoke it correctly: what is listed, where the cache lives, the constraint on downstream use, and the alternative for uncached datasets. Return values need not be explained because an output schema exists.
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 has zero parameters, so the baseline is 4 and there is no parameter meaning for the description to add. The schema is empty and fully covered.
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 uses a specific verb and resource: list dataset ids whose rows are cached locally in data/raw/. It also explicitly contrasts with fetch_dataset for datasets that are not cached, so the agent can distinguish it from sibling tools without opening schemas.
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?
It clearly states when this tool is relevant by noting that only cached datasets can be queried in SQL or audited for coverage. It also names the alternative action, fetch_dataset, for datasets that are not yet cached.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
queryA
Run a DuckDB SELECT over the cached datasets, exposed as one SQL view per dataset named ds_<id_with_underscores> (e.g. ixg8-tyau -> ds_ixg8_tyau). This is the cross-referencing step: join/aggregate across ds_* views. Every Socrata column is a string -- use TRY_CAST(col AS DOUBLE) for numeric work, and expect join keys (e.g. department names) to need normalization before they line up. NOTE: runs arbitrary SQL over local Parquet only; a trusted single-user tool, not sandboxed. Prefer describe_dataset + coverage_audit first so you know the fields exist and are fully populated.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | ||
| limit | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
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 so well: it discloses that it runs arbitrary SQL over local Parquet only, is a trusted single-user tool and not sandboxed. It also warns that every Socrata column is a string, requiring TRY_CAST for numeric work, and that join keys need normalization — behavioral context an agent cannot get from the schema.
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?
Front-loaded with the core action and view-naming rule, then caveats and prerequisites. Dense but nearly every clause carries operational value; the parenthetical example and casting note are well placed. Minor redundancy in the closing prerequisite note, but nothing that should be cut.
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?
Output schema exists, so return values needn't be explained, and the description covers the tricky parts: type coercion, join-key normalization, view naming, and the non-sandboxed trust model. The only real gap is the undocumented `limit` parameter, which matters for large result sets.
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 0%, so the description must compensate. It effectively documents the semantics of the `sql` parameter (SELECT-only, ds_* view namespace, string columns, TRY_CAST) but never mentions the `limit` parameter or its default of 1000, leaving one of two parameters undocumented.
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 and resource ('Run a DuckDB SELECT over the cached datasets') and immediately explains the ds_<id> view naming with a concrete example. It also signals its distinct role as the 'cross-referencing step' for joins/aggregation, which separates it from single-dataset siblings like fetch_dataset and describe_dataset.
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?
Gives explicit sequencing guidance ('Prefer describe_dataset + coverage_audit first so you know the fields exist and are fully populated') and names the exact scenario this tool is for: joining/aggregating across ds_* views. An agent knows both when to reach for it and which siblings to call before it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
refresh_catalogA
Refresh the local catalog cache from the live Socrata Discovery API. Pulls the full dataset listing (~280 datasets: id, name, description, fields, tags, update cadence) into data/catalog.parquet. Run first if search_datasets reports a missing cache, or when the portal may have new datasets. Needs no credentials; the app token in .env only lifts the anonymous rate limit. Returns the count of datasets cached.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations supplied, the description carries the full burden and does well: it discloses the write target (data/catalog.parquet), that no credentials are required, that the .env app token only raises the anonymous rate limit, and the return value. It stops short of saying whether the refresh replaces or merges existing cache entries, which matters for a cache-overwriting operation.
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?
Front-loaded with the action and source, followed by payload contents, trigger conditions, constraints, and return value in that order. Dense but every sentence carries information; the parenthetical field list is the only mildly expendable element.
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-parameter cache-refresh tool with an output schema already documenting the return shape, the description covers source, destination, scale (~280 datasets), prerequisites, rate-limit caveat, and invocation timing. Nothing an agent needs in order to call it correctly 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?
The tool takes zero parameters, so there is nothing for the description to disambiguate; baseline 4 applies. The description correctly spends no words on argument syntax.
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 and resource ('Refresh the local catalog cache') and names the exact upstream source (Socrata Discovery API), so the agent can distinguish it from read-only siblings like search_datasets or list_cached_datasets without opening a schema.
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?
Gives two explicit trigger conditions — 'Run first if search_datasets reports a missing cache' and 'when the portal may have new datasets' — and routes the agent to the sibling that signals the need. This is the when-to-use guidance most definitions omit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_datasetsA
Search the cached dataset catalog by keyword. Matches name, description, category, and tags. Returns each result's id, name, category, link, and -- crucially -- columns_field_name, the machine field names a query actually accepts (NOT columns_name, the human display names; querying with a display name silently returns zero rows). Use this to find a dataset, then describe_dataset to get its full schema before querying.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| keyword | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the burden, and it delivers the highest-value behavioral fact: columns_field_name vs columns_name, with the consequence spelled out ("silently returns zero rows"). It omits catalog staleness/freshness behavior and what limit does when exceeded, so the operational profile is incomplete but far above baseline.
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?
Front-loaded with the core action and closes with the workflow instruction; nearly every clause earns its place. The parenthetical about columns_field_name is deliberately verbose and valuable, though the italics/em-dash framing makes it denser than it needs to be.
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?
An output schema exists, yet the description usefully flags the one returned field that causes silent failures, so it is complete where it matters most for a simple two-parameter search. The remaining gap is catalog freshness and result-limit behavior, which an agent would still have to discover.
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 coverage is 0%, so the description must compensate. It does define what keyword matches against (name, description, category, tags), which is genuine added meaning, but says nothing about the limit parameter (default 20, max, pagination), leaving half the parameters undocumented anywhere.
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 and resource ("Search the cached dataset catalog by keyword") and immediately names the indexed fields (name, description, category, tags), which distinguishes it from list_cached_datasets and query without the agent needing to open schemas.
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?
Explicitly routes the agent forward: "Use this to find a dataset, then describe_dataset to get its full schema before querying" names both the alternative and the ordering condition. It stops short of the full sibling set — no guidance on when to prefer list_cached_datasets or when refresh_catalog is needed first.
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.
8 tool updates
v0.1.0- First observed
coverage_audit - First observed
describe_dataset - First observed
fetch_dataset - First observed
field_coverage - First observed
list_cached_datasets - First observed
query - First observed
refresh_catalog - First observed
search_datasets
TDQS
Scored across 8 tools
Most tools have clearly distinct pipeline roles: refresh_catalog (metadata cache), fetch_dataset (row cache), search/describe (metadata lookup), query (SQL). The only real overlap is field_coverage vs coverage_audit (one field vs all fields), but the descriptions explicitly frame the audit as the batch alternative to the manual check.
Six of eight names follow a clear verb_noun pattern (refresh_catalog, search_datasets, describe_dataset, fetch_dataset, list_cached_datasets), plus the short query. field_coverage and coverage_audit break the pattern as noun phrases, a minor but noticeable deviation.
Eight tools is well-scoped for a dataset-portal pipeline: discovery, schema, fetch, cache listing, coverage checks, and SQL querying, with no redundant entries. Each tool earns its place in a coherent workflow.
The surface covers the full lifecycle from catalog refresh through schema inspection, fetching, coverage auditing, and cross-dataset SQL. Minor gaps exist: no way to delete/evict cached data, no export or pagination of query results, and no catalog filtering by category or update date beyond keyword search.
Maintenance
Related MCP Connectors
Provides access to Civic Plus - See Click Fix, allowing you to interact with your data via an LLM.…
PostgreSQL, MySQL, and SQL Server in one session. 26 read-only MCP tools for AI agents.
The all-in-one data stack for agents. Upload files, run SQL, evolve tables, and render charts.
Connect your ads, shop, analytics, social, CRM and finance platforms once, then let Claude, ChatGPT, Cursor or any MCP client read, join and explain your numbers. Public statistics from the World Bank, IMF, Eurostat, OECD, WHO and SEC filings come as context, searchable and chartable from the same tools. Read-only by design, every number carries its source.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables AI assistants to search, explore, and query San Francisco's open data portal through a standardized interface for public datasets. It supports SQL-like querying via the Socrata platform and includes features like fuzzy column matching and schema caching.4MIT
- AlicenseAqualityAmaintenanceEnables AI assistants to search, explore, and query any CKAN open data portal through natural language, making public datasets accessible without requiring knowledge of the portal's API.201,857 npm60MIT
- AlicenseNot gradedqualityBmaintenanceEnables querying City of Boston open data through the CKAN API, providing access to datasets from data.boston.gov via natural language.489 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables querying and exploring the City of Worcester's open data portal (ArcGIS Hub) through natural language, including dataset search, type filtering, schema inspection, spatial point-in-polygon queries, and geocoding.MIT