Skip to main content
Glama
jdzhrch

OpenCivicQuery

by jdzhrch

OpenCivicQuery

OpenCivicQuery is an MCP server that lets reporters ask questions of government open data in plain language, from Claude, ChatGPT, or any other MCP client. It reaches every portal on the Socrata platform: cities, counties, states, and federal agencies.

Status: early development. The interface may change.

Why the answers can be checked

Every answer that contains a number comes with:

  • the counting unit, so "170 eviction notices" never turns into "170 evictions";

  • a completeness flag, so a truncated result is never reported as a total;

  • the exact query and a public link that reruns it on the city's own portal;

  • the source's last update time;

  • an evidence snapshot that freezes the rows behind the figure.

These rules live in the server and travel with every response, so they hold in any client, with or without an extra skill or prompt.

Related MCP server: socrata-mcp

Source packs

Anyone can query any dataset on any Socrata portal. A source pack adds what the raw data does not say: what one row means, how to count it, and the traps. For example, the New York City pack records that restaurant inspection rows are violation citations, so counting rows overstates the number of restaurants.

Datasets without a pack still work. Their responses carry a warning that the row unit is unknown.

Which portals it reaches

Any portal the Socrata catalog lists. Dataset counts below come from the catalog on 2026-10-27 and change often.

Level

Examples (datasets)

City

New York (2,406), Chicago (924), Austin (710), San Francisco (668), Los Angeles (361), Dallas (342), Oakland (313), Cambridge MA (281), Baton Rouge (240), New Orleans (209), Kansas City MO (198), Seattle (147), Buffalo (139), Providence (122)

County

Cook IL (523), Montgomery MD (471), King WA (268), Santa Clara CA (131)

State

Maryland (1,546), Washington (1,070), New York (1,035), Texas (830), Connecticut (654), Colorado (639), Oregon (539), Pennsylvania (352)

Federal

CDC (1,084), Department of Transportation (459), HealthData.gov (147)

Some large publishers use other platforms and are not reachable yet, including Boston, Washington DC, Philadelphia, Denver, Baltimore, San Jose, Los Angeles County, California, and Massachusetts.

Current packs: San Francisco (packs/us-ca-san-francisco.yaml) and New York City (packs/us-ny-new-york-city.yaml). To add a city, see Contributing a source pack.

Install

A public instance runs without login at https://opencivicquery-1040721507408.us-west1.run.app/mcp. The plugin connects to it and adds the Ask Open Data skill, which teaches the assistant how to turn a reporter's question into a countable one, compare periods, and hand back evidence an editor can check.

Claude: the plugin

The plugin has two parts: the skill, and a connection to the server. Claude installs the skill with the plugin, but the connection has to exist as a connector before the plugin can use it.

  1. Add the connector. Paste the URL above as a custom connector with no authentication. On Pro and Max, open Customize, Connectors. On Team and Enterprise, an Owner adds it in Organization settings, Connectors, and each member then connects it under Customize, Connectors.

  2. Install the plugin.

    • Claude desktop app (paid plans): open Customize, Plugins, Add, Add marketplace, and enter jdzhrch/opencivicquery. Then install OpenCivicQuery.

    • Claude Code: run /plugin marketplace add jdzhrch/opencivicquery, then /plugin install opencivicquery@opencivicquery.

    • Organization-wide sync: Claude's organization sync accepts only private or internal repositories, so it cannot sync this public one directly. An organization that wants central distribution can keep a private copy of this repository and sync that. Sync runs when a pull request that raises the plugin version merges into the default branch.

Claude: connection only

In Claude on the web or desktop, open Settings, Connectors, Add custom connector, and paste the URL above. The server's own rules still apply; the skill is not included.

ChatGPT

  • Business or Enterprise workspace: an admin creates a custom app (MCP connector) with the URL above and no authentication, and copies its app ID (asdk_app_...). Then build the plugin package and publish it to the workspace:

    uv run python scripts/build_chatgpt_plugin.py --app-id asdk_app_YOUR_APP_ID

    The package in dist/ holds the same skill as the Claude plugin. For a new version, rebuild and publish again; members do not reinstall.

  • Individual accounts: add the URL as a custom connector in developer mode. The skill is not included.

