io.github.cyanheads/socrata-mcp-server
Search and query government open-data portals (Socrata SODA API).
ماذا يمكنك أن تفعل مع io.github.cyanheads/socrata-mcp-server؟
- Full Socrata SODA 2.1 API integration — SoQL query builder with select, where, group, having, order, search, limit, offset
- Discovery API for cross-portal dataset search and per-portal dataset counts (curated 39-portal catalog, counts cached ~24h)
- App token support (
SOCRATA_APP_TOKEN) for higher per-IP rate limits - Configurable default portal domain via
SOCRATA_DEFAULT_DOMAIN - DataCanvas spillover (DuckDB, bundled) — large query results register as SQL tables for analytical queries
- Assembled SoQL string echoed in every
socrata_query_datasetresponse so agents can learn and refine syntax - Recovery hints on empty results — echoes applied filters with specific suggestions for broadening
- Truncation disclosure —
truncated/shown/capfields when rows fill the limit, with guidance to page or raise the limit, naming the staged table and both dataframe tools when the result spilled
التثبيت
أضف هذا إلى إعدادات MCP في عميلك (Claude Desktop: claude_desktop_config.json، وCursor: .cursor/mcp.json، ويستخدم VS Code وغيره الصيغة نفسها «mcpServers»).
claude mcp add --transport http socrata-mcp-server 'https://socrata.caseyjhand.com/mcp'
{
"mcpServers": {
"socrata-mcp-server": {
"type": "http",
"url": "https://socrata.caseyjhand.com/mcp"
}
}
}
@cyanheads/socrata-mcp-serverclaude mcp add socrata-mcp-server -e 'SOCRATA_APP_TOKEN=<SOCRATA_APP_TOKEN>' -e 'SOCRATA_DEFAULT_DOMAIN=data.seattle.gov' -e 'SOCRATA_DATAFRAME_DROP_ENABLED=false' -e 'MCP_LOG_LEVEL=info' -- npx -y @cyanheads/socrata-mcp-server@0.5.1
{
"mcpServers": {
"socrata-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/socrata-mcp-server@0.5.1"
],
"env": {
"SOCRATA_APP_TOKEN": "<SOCRATA_APP_TOKEN>",
"SOCRATA_DEFAULT_DOMAIN": "data.seattle.gov",
"SOCRATA_DATAFRAME_DROP_ENABLED": "false",
"MCP_LOG_LEVEL": "info"
}
}
}
}
متغيرات البيئة
SOCRATA_APP_TOKENSocrata app token (X-App-Token header). Without a token, requests share a throttled pool per source IP. Free to register at any Socrata portal.SOCRATA_DEFAULT_DOMAINDefault portal domain when domain is omitted from tool calls (e.g. data.seattle.gov, data.cityofnewyork.us).SOCRATA_DATAFRAME_DROP_ENABLEDSet to true to enable socrata_dataframe_drop, which deletes staged DataCanvas data. Off, the tool is omitted from the tool list.MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
@cyanheads/socrata-mcp-serverclaude mcp add socrata-mcp-server -e 'MCP_TRANSPORT_TYPE=<MCP_TRANSPORT_TYPE>' -e 'SOCRATA_APP_TOKEN=<SOCRATA_APP_TOKEN>' -e 'SOCRATA_DEFAULT_DOMAIN=data.seattle.gov' -e 'SOCRATA_DATAFRAME_DROP_ENABLED=false' -e 'MCP_HTTP_HOST=127.0.0.1' -e 'MCP_HTTP_PORT=3010' -e 'MCP_HTTP_ENDPOINT_PATH=/mcp' -e 'MCP_AUTH_MODE=none' -e 'MCP_LOG_LEVEL=info' -- npx -y @cyanheads/socrata-mcp-server@0.5.1
{
"mcpServers": {
"socrata-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/socrata-mcp-server@0.5.1"
],
"env": {
"MCP_TRANSPORT_TYPE": "<MCP_TRANSPORT_TYPE>",
"SOCRATA_APP_TOKEN": "<SOCRATA_APP_TOKEN>",
"SOCRATA_DEFAULT_DOMAIN": "data.seattle.gov",
"SOCRATA_DATAFRAME_DROP_ENABLED": "false",
"MCP_HTTP_HOST": "127.0.0.1",
"MCP_HTTP_PORT": "3010",
"MCP_HTTP_ENDPOINT_PATH": "/mcp",
"MCP_AUTH_MODE": "none",
"MCP_LOG_LEVEL": "info"
}
}
}
}
متغيرات البيئة
MCP_TRANSPORT_TYPESelects the HTTP transport.SOCRATA_APP_TOKENSocrata app token (X-App-Token header). Without a token, requests share a throttled pool per source IP. Free to register at any Socrata portal.SOCRATA_DEFAULT_DOMAINDefault portal domain when domain is omitted from tool calls (e.g. data.seattle.gov, data.cityofnewyork.us).SOCRATA_DATAFRAME_DROP_ENABLEDSet to true to enable socrata_dataframe_drop, which deletes staged DataCanvas data. Off, the tool is omitted from the tool list.MCP_HTTP_HOSTThe hostname for the HTTP server.MCP_HTTP_PORTThe port to run the HTTP server on.MCP_HTTP_ENDPOINT_PATHThe endpoint path for the MCP server.MCP_AUTH_MODEAuthentication mode to use: 'none', 'jwt', or 'oauth'.MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
التوثيق
مأخوذ من ملف README للمشروع على GitHub ويُحدَّث أسبوعيًا. تفتح الروابط على GitHub.
المحتويات
@cyanheads/socrata-mcp-server
Search and query government open-data portals (Socrata SODA API) via MCP. STDIO or Streamable HTTP.
7 Tools • 2 Resources • 1 Prompt
Public Hosted Server: https://socrata.caseyjhand.com/mcp
Overview
Query city, county, state, and federal open-data portals built on Socrata. Discover portals and datasets, inspect column schemas, and run SoQL queries, or SQL over large result sets.
Tools
| Tool | Description |
|---|---|
socrata_list_portals | List known Socrata-powered government open-data portals with domain, organization name, and approximate dataset count |
socrata_find_datasets | Search for datasets across all Socrata portals or scope to one portal via the Discovery API |
socrata_get_dataset | Fetch full metadata and typed column schema for a dataset by ID — required before writing SoQL queries |
socrata_query_dataset | Execute a SoQL query against any dataset: search, select, where, group, having, order, with DataCanvas spillover |
socrata_dataframe_describe | List registered tables in a DataCanvas session — schema, row count, column names |
socrata_dataframe_query | Run SELECT-only SQL against DataCanvas tables populated by socrata_query_dataset |
socrata_dataframe_drop | Drop a DataCanvas canvas, or one table on it — opt-in via SOCRATA_DATAFRAME_DROP_ENABLED=true |
Resources
| Resource | Description |
|---|---|
socrata://datasets/{domain}/{datasetId} | Fetch full metadata and column schema for a dataset by stable URI — same payload as socrata_get_dataset |
socrata://portals | Paginated list of known Socrata portals with organization name and approximate dataset count |
All resource data is also reachable via tools. Use the corresponding tool for agent workflows — resources are for clients that support URI-addressable data.
Prompts
| Prompt | Description |
|---|---|
explore_open_data | Structured six-step civic data investigation workflow: find portal → discover datasets → inspect schema → query → aggregate → synthesize |
Capability reference
socrata_list_portals tool
- Curated catalog of 39 well-known city, county, state, and federal portals — every member verified live in the Discovery catalog
- Per-portal dataset counts fetched live from the Discovery API, cached ~24 hours (
0means the portal exposes no dataset assets to the catalog;nullmeans the count is temporarily unavailable) - Client-side substring filtering on domain or organization name; pagination up to 200 per page with offset
- Returns domain (pass to
socrata_find_datasets), organization name, and approximate dataset count; the count includes datasets a portal federates from another Socrata tenant (Austin, Illinois, Mesa, and San Francisco publish through a data hub; Seattle catalogs under a sibling tenant) - Never fails on an upstream error — a count that cannot be fetched comes back
nulland the listing still returns
socrata_find_datasets tool
- Full-text query across dataset names/descriptions; scope with
domain, filter bycategories/tags, restrictonlyto an asset type (datasets, maps, files, calendars, stories) - Sort by relevance, page views, created date, or updated date; up to 100 per page with offset pagination
- Returns dataset IDs, names, domains, tags, update timestamps, and
column_names— the API field names SoQL takes (cuisine_description, not the display labelCUISINE DESCRIPTION), computed-region columns dropped — callsocrata_get_datasetfor typed schema before writing queries - Recovery hints on empty results — echoes applied filters and suggests how to broaden
domaintakes a bare hostname; URL forms (https://data.cdc.gov/) are reduced to the host. A scoped search covers every dataset the portal publishes, including ones federated from another Socrata tenant, reported under the portal's own domain- Typed errors:
rate_limited(retryable) when the Discovery API returns 429,unknown_domainwhen the Discovery catalog does not index the domain,invalid_domainwhen the domain is not a hostname
socrata_get_dataset tool
- Returns field names, Socrata data types, descriptions, row count (with
row_count_sourceprovenance), and licensing when available - Column
data_typedetermines WHERE clause syntax:Number→ bare literals (year=2023),Text→ single-quoted strings (year='2023') - Excludes computed region columns (
:@computed_region_*) to reduce noise; includes per-column non-null counts when available - Dataset IDs are portal-scoped — pass the
domainfrom the samesocrata_find_datasetsresult; URL-form domains are reduced to the host - Typed errors:
invalid_id(malformed four-by-four ID),not_found(no such dataset on the domain queried — the message names the ID and domain, and the recovery names the portal that holds the ID when the Discovery catalog knows it),unknown_domain(the domain is not serving the Socrata API — it does not resolve, is not a Socrata portal, or redirects elsewhere; fails on the first attempt),invalid_domain(not a hostname),rate_limited(retryable; honors the upstreamRetry-After) - Always call before writing a
socrata_query_datasetWHERE clause
socrata_query_dataset tool
searchfor quick full-text lookup ($q), or combineselect/where/group/having/orderfor full analytical control — clauses reference columns by API field name (field_namefromsocrata_get_dataset), never the display label; operators=,!=,>,<,LIKE,IN(...),BETWEEN,IS NULL,starts_with(),contains(),AND,OR,NOT- Aggregation via
count(*),sum(),avg(),min(),max()withgroup/having not_tabularidentifies assets without queryable rows; search withonly: "datasets".query_rejectedidentifies a gateway refusal of query clauses when a bare row request succeeds; simplify the query and use SoQLcase(condition, value, true, fallback)for conditional aggregates.- Up to 5000 rows per call with offset pagination;
total_countreturned when a plain row query is truncated (absent for grouped/aggregate queries) assembled_queryechoes the SoQL string for learning the syntax; all SODA 2.1 row values are strings except geo/location columns, which return nested objects- When
CANVAS_PROVIDER_TYPE=duckdband the page fillslimit, up to 50,000 matching rows spill to a DataCanvas table whatever thelimit(canvas_id,table_name,canvas_row_count) — list its columns withsocrata_dataframe_describe, then run SQL withsocrata_dataframe_query. A smalllimit(e.g. 10) stages a large match without a large inline page - Typed errors:
not_tabular,query_rejected,invalid_id,not_found(names the ID, the domain queried, and the portal holding the ID when known),unknown_domain,invalid_domain,soql_error(bad SoQL, unknown column, or type mismatch — carries the upstreamsocrataCodeand, when upstream names it, the offendingcolumn; the recovery hint matches the code: API field names for a parse error, both fixes for an unknown identifier, the quoting rule for a type mismatch),rate_limited(retryable; honors the upstreamRetry-After)
socrata_dataframe_describe tool
- Requires
canvas_idfrom a priorsocrata_query_datasetspill — canvases cannot be enumerated, so omitting it fails withcanvas_id_requiredrather than listing tables - Shows table name, row count, and DuckDB column types for each registered table (SODA
number→DOUBLE) - Only meaningful when
CANVAS_PROVIDER_TYPE=duckdbis set - Typed errors:
canvas_id_required,canvas_not_found(expired or unknown token — re-runsocrata_query_datasetto stage a fresh canvas)
socrata_dataframe_query tool
- SELECT-only SQL against a
canvas_idtable staged bysocrata_query_dataset; DDL, DML, file references, file-reading functions, and engine-setting functions (current_schema,current_setting) are rejected. Use direct table references instead ofquery_table;query()accepts only a single SQL string literal. Qualify a staged column namedcurrent_schemawith its table (t.current_schema). - Spilled columns are typed from the SODA response headers:
numbercolumns (aggregate aliases included) areDOUBLE, so numeric comparisons work without a cast (year > 2020,amount < 500); text and timestamp columns stayVARCHAR— compare times withCAST(date AS TIMESTAMP) - Up to 10,000 rows per call, default 1000
- Typed errors:
canvas_disabled(CANVAS_PROVIDER_TYPE=none),canvas_not_found,table_not_found,sql_rejected(non-SELECT, system catalog access, or a denied function) - Works out of the box — DuckDB ships as a regular dependency and is enabled by default;
CANVAS_PROVIDER_TYPE=nonedisables it
socrata_dataframe_drop tool
- Opt-in: omitted from the tool list until
SOCRATA_DATAFRAME_DROP_ENABLED=true; also needsCANVAS_PROVIDER_TYPE=duckdb - Without
table_name, drops the whole canvas — itscanvas_idstops resolving forsocrata_dataframe_describeandsocrata_dataframe_query. Withtable_name, drops that one table and leaves the canvas and its other tables in place - Reports the dropped tables with their row counts and the tables still on the canvas
- Deletes only the staged copy —
socrata_query_datasetcan stage the data again - Typed errors:
canvas_disabled(CANVAS_PROVIDER_TYPE=none),canvas_not_found(unknown, expired, or already dropped),table_not_found(carries the canvas'savailableTables)
socrata://datasets/{domain}/{datasetId} resource
- Returns the same payload as
socrata_get_dataset— field names, data types, descriptions, row count, licensing domainanddatasetIdcome fromsocrata_find_datasets;datasetIdmust match the four-by-four pattern (e.g.kzjm-xkqj)- Fails validation on a malformed ID, and not-found when the dataset doesn't exist on the domain (naming the portal that holds the ID when the Discovery catalog knows it)
socrata://portals resource
- Curated catalog of 39 known Socrata portals, cursor-paginated (
cursorparam, default 50 per page, capped at 200) - Returns domain, organization name, and approximate dataset count (
0= no dataset assets,null= temporarily unavailable), cached ~24 hours - Pass
domaintosocrata_find_datasetsto scope a search to one portal
explore_open_data prompt
- Arguments:
topicrequired;portalandgeographyoptional to skip discovery or scope WHERE clauses - Returns one user message walking a six-step workflow: find portal → discover datasets → inspect schema → query → aggregate → synthesize
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
Socrata-specific:
- Full Socrata SODA 2.1 API integration — SoQL query builder with select, where, group, having, order, search, limit, offset
- Discovery API for cross-portal dataset search and per-portal dataset counts (curated 39-portal catalog, counts cached ~24h)
- App token support (
SOCRATA_APP_TOKEN) for higher per-IP rate limits - Configurable default portal domain via
SOCRATA_DEFAULT_DOMAIN - DataCanvas spillover (DuckDB, bundled) — large query results register as SQL tables for analytical queries
Agent-friendly output:
- Assembled SoQL string echoed in every
socrata_query_datasetresponse so agents can learn and refine syntax - Recovery hints on empty results — echoes applied filters with specific suggestions for broadening
- Truncation disclosure —
truncated/shown/capfields when rows fill the limit, with guidance to page or raise the limit, naming the staged table and both dataframe tools when the result spilled - Typed error reasons across every tool (
invalid_id,not_found,not_tabular,query_rejected,unknown_domain,invalid_domain,soql_error,rate_limited,canvas_id_required,canvas_not_found,table_not_found,sql_rejected,canvas_disabled) with actionable recovery text
Getting started
Add the following to your MCP client configuration file.
Public Hosted Instance
A public instance is available at https://socrata.caseyjhand.com/mcp — no installation required. It serves Streamable HTTP; each client takes its own config shape.
For Claude Code:
claude mcp add --transport http socrata-mcp-server https://socrata.caseyjhand.com/mcp
For Cline (cline_mcp_settings.json):
{
"mcpServers": {
"socrata-mcp-server": {
"type": "streamableHttp",
"url": "https://socrata.caseyjhand.com/mcp"
}
}
}
For Cursor (mcp.json):
{
"mcpServers": {
"socrata-mcp-server": {
"url": "https://socrata.caseyjhand.com/mcp"
}
}
}
Claude Desktop adds remote servers under Settings → Connectors.
Self-Hosted / Local
{
"mcpServers": {
"socrata-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/socrata-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"socrata-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/socrata-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"socrata-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"ghcr.io/cyanheads/socrata-mcp-server:latest"
]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+).
- Optional: A Socrata app token — register for free at any portal (e.g. data.seattle.gov) to get higher rate limits (10 req/s per token vs. shared throttled pool without one).
Installation
- Clone the repository:
git clone https://github.com/cyanheads/socrata-mcp-server.git
- Navigate into the directory:
cd socrata-mcp-server
- Install dependencies:
bun install
- Configure environment:
cp .env.example .env
# edit .env and set SOCRATA_APP_TOKEN if you have one
Configuration
All configuration is validated at startup via Zod schemas in src/config/server-config.ts. Key environment variables:
| Variable | Description | Default |
|---|---|---|
SOCRATA_APP_TOKEN | Socrata app token (X-App-Token header). Without a token, requests share a throttled pool per source IP. | — |
SOCRATA_DEFAULT_DOMAIN | Default portal domain when domain is omitted from tool calls. | data.seattle.gov |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | Port for HTTP server. | 3010 |
MCP_SESSION_MODE | Session handling: stateful, stateless, or auto (schema default auto resolves to stateful). This server sets it explicitly to stateless. | stateless |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (RFC 5424): debug, info, notice, warning, error. | info |
CANVAS_PROVIDER_TYPE | DataCanvas spillover for large result sets; none disables it. DuckDB ships with the server — no additional install required. | duckdb |
SOCRATA_DATAFRAME_DROP_ENABLED | Set to true to enable socrata_dataframe_drop. Off, the tool is omitted from the tool list. | false |
LOGS_DIR | Directory for log files (Node.js only). | <project-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1. | in-memory |
OTEL_ENABLED | Enable OpenTelemetry instrumentation. | false |
LOG_TOOL_FAILURE_PAYLOADS | Log each failed tool call's arguments and result (key-name redaction only). | false |
See .env.example for the full list of optional overrides.
Running the server
Local development
- Build and run:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:http - Run checks and tests:
bun run devcheck # Lint, format, typecheck, security audit bun run test # Vitest test suite
Docker
docker build -t socrata-mcp-server .
docker run --rm -e MCP_TRANSPORT_TYPE=http -p 3010:3010 socrata-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/socrata-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools, resources, prompts, and inits the Socrata service. |
src/config | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools | Tool definitions (*.tool.ts). Seven tools covering portal listing, dataset search, schema fetch, SoQL query, and DataCanvas SQL and cleanup. |
src/mcp-server/resources | Resource definitions (*.resource.ts). Dataset metadata and portal catalog resources. |
src/mcp-server/prompts | Prompt definitions (*.prompt.ts). Civic data investigation workflow prompt. |
src/services/socrata | Socrata service layer — SODA 2.1 API client, Discovery API, query builder, type normalization. |
tests/ | Unit and integration tests mirroring src/. |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storage - Call
socrata_get_datasetbefore writing WHERE clauses —field_nameis what SoQL references and columndata_typedetermines quoting - Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
License
Apache-2.0 — see LICENSE for details.
الأسئلة الشائعة
ما هو io.github.cyanheads/socrata-mcp-server؟
Search and query government open-data portals (Socrata SODA API).
كيف أثبّت io.github.cyanheads/socrata-mcp-server؟
يعمل كخادم بعيد. في Claude Code: claude mcp add --transport http socrata-mcp-server 'https://socrata.caseyjhand.com/mcp'. وفي العملاء الآخرين، الصق إعداد JSON من هذه الصفحة في إعدادات MCP الخاصة بهم.
هل يحتاج io.github.cyanheads/socrata-mcp-server إلى مفتاح API؟
لا يذكر إدراجه في السجل أي مفتاح أو سر إلزامي. قد تتطلب بعض الميزات حسابًا لدى الخدمة التي يتصل بها.
هل io.github.cyanheads/socrata-mcp-server مفتوح المصدر؟
نعم. شيفرته متاحة على GitHub بترخيص Apache-2.0.
من يصون io.github.cyanheads/socrata-mcp-server؟
ينشره cyanheads. يدرجه AI.tn لكنه لا يصونه ولا يوصي به.
من سجل MCP الرسمي. الإدراج ليس توصية: راجع شيفرة الخادم وصلاحياته قبل منحه الوصول إلى بياناتك.