seattle-open-data
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., "@seattle-open-datahow many 311 requests were reported in Ballard last month?"
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.
seattle-open-data
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 |
| Find datasets by topic |
| Columns, row count, time coverage, place fields, geo columns |
| Bounded reads and aggregates (SoQL clauses or raw SoQL) |
| Capability summary, SoQL help, guides, error catalog |
Related MCP server: data-seattle
Run
uv run seattle-open-data # stdioClaude Code:
claude mcp add seattle-open-data -- uv run --directory /path/to/seattle-open-data seattle-open-dataOptional: 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> --answersRelease
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 toolsseattle_data_describe_datasetSeattle Data Describe DatasetARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| detail | No | summary (default) or full: adds place-field values and column stats. | |
| dataset_id | Yes | Socrata dataset id, e.g. kzjm-xkqj (from seattle_data_search_datasets). | |
| sample_rows | No | Example rows to include. Default 0. | |
| column_query | No | Only columns whose name or description contains this; omit for all. |
Output Schema
| Name | Required | Description |
|---|---|---|
| title | Yes | |
| source | Yes | |
| columns | Yes | |
| guide_uri | No | |
| row_count | Yes | |
| dataset_id | Yes | |
| geo_columns | Yes | |
| sample_rows | No | |
| geo_unusable | No | |
| place_fields | Yes | |
| queryability | Yes | |
| data_coverage | Yes | |
| time_semantics | Yes | |
| example_queries | No | |
| stats_available | Yes |
TDQS
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.
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.
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.
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.
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.
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 ReferenceARead-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"}.
| Name | Required | Description | Default |
|---|---|---|---|
| topic | No | Default index. | |
| item_id | No | An item from the topic's entries; omit for the topic index. |
Output Schema
| Name | Required | Description |
|---|---|---|
| uri | Yes | |
| body | No | |
| title | Yes | |
| topic | Yes | |
| source | Yes | |
| entries | No | |
| summary | Yes | |
| version | Yes |
TDQS
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.
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.
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.
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.
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.
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 DatasetARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | clauses (default): built from the clause arguments, paged by cursor. soql: run `soql` verbatim, one page. | |
| near | No | Rows within radius_m meters of a point. | |
| soql | No | Full SoQL statement; set mode='soql' and no clause arguments. Not paged: use LIMIT <= page_size and advance OFFSET. | |
| where | No | SoQL predicate, e.g. "datetime >= '2026-09-01T00:00:00'". Never append Z or call now(); both fail. Omit for all rows. | |
| cursor | No | next_cursor from the previous page; omit for page one. | |
| detail | No | summary (default) or full: adds query_url and download_url (CSV of all matching rows). | |
| having | No | Predicate on aggregated rows, e.g. "n > 10"; omit for none. | |
| select | No | Columns or expressions, e.g. ["type", "count(*) AS n"]. Omit for all data columns. | |
| group_by | No | e.g. ["type"]; omit for no grouping. | |
| order_by | No | e.g. ["n DESC"]; omit for arbitrary order. DESC lists nulls first: for most recent, add `col IS NOT NULL` to where. | |
| page_size | No | Most rows to return (default 100; wide rows may return fewer). Omit on a continuation to keep the first page's size. | |
| dataset_id | Yes | Socrata dataset id, e.g. kzjm-xkqj (from seattle_data_search_datasets). | |
| search_text | No | Full-text search across text columns. |
Output Schema
| Name | Required | Description |
|---|---|---|
| rows | Yes | |
| source | Yes | |
| columns | Yes | |
| has_more | Yes | |
| query_url | No | |
| truncated | Yes | |
| dataset_id | Yes | |
| consistency | Yes | |
| next_cursor | No | |
| download_url | No | |
| returned_rows | Yes | |
| effective_query | No | |
| truncation_hint | No | |
| coverage_warnings | No | |
| query_url_omitted | No | |
| truncation_reason | No | |
| download_url_omitted | No |
TDQS
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.
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.
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.
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.
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.
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 DatasetsARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | Words to match; omit to list the most-viewed. | |
| cursor | No | next_cursor from the previous page; omit for page one. | |
| detail | No | summary (default) or full: adds descriptions. | |
| category | No | Exact category name, e.g. Public Safety; omit for all. | |
| page_size | No | Default 10. | |
| asset_scope | No | tabular (default): queryable datasets and filter views. all: adds federated ArcGIS and external links, which cannot be queried. |
Output Schema
| Name | Required | Description |
|---|---|---|
| source | Yes | |
| datasets | Yes | |
| has_more | Yes | |
| next_cursor | No |
TDQS
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.
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.
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.
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.
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.
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.
4 tool updates
v0.1.0- First observed
seattle_data_describe_dataset - First observed
seattle_data_get_reference - First observed
seattle_data_query_dataset - First observed
seattle_data_search_datasets
TDQS
Scored across 4 tools
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).
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.
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.
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
Related MCP Connectors
DataSeattle MCP — Seattle open data (data.seattle.gov, Socrata SODA API).
Search and query government open-data portals (Socrata SODA API).
Provides access to Civic Plus - See Click Fix, allowing you to interact with your data via an LLM.…
Gateway between LLM agents and world data through eight tools and a bundled endpoint catalog.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to query and retrieve San Francisco open data from data.sfgov.org via the Socrata SODA API.246 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables querying Seattle open data from data.seattle.gov via the Socrata SODA API.24 npmMIT
- AlicenseNot gradedqualityBmaintenanceProvides access to Cincinnati open data via the Socrata SODA API, allowing users to query datasets using natural language or direct tool calls.32 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to search, query, and retrieve metadata from the Cook County Open Data catalog using Socrata SoQL queries.23 npmMIT