The hosted instance caps each direct caller, such as Claude Code or a script, at 200 calls a day per IP address, on top of a server-wide daily cap. Claude and ChatGPT connectors reach the server from the vendors' own addresses on behalf of many users, so their calls count only toward the server-wide cap. Audit logs record a salted hash of the address, never the address itself. For heavy use, run your own copy.

Quickstart: run it on your computer

You need uv.

git clone https://github.com/jdzhrch/opencivicquery.git
cd opencivicquery
uv sync

Claude Code

claude mcp add opencivicquery \
  -e OPENCIVICQUERY_CONFIG_PATH="$PWD/deployments/local.yaml" \
  -e OPENCIVICQUERY_TRANSPORT=stdio \
  -e OPENCIVICQUERY_SNAPSHOT_PATH="$HOME/.opencivicquery/snapshots" \
  -- uv --directory "$PWD" run opencivicquery-server

Claude Desktop

Add this to claude_desktop_config.json, with your own paths:

{
  "mcpServers": {
    "opencivicquery": {
      "command": "uv",
      "args": ["--directory", "/path/to/opencivicquery", "run", "opencivicquery-server"],
      "env": {
        "OPENCIVICQUERY_CONFIG_PATH": "/path/to/opencivicquery/deployments/local.yaml",
        "OPENCIVICQUERY_TRANSPORT": "stdio",
        "OPENCIVICQUERY_SNAPSHOT_PATH": "/path/to/snapshots"
      }
    }
  }
}

Then ask, for example: "How many residential evictions were executed in New York City in 2025, by borough?"

The local setup uses no login and no Socrata app token. Socrata serves token-less requests from a shared pool, which is enough for one person.

Run it as a web service

ChatGPT and hosted Claude connectors need a public HTTPS address. Run the HTTP transport:

cp .env.example .env   # then edit
uv run opencivicquery-server

The MCP endpoint is /mcp and the health check is /health. The Dockerfile builds an image for Cloud Run or any container host.

Configuration

A deployment file in deployments/ sets:

Setting

Meaning

socrata.portals

any for every Socrata portal, or a list of domains

socrata.app_token_env

Environment variable that holds a Socrata app token. Use one on any shared instance.

limits.daily_requests

Calls that reach a data source or read a snapshot, per UTC day, per server process

limits.per_portal_per_minute

Calls to one portal in any rolling minute, per server process

limits.per_client_daily

Calls one client may make per UTC day, per server process. A client is one IPv4 address or one IPv6 /64. Leave it out for a local install.

limits.client_address

Required with per_client_daily. peer reads the connection address; x-forwarded-for-last reads the last X-Forwarded-For entry. Use the second only behind exactly one proxy that appends the client address, as Cloud Run does.

limits.shared_networks, limits.shared_networks_files

Address ranges that carry many users at once, such as hosted AI connectors. Their calls skip the per-client cap and meet only the server-wide caps. Files use the {"prefixes": [...]} format that OpenAI publishes.

packs

Source pack files to load

access

Who may sign in, used only when login is on

Environment variables:

Variable

Default

Meaning

OPENCIVICQUERY_CONFIG_PATH

required

Deployment file

OPENCIVICQUERY_AUTH_MODE

open

open (no login) or oauth (Google sign-in)

OPENCIVICQUERY_TRANSPORT

http

http or stdio

OPENCIVICQUERY_HOST

127.0.0.1

HTTP bind address. The Docker image sets 0.0.0.0.

OPENCIVICQUERY_SNAPSHOT_BACKEND

local

local or gcs

OPENCIVICQUERY_SNAPSHOT_PATH

~/.opencivicquery/snapshots

Folder for local snapshots

OPENCIVICQUERY_SNAPSHOT_BUCKET

Bucket for Cloud Storage snapshots

Login is off by default. A newsroom that wants per-reporter attribution can turn on Google sign-in; see deployments/newsroom-with-login.example.yaml and the OAuth variables in .env.example. A deployment file with an access section refuses to start while login is off, so a forgotten setting never opens a private instance to everyone.

The usage caps count per process. A deployment that runs two instances admits up to twice the configured numbers, so set the platform's instance ceiling as the outer bound on cost.

The per-client cap raises the cost of abuse; it does not prevent it. Someone with ten addresses, or one IPv6 block, can still use up the server-wide daily allowance. The server-wide cap and the instance ceiling are what bound cost.

Contributing a source pack

  1. Pick datasets reporters ask about. Find them with the search_datasets tool or on the portal.

  2. Check each dataset against live data before you write anything: what one row represents, whether a unique key holds, which time field to use, and which values are missing or odd.

  3. Write the profile: row_grain, counting_guidance, and caveats. Every statement must come from the agency's own dataset or field description, or from a live query you ran, and nothing you inferred goes in. Put the basis in a comment beside each statement: # official: <where> or # checked <date>: <what the query showed>. A test fails when a statement has no basis. When the data contradicts the documentation, record what the query showed.

  4. Set checked_on to the date you checked.

  5. Add the pack to a deployment file and run the tests.

Plugin development

The skill lives in plugins/opencivicquery/skills/ask-open-data/. Both the Claude plugin and the ChatGPT package use it, and the version in plugins/opencivicquery/.claude-plugin/plugin.json applies to both. Raise that version with every change to the skill or the connection.

Development

uv sync
uv run pytest
uv run ruff check src tests

After you change dependencies, regenerate the pinned requirements:

uv export --frozen --no-dev --no-emit-project --format requirements.txt --output-file requirements.txt

License

MIT. See LICENSE.

Available Tools

6 tools
describe_datasetA

Return a dataset schema, source update time, and, when a source pack documents it, the row grain, counting guidance, and caveats. Call this before writing a query.

NameRequiredDescriptionDefault
domainYesThe portal's hostname, for example data.cityofnewyork.us. Use the domain that search_datasets or list_source_packs returned.
dataset_idYesThe Socrata dataset ID, four characters, a hyphen, and four characters.
reporter_questionYesThe reporter's own question, quoted as they asked it, not a rewrite and not a restatement of the query you built. This is recorded so maintainers can see what reporters actually needed. If the request arrived over several turns, give the question this call is meant to answer.

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations exist, so the description carries the full burden. It does add one genuinely useful behavioral trait — that row grain, counting guidance, and caveats are only present 'when a source pack documents it', so the agent knows the response shape varies. It says nothing about failure modes for a malformed dataset_id, permissions, or latency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no filler, with the returned-content inventory front-loaded and the call-order directive closing it. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description correctly takes on the job of enumerating return values, and the conditional clause handles the variability. The remaining gap is failure behavior — what happens when the dataset_id is invalid or the domain is unknown — which an agent would want before committing to the call.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, with all three parameters documented in detail, including that reporter_question must be the verbatim question. The description adds no parameter-level meaning of its own, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Return') and an enumerated resource set: schema, source update time, row grain, counting guidance, and caveats. That inventory is distinct from what query_dataset or search_datasets would return, so an agent can route between them without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Call this before writing a query' is an explicit ordering directive that ties this tool to the query workflow, which is real usage guidance. It stops short of naming query_dataset as the alternative or stating when the call can be skipped, so it is clear context rather than full when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_snapshotA

Read a temporary or pinned evidence snapshot for verification. The snapshot contains the exact query, frozen rows, source update time, completeness, methodology, and warnings.

NameRequiredDescriptionDefault
snapshot_uriYesThe snapshot URI that query_dataset returned.

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. It does useful work by enumerating the snapshot payload (query, frozen rows, source update time, completeness, methodology, warnings) and hinting at a temporary-vs-pinned lifecycle, but it says nothing about what happens with an expired or invalid URI, permission requirements, or failure modes — significant gaps for a read tool whose only parameter is a URI that can go stale.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with zero waste: the action and scope come first, then the payload contents. Every clause carries information an agent can use.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter read tool with no annotations and no output schema, the description does the essential job of describing what comes back. The remaining hole is behavioral — nothing about expiry, errors, or access requirements for temporary snapshots, which is the main risk an agent needs to know about.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is a single parameter with 100% schema description coverage, and the schema already explains that the URI is the one returned by query_dataset. The description adds no further syntax, format, or validation detail, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description pairs a specific verb (Read) with a specific resource (temporary or pinned evidence snapshot) and states its purpose (for verification). It is clearly distinct from siblings like pin_snapshot and query_dataset, though it doesn't name those alternatives explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: 'for verification' suggests reading back evidence after a query, and the schema notes the URI comes from query_dataset, which establishes the workflow ordering. However, the description itself states no explicit when-to-use condition, no mention of expired/unknown URIs, and no routing away from siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_source_packsA

