Skip to main content
Glama
briandconnelly

seattle-open-data

seattle-open-data

CI Python License: MIT

An agent-friendly MCP server for Seattle Open Data (Socrata SODA2).

Status: alpha (0.1.0). All four tools work against the live portal, with curated guides for seven flagship datasets. See evals/results for the agent evaluation.

Tools

Tool

Purpose

seattle_data_search_datasets

Find datasets by topic

seattle_data_describe_dataset

Columns, row count, time coverage, place fields, geo columns

seattle_data_query_dataset

Bounded reads and aggregates (SoQL clauses or raw SoQL)

seattle_data_get_reference

Capability summary, SoQL help, guides, error catalog

Related MCP server: data-seattle

Run

uv run seattle-open-data          # stdio

Claude Code:

claude mcp add seattle-open-data -- uv run --directory /path/to/seattle-open-data seattle-open-data

Optional: set SOCRATA_APP_TOKEN to use a Socrata application token. A rejected token is reported as app_token_rejected, never silently dropped.

To build the installable MCPB bundle (needs the mcpb CLI): make mcpb.

Develop

uv sync
uv run pytest
uv run ruff check && uv run ruff format --check && uv run ty check
UPDATE_SNAPSHOTS=1 uv run pytest tests/test_contract.py   # after an intended tool-surface change
uv run pytest --run-integration -m integration            # live tests against data.seattle.gov
uv run python evals/run.py [--host claude|codex] <out_dir> [task_id ...]
uv run python evals/report.py <out_dir> --answers

Release

Bump the version in pyproject.toml, run make manifest, move the CHANGELOG [Unreleased] entries under the new version, merge, then push a vX.Y.Z tag. The release workflow checks that the versions agree, builds the wheel, sdist, and .mcpb, and attaches all three to a GitHub Release. Publishing to PyPI is off until the repository variable PUBLISH_PYPI is true.

License

MIT

Available Tools

4 tools
seattle_data_describe_datasetSeattle Data Describe DatasetA
Read-only

Decide whether and how to query a dataset: columns, live row count, data_coverage (actual time range), place fields for "in " questions (with reliability), and geo columns for near.

Call before querying a dataset whose columns you do not know. For area questions, use detail="full". Filter a place field on its value, never its label; an area may span several values. Example: {"dataset_id": "kzjm-xkqj", "detail": "full"}. Typically 1-3 s; fails with query_timeout after 30 s.

ParametersJSON Schema
NameRequiredDescriptionDefault
detailNosummary (default) or full: adds place-field values and column stats.
dataset_idYesSocrata dataset id, e.g. kzjm-xkqj (from seattle_data_search_datasets).
sample_rowsNoExample rows to include. Default 0.
column_queryNoOnly columns whose name or description contains this; omit for all.

Output Schema

ParametersJSON Schema
NameRequiredDescription
titleYes
sourceYes
columnsYes
guide_uriNo
row_countYes
dataset_idYes
geo_columnsYes
sample_rowsNo
geo_unusableNo
place_fieldsYes
queryabilityYes
data_coverageYes
time_semanticsYes
example_queriesNo
stats_availableYes

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already cover the safety profile (readOnlyHint, openWorldHint), so the description earns credit for adding latency and failure behavior: 'Typically 1-3 s; fails with query_timeout after 30 s.' It also flags a non-obvious data caveat (place values vs labels, areas spanning multiple values), which is genuinely beyond structured fields.

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?

Front-loads the payoff, then usage rules, then an example and a performance note. Dense but every line carries decision-relevant information; the enumerated return list is a touch verbose but justified for a metadata tool.

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

Completeness5/5

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

An output schema exists, so return formatting need not be explained. The description supplies everything an agent needs to decide whether to call it, choose detail, and interpret place fields, matching the tool's complexity.

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 100%, so the baseline is 3, but the description adds real decision semantics: when to set detail="full" (area questions) and how to use place fields (filter on value, not label). It also supplies a concrete example call.

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 (decide whether/how to query) and enumerates exactly what the tool returns: columns, live row count, data_coverage, place fields with reliability, and geo columns. The mention of querying clearly separates it from seattle_data_search_datasets and seattle_data_get_reference.

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?

Gives a clear trigger ('Call before querying a dataset whose columns you do not know') and conditional guidance ('For area questions, use detail="full"'), plus a field-filtering rule. It stops short of explicitly naming seattle_data_query_dataset as the next step or stating when this call can be skipped.

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