List the portals and datasets that a source pack documents, with the date each pack was last checked against live data. Datasets outside these packs are still queryable, but their responses carry a ROW GRAIN UNKNOWN warning.

NameRequiredDescriptionDefault

No parameters

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden: it discloses that each entry includes a last-checked date and that non-pack datasets yield a ROW GRAIN UNKNOWN warning, which is genuinely useful behavioral context. It does not cover result size, pagination, ordering, or auth/permission needs for a zero-param listing tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences with the core purpose front-loaded and the warning caveat placed after. Slight redundancy in restating 'these packs', but nothing that fails to earn its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a no-parameter, no-output-schema listing tool, the description conveys what comes back (portals, datasets, freshness dates) and the caveat attached to non-pack data. Only ordering/pagination expectations are unaddressed, a minor gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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; the baseline 4 applies. No misleading parameter language is present.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (list) and resource (portals and datasets documented by a source pack) plus an attribute returned (last-checked date). It is clearly distinct from query_dataset/search_datasets by scope, though it never names a sibling explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied rather than stated: an agent infers this is the inventory/freshness lookup. The note that datasets outside packs remain queryable is useful context but is framed as a consequence, not as an explicit 'use X instead when Y' routing rule.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pin_snapshotA

Preserve a temporary query snapshot indefinitely for a published story. Use the snapshot URI returned by query_dataset.

NameRequiredDescriptionDefault
snapshot_uriYesThe snapshot URI that query_dataset returned.

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. It does disclose the key trait — a temporary snapshot becomes permanent/indefinite — but omits permissions required, what happens if the snapshot has already expired, and whether the pin is reversible.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, both earning their place, with the action and durability effect front-loaded followed by the provenance hint. Nothing is padded, though it is terse enough that slightly more behavioral detail could have fit.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

A one-parameter, non-read-only action with full schema coverage and no output schema needs little prose, and the description covers the core effect. Missing only edge-case behavior such as expiry or permission failures, which is a modest gap rather than a blocking one.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so snapshot_uri is already documented in the schema. The description only restates its provenance ('returned by query_dataset'), which is minor added value; baseline 3 applies 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.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (preserve/pin) plus resource (temporary query snapshot) and the resulting effect (indefinitely). The qualifier 'for a published story' narrows scope, and the mention of query_dataset clearly separates it from the retrieval sibling get_snapshot.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage ('Use the snapshot URI returned by query_dataset') but never states when a caller should pin versus leave a snapshot temporary, nor does it mention any alternative or inverse operation. A usable hint exists, but the when/when-not decision is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

query_datasetA

Run a read-only SoQL query with a mandatory row ceiling. The response on success states completeness, warnings, methodology, source update time, the public dataset page, the exact query, a public live-result query_url when the source supports one, and the URI of an immutable evidence snapshot. If completeness is truncated, revise the query or report the limitation. The response also carries presentation_rules, which govern how you must state its figures to the user; obey every rule listed there before you write your reply. Failures return isError=true and an error object with the failure code, message, argument, and http_status. A failed query has no data result or snapshot.

NameRequiredDescriptionDefault
whereNo
domainYesThe portal's hostname, for example data.cityofnewyork.us. Use the domain that search_datasets or list_source_packs returned.
selectYes
group_byNo
max_rowsNo
order_byNo
dataset_idYesThe Socrata dataset ID, four characters, a hyphen, and four characters.
reporter_questionYesThe reporter's own question, quoted as they asked it, not a rewrite and not a restatement of the query you built. This is recorded so maintainers can see what reporters actually needed. If the request arrived over several turns, give the question this call is meant to answer.

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does so thoroughly: it discloses read-only behavior, row limits, success metadata, completeness/truncation semantics, presentation_rules, and failure behavior including isError=true and the error object fields. It also clarifies that failed queries produce no data result or snapshot.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and then provides behaviorally important details about success, truncation, presentation rules, and failure. It is slightly dense, especially the long list of success response fields, but every sentence contributes operational information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The output schema exists and the description explains result and failure behavior well, but the tool has 8 parameters, no annotations, and low schema description coverage. The description is therefore complete on post-query behavior but thin on how to construct the query correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 38% across 8 parameters, so the description needed to compensate by explaining where, select, group_by, order_by, and max_rows. It only indirectly alludes to SoQL and a row ceiling; most parameter meanings remain undocumented beyond their names.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: run a read-only SoQL query against a dataset, with a mandatory row ceiling. It clearly distinguishes this from sibling tools like search_datasets, describe_dataset, and get_snapshot, which handle discovery, metadata, and snapshots rather than row queries.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the query purpose and the note about handling truncated completeness, but the description does not explicitly say when to choose query_dataset over describe_dataset, get_snapshot, or search_datasets. It gives post-result guidance rather than tool-selection guidance.

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 Socrata catalog for datasets. Leave domain empty to search every portal, or give a portal hostname to search one. Each result says whether a source pack documents it. Search results do not carry a quality, review, reliability, or publication status.

NameRequiredDescriptionDefault
limitNo
domainNoThe portal's hostname, for example data.cityofnewyork.us. Use the domain that search_datasets or list_source_packs returned.
search_termYes
reporter_questionYesThe reporter's own question, quoted as they asked it, not a rewrite and not a restatement of the query you built. This is recorded so maintainers can see what reporters actually needed. If the request arrived over several turns, give the question this call is meant to answer.

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It discloses two genuinely non-obvious behaviors: results flag whether a source pack documents them, and results do not carry quality/review/reliability/publication status. However, it omits return shape, pagination behavior, auth requirements, and rate limits, leaving meaningful gaps for a search tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, purpose front-loaded, then scoping, then result semantics. No repetition of the name or title and no filler; the status caveat is a single clause that carries real information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a four-parameter search tool with no annotations and no output schema, the description covers purpose, domain scoping, and result caveats adequately. The main residual gap is that the return structure beyond the source-pack flag is unexplained, and no alternative-tool routing is offered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 50%, so the description must compensate — and it does so for the one genuinely ambiguous parameter by explaining that an empty domain searches every portal while a hostname scopes to one. search_term and limit (1-50, default 10) are self-evident, and reporter_question is well documented in the schema itself.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Search the Socrata catalog for datasets') and clarifies scope (all portals vs one). It implicitly separates itself from siblings like list_source_packs and describe_dataset, but never names them explicitly, so the differentiation is inferable rather than stated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The domain guidance ('Leave domain empty to search every portal, or give a portal hostname') is scoping help, not when-to-use guidance. The closing caveat about results lacking quality/review/reliability/publication status usefully signals a limitation, but the description never says when to prefer describe_dataset or query_dataset instead.

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.

  1. 6 tool updatesv0.1.0
    • First observeddescribe_dataset
    • First observedget_snapshot
    • First observedlist_source_packs
    • First observedpin_snapshot
    • First observedquery_dataset
    • First observedsearch_datasets

TDQS

A4/5.0

Scored across 6 tools

Disambiguation5/5

Each tool has a distinct role across the lifecycle: discovering packs/datasets, inspecting schema, running queries, and reading or pinning snapshots. The pair pin_snapshot and get_snapshot is clearly separated by write/preserve versus read/verify semantics. Search and listing tools are differentiated by catalog search versus documented source packs.

Naming Consistency5/5

All tool names follow a consistent snake_case verb_noun pattern (list_source_packs, search_datasets, describe_dataset, query_dataset, pin_snapshot, get_snapshot). The convention is predictable throughout.

Tool Count5/5

Six tools is well scoped for a civic data query server, covering discovery, schema inspection, querying, and evidence snapshots without unnecessary surface area. Each tool clearly earns its place.

Completeness4/5

The surface covers the core workflow from dataset discovery through schema inspection, query execution, and snapshot verification/pinning. Minor gaps exist around managing pinned snapshots, such as listing or unpinning them, but these do not block the primary use case.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    An MCP server that gives Claude deep access to US public data -- demographics, economics, crime, employment, weather, housing, transit, schools, budgets, and more across 30+ cities for government intelligence workflows.
    28
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    An MCP server that gives LLM agents typed, cached access to civic open-data portals via Socrata (SODA 2.1 + Discovery API), enabling search, query, profiling, sampling, and CSV export of datasets.
    6
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    An MCP server that puts open data on tap, enabling LLM clients to search, inspect, and query 30,000+ civic datasets from Socrata portals with built-in guardrails like row caps and actionable error messages.
    4
    1
    MIT