seattle_data_get_referenceSeattle Data Get ReferenceA
Read-only

Read the server's reference: capability summary, SoQL help, dataset guides, and the full error catalog. Call with no arguments for the index.

Example: {"topic": "soql", "item_id": "dates"}.

ParametersJSON Schema
NameRequiredDescriptionDefault
topicNoDefault index.
item_idNoAn item from the topic's entries; omit for the topic index.

Output Schema

ParametersJSON Schema
NameRequiredDescription
uriYes
bodyNo
titleYes
topicYes
sourceYes
entriesNo
summaryYes
versionYes

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds useful behavioral context beyond that: the no-argument default returns the index, and the reference is organized into named sections that can be drilled into by topic/item_id.

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 tight sentences plus a single example line; the content list is front-loaded and every clause carries information (what is retrievable, default behavior, worked example). No filler.

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 an output schema present and zero required parameters, the description does not need to explain return shapes. It covers content scope, default behavior, and parameterization adequately; only an explicit pointer away from the dataset siblings would make it fully complete.

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 description coverage is 100% and the enum values are self-explanatory, so the baseline is 3. The description adds an illustrative example ({"topic": "soql", "item_id": "dates"}) that demonstrates the two-level topic→item lookup semantics, which is a genuine increment over the schema.

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 ('Read') and a well-scoped resource ('the server's reference'), then enumerates exactly what the reference contains: capability summary, SoQL help, dataset guides, and error catalog. This clearly separates it from the dataset-oriented siblings (search/describe/query), which operate on data rather than documentation.

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 with no arguments for the index' plus a concrete call example tells the agent how to enter the reference at two levels (index vs. specific item). It gives clear context for use but never explicitly contrasts itself with alternatives such as seattle_data_describe_dataset, so it stops short of 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.

seattle_data_query_datasetSeattle Data Query DatasetA
Read-only

Run a bounded read or aggregate on one dataset; paging stops at 10,000 rows.

For counts and breakdowns, use count() with group_by, not row paging. With cursor, send only dataset_id, cursor, and optionally page_size or detail. For all rows, give the user download_url (detail="full") instead of paging. Example: {"dataset_id": "kzjm-xkqj", "select": ["type", "count() AS n"], "group_by": ["type"], "order_by": ["n DESC"]}. Typically 1-5 s; fails with query_timeout after 30 s.

ParametersJSON Schema
NameRequiredDescriptionDefault
modeNoclauses (default): built from the clause arguments, paged by cursor. soql: run `soql` verbatim, one page.
nearNoRows within radius_m meters of a point.
soqlNoFull SoQL statement; set mode='soql' and no clause arguments. Not paged: use LIMIT <= page_size and advance OFFSET.
whereNoSoQL predicate, e.g. "datetime >= '2026-09-01T00:00:00'". Never append Z or call now(); both fail. Omit for all rows.
cursorNonext_cursor from the previous page; omit for page one.
detailNosummary (default) or full: adds query_url and download_url (CSV of all matching rows).
havingNoPredicate on aggregated rows, e.g. "n > 10"; omit for none.
selectNoColumns or expressions, e.g. ["type", "count(*) AS n"]. Omit for all data columns.
group_byNoe.g. ["type"]; omit for no grouping.
order_byNoe.g. ["n DESC"]; omit for arbitrary order. DESC lists nulls first: for most recent, add `col IS NOT NULL` to where.
page_sizeNoMost rows to return (default 100; wide rows may return fewer). Omit on a continuation to keep the first page's size.
dataset_idYesSocrata dataset id, e.g. kzjm-xkqj (from seattle_data_search_datasets).
search_textNoFull-text search across text columns.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rowsYes
sourceYes
columnsYes
has_moreYes
query_urlNo
truncatedYes
dataset_idYes
consistencyYes
next_cursorNo
download_urlNo
returned_rowsYes
effective_queryNo
truncation_hintNo
coverage_warningsNo
query_url_omittedNo
truncation_reasonNo
download_url_omittedNo

TDQS

A4.9/5.0
Behavior5/5

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

Annotations only cover read-only and open-world status; the description adds the operational traits that matter: a 10,000-row paging ceiling, typical latency of 1-5 s, and a hard failure mode ('query_timeout after 30 s'). The cursor continuation constraint is a behavioral rule not derivable from the schema alone.

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?

Front-loads the core operation and row cap, then layers paging rules, an alternative path, a compact JSON example, and timing. Every sentence carries actionable information with no filler.

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

Completeness5/5

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

For a 13-parameter query tool with an output schema, the description covers the things the schema and annotations cannot: aggregation-vs-paging guidance, continuation semantics, row limits, and timeout behavior. Nothing an agent needs before invoking it is missing.

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 description coverage is 100%, so the baseline is 3; the description still adds value by constraining continuation payloads (only dataset_id, cursor, and optionally page_size or detail) and by pairing count(*) with group_by in the worked example.

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 and resource ('run a bounded read or aggregate on one dataset') plus an explicit scope limit ('paging stops at 10,000 rows'). This cleanly separates it from the sibling search/describe/reference tools, which don't execute queries against a dataset.

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

Usage Guidelines5/5

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

Gives explicit routing rules: use count(*) with group_by for counts and breakdowns rather than paging, and hand the user download_url with detail='full' instead of paging for all rows. It also states what to send on a continuation call with cursor, which is exactly the when/when-not guidance an agent needs.

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

seattle_data_search_datasetsSeattle Data Search DatasetsA
Read-only

Find Seattle datasets by topic. Call first when you lack a dataset id.

Only results with queryability "supported" can be described or queried. Example: {"query": "fire 911"}. Typically 1-3 s.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryNoWords to match; omit to list the most-viewed.
cursorNonext_cursor from the previous page; omit for page one.
detailNosummary (default) or full: adds descriptions.
categoryNoExact category name, e.g. Public Safety; omit for all.
page_sizeNoDefault 10.
asset_scopeNotabular (default): queryable datasets and filter views. all: adds federated ArcGIS and external links, which cannot be queried.

Output Schema

ParametersJSON Schema
NameRequiredDescription
sourceYes
datasetsYes
has_moreYes
next_cursorNo

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already declare readOnlyHint and openWorldHint, so the safety profile is covered. The description adds genuinely new behavior: the queryability filter that gates downstream usability of results, and expected latency ('Typically 1-3 s'). Pagination/cursor behavior is left to 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.

Conciseness4/5

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

Four short sentences, front-loaded with purpose then routing, then the constraint, then a concrete example and latency. Every line carries information; slight compression leaves terms like 'queryability' implicit relative to the schema's 'queryable' phrasing.

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

Completeness5/5

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 and cursor handling need not be restated. Given the tool's low complexity (no required params, all-optional filters), purpose, routing, the queryability gate, an example and latency are sufficient for an agent to call it correctly.

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% with defaults and enum meanings spelled out for all six parameters, so the baseline is 3. The single example {"query": "fire 911"} illustrates query matching but adds little semantic detail beyond the schema's own 'Words to match' wording.

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 and resource ('Find Seattle datasets') plus the search dimension ('by topic'), so an agent knows it is a search tool rather than a fetch/describe tool. The routing line 'Call first when you lack a dataset id' further separates it from the describe/query siblings 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?

Gives an explicit call condition ('Call first when you lack a dataset id') and a downstream constraint ('Only results with queryability "supported" can be described or queried'), which tells the agent what is usable next. It stops short of naming the alternative tool by name or stating when not to use this one, so it is strong but not fully explicit.

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. 4 tool updatesv0.1.0
    • First observedseattle_data_describe_dataset
    • First observedseattle_data_get_reference
    • First observedseattle_data_query_dataset
    • First observedseattle_data_search_datasets

TDQS

A4.6/5.0

Scored across 4 tools

Disambiguation5/5

Each tool targets a distinct phase of the workflow: search_datasets (discovery), describe_dataset (schema inspection), query_dataset (execution), and get_reference (documentation). There is no overlap between their purposes, and descriptions explicitly guide sequencing (call search first, call describe before querying).

Naming Consistency5/5

All four tools share the seattle_data_ prefix and follow a consistent verb_noun pattern (search_datasets, describe_dataset, query_dataset, get_reference). The convention is entirely predictable.

Tool Count5/5

Four tools is a well-scoped, minimal surface for a read-only data portal: discover, inspect, query, and reference are exactly the operations needed. Each tool clearly earns its place with no redundancy.

Completeness5/5

The set covers the full read lifecycle of open-data access (search, describe, bounded query/aggregate, and reference/help) for a read-only public data domain where create/update/delete are not applicable. No dead ends are apparent.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers