Skip to main content
Glama

socrata-mcp-server

Query Dataset

socrata_query_dataset
Read-onlyIdempotent

Execute a SoQL query against any dataset on any Socrata portal. Use the search parameter for quick full-text lookup, or combine select/where/group/having/order for full analytical control. Returns rows plus the assembled SoQL string so you can learn the pattern. Columns are referenced by API field name (field_name from socrata_get_dataset, e.g. cuisine_description), never the display label. All SODA 2.1 row values are strings even for numeric columns — check data_type from socrata_get_dataset to determine correct WHERE quoting: Number columns use bare literals (year=2023), Text columns use single-quoted strings (year='2023'). To enumerate distinct values, use select="col, count(*) as n" with group="col" and order="n DESC". When CANVAS_PROVIDER_TYPE=duckdb and rows fill limit, up to 50,000 matching rows spill to a DataCanvas table whatever the limit: list its columns with socrata_dataframe_describe, then run SQL with socrata_dataframe_query.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
groupNoSoQL GROUP BY clause over API field names (field_name from socrata_get_dataset). Requires an aggregate function in select.
limitNoMax rows to return (1–5000). Default 100. Use with offset for pagination. When the canvas is enabled and the page fills limit, up to 50,000 matching rows are staged on it whatever the limit — pass a small limit (e.g. 10) to stage a large match without a large inline page.
orderNoSoQL ORDER BY clause over API field names or select aliases, e.g. "total_deaths DESC" or "date ASC".
whereNoSoQL WHERE clause over API field names (field_name from socrata_get_dataset). Check column data_type there first — Number columns: year=2023, Text columns: year='2023'; an unquoted text value is read as a column name. Operators: =, !=, >, <, LIKE, IN(...), BETWEEN, IS NULL, starts_with(), contains(), AND, OR, NOT.
domainNoPortal the dataset lives on, as a bare hostname (e.g. data.cityofnewyork.us); URL forms like https://data.cityofnewyork.us/ are accepted and reduced to the host. Pass the domain from the same socrata_find_datasets result as dataset_id. Defaults to SOCRATA_DEFAULT_DOMAIN or data.seattle.gov, which is wrong for another portal’s ID.
havingNoSoQL HAVING clause. Filters on aggregated results, e.g. count > 100.
offsetNoRow offset for pagination. Default 0.
searchNoFull-text search across all text columns ($q). For field-specific filtering, use where instead.
selectNoSoQL SELECT clause — API field names (field_name from socrata_get_dataset, not display labels), aliases, aggregates: "state, sum(deaths) as total_deaths". Omit for all columns.
canvas_idNoOptional 10-char DataCanvas token from a prior socrata_query_dataset or socrata_dataframe_describe call. Omit on first call when CANVAS_PROVIDER_TYPE=duckdb to mint a fresh canvas. Large result sets spill here automatically.
dataset_idYesFour-by-four dataset ID (e.g. kzjm-xkqj). IDs are portal-scoped: take it from socrata_find_datasets together with that result’s domain.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
capNoThe row limit that was applied when capped.
rowsNoResult rows. Scalar values are strings (SODA 2.1); geo/location columns return nested objects. Use column schema from socrata_get_dataset for type context.
errorNoPresent when the call failed. Absent on success.
shownNoRows returned in this response when capped.
domainNoPortal hostname queried, normalized from the domain input.
noticeNoGuidance when the query returned zero rows (review the SoQL or broaden the filter), or when rows filled the limit (how to page, and the staged table to query when the result spilled). Absent otherwise.
canvas_idNoDataCanvas token when results spilled (requires CANVAS_PROVIDER_TYPE=duckdb). Pass to socrata_dataframe_query to run SQL over the staged rows in table_name — a bounded copy of the matching set (up to 50,000 rows, reported in canvas_row_count), not the full set when total_count exceeds that cap. Page with offset to reach rows beyond it.
row_countNoRows returned in this response.
truncatedNoTrue when rows filled the limit — more rows may match (see total_count when present). Spills to canvas when enabled; table_name names the staged table.
dataset_idNoDataset ID queried.
table_nameNoCanvas table holding the staged rows; present when canvas_id is. Use it as the FROM target in socrata_dataframe_query SQL; list its columns with socrata_dataframe_describe.
total_countNoTotal matching source rows when a plain row query is truncated (row_count < total_count). Absent when the full result fits and for grouped/aggregate queries (group set), where a source-row count would not describe the returned groups.
assembled_queryNoSoQL clauses assembled for this request — useful for learning the syntax.
canvas_row_countNoRows staged onto the DataCanvas — a bounded copy of the matching result set (capped at 50,000). Fewer than total_count when the match exceeds the cap. Present only when canvas_id is.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed5 schema fields changed
    • changedInput schema / properties / limit / description
      Previous value: -"Max rows to return (1–5000). Default 100. Use with offset for pagination."New value: +"Max rows to return (1–5000). Default 100. Use with offset for pagination. When the canvas is enabled and the page fills limit, up to 50,000 matching rows are staged on it whatever the limit — pass a small limit (e.g. 10) to stage a large match without a large inline page."
    • changedOutput schema / properties / canvas_id / description
      Previous value: -"DataCanvas token when results spilled (requires CANVAS_PROVIDER_TYPE=duckdb). Pass to socrata_dataframe_query to run SQL over the staged rows — a bounded copy of the matching set (up to 50,000 rows, reported in canvas_row_count), not the full set when total_count exceeds that cap. Page with offset to reach rows beyond it."New value: +"DataCanvas token when results spilled (requires CANVAS_PROVIDER_TYPE=duckdb). Pass to socrata_dataframe_query to run SQL over the staged rows in table_name — a bounded copy of the matching set (up to 50,000 rows, reported in canvas_row_count), not the full set when total_count exceeds that cap. Page with offset to reach rows beyond it."
    • changedOutput schema / properties / notice / description
      Previous value: -"Guidance when the query returned zero rows — suggests narrowing or reviewing the SoQL. Absent on non-empty result sets."New value: +"Guidance when the query returned zero rows (review the SoQL or broaden the filter), or when rows filled the limit (how to page, and the staged table to query when the result spilled). Absent otherwise."
    • addedOutput schema / properties / table_name
      Added value: +{
      +  "description": "Canvas table holding the staged rows; present when canvas_id is. Use it as the FROM target in socrata_dataframe_query SQL; list its columns with socrata_dataframe_describe.",
      +  "type": "string"
      +}
    • changedOutput schema / properties / truncated / description
      Previous value: -"True when rows filled the limit — more rows may match (see total_count when present). Spills to canvas when enabled."New value: +"True when rows filled the limit — more rows may match (see total_count when present). Spills to canvas when enabled; table_name names the staged table."
  2. Changed9 schema fields changed
    • changedInput schema / properties / dataset_id / description
      Previous value: -"Four-by-four dataset ID (e.g. kzjm-xkqj). Obtain from socrata_find_datasets."New value: +"Four-by-four dataset ID (e.g. kzjm-xkqj). IDs are portal-scoped: take it from socrata_find_datasets together with that result’s domain."
    • changedInput schema / properties / domain / description
      Previous value: -"Portal domain (e.g. data.seattle.gov). Defaults to SOCRATA_DEFAULT_DOMAIN or data.seattle.gov."New value: +"Portal the dataset lives on, as a bare hostname (e.g. data.cityofnewyork.us); URL forms like https://data.cityofnewyork.us/ are accepted and reduced to the host. Pass the domain from the same socrata_find_datasets result as dataset_id. Defaults to SOCRATA_DEFAULT_DOMAIN or data.seattle.gov, which is wrong for another portal’s ID."
    • changedInput schema / properties / group / description
      Previous value: -"SoQL GROUP BY clause. Requires an aggregate function in select."New value: +"SoQL GROUP BY clause over API field names (field_name from socrata_get_dataset). Requires an aggregate function in select."
    • changedInput schema / properties / order / description
      Previous value: -"SoQL ORDER BY clause, e.g. \"total_deaths DESC\" or \"date ASC\"."New value: +"SoQL ORDER BY clause over API field names or select aliases, e.g. \"total_deaths DESC\" or \"date ASC\"."
    • changedInput schema / properties / select / description
      Previous value: -"SoQL SELECT clause — column names, aliases, aggregates: \"state, sum(deaths) as total_deaths\". Omit for all columns."New value: +"SoQL SELECT clause — API field names (field_name from socrata_get_dataset, not display labels), aliases, aggregates: \"state, sum(deaths) as total_deaths\". Omit for all columns."
    • changedInput schema / properties / where / description
      Previous value: -"SoQL WHERE clause. Check column dataType from socrata_get_dataset first — Number columns: year=2023, Text columns: year='2023'. Operators: =, !=, >, <, LIKE, IN(...), BETWEEN, IS NULL, starts_with(), contains(), AND, OR, NOT."New value: +"SoQL WHERE clause over API field names (field_name from socrata_get_dataset). Check column data_type there first — Number columns: year=2023, Text columns: year='2023'; an unquoted text value is read as a column name. Operators: =, !=, >, <, LIKE, IN(...), BETWEEN, IS NULL, starts_with(), contains(), AND, OR, NOT."
    • changedOutput schema / properties / domain / description
      Previous value: -"Portal domain queried."New value: +"Portal hostname queried, normalized from the domain input."
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `invalid_id`: Dataset ID does not match the four-by-four pattern. `not_found`: Dataset does not exist on this domain. `soql_error`: SoQL syntax error or unknown column name. `rate_limited`: SODA endpoint returned 429. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `invalid_id`: Dataset ID does not match the four-by-four pattern. `not_found`: The dataset does not exist on the domain queried — including a gateway HTTP 403 for an ID the portal does not serve. `unknown_domain`: The domain does not serve the Socrata API to this server: its hostname does not resolve (DNS ENOTFOUND), its API answered HTTP 404 without a Socrata error body, it redirected the request to another host that did not answer with Socrata data, or a gateway refused a dataset the Discovery catalog lists there. `invalid_domain`: The domain is not a hostname, even after dropping a URL scheme, path, or query. `soql_error`: SoQL syntax error, unknown column, or literal/column type mismatch. data.socrataCode carries the upstream code and data.column the offending token when upstream names one. `rate_limited`: SODA endpoint returned 429. Other values are possible when a failure originates below the handler."
    • changedOutput schema / properties / error / properties / data / properties / reason / examples
      Previous value: -[
      -  "invalid_id",
      -  "not_found",
      -  "soql_error",
      -  "rate_limited"
      -]New value: +[
      +  "invalid_id",
      +  "not_found",
      +  "unknown_domain",
      +  "invalid_domain",
      +  "soql_error",
      +  "rate_limited"
      +]
  3. Changed2 schema fields changed
    • changedInput schema / properties / canvas_id / description
      Previous value: -"Optional 10-char DataCanvas token from a prior call. Omit on first call when CANVAS_PROVIDER_TYPE=duckdb to mint a fresh canvas. Large result sets spill here automatically."New value: +"Optional 10-char DataCanvas token from a prior socrata_query_dataset or socrata_dataframe_describe call. Omit on first call when CANVAS_PROVIDER_TYPE=duckdb to mint a fresh canvas. Large result sets spill here automatically."
    • addedInput schema / properties / canvas_id / pattern
      Added value: +"^[A-Za-z0-9_-]{10}$"
  4. Changed6 schema fields changed
    • changedInput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedInput schema / additionalProperties
      Added value: +false
    • changedOutput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedOutput schema / anyOf
      Added value: +[
      +  {
      +    "not": {
      +      "required": [
      +        "error"
      +      ]
      +    },
      +    "required": [
      +      "rows",
      +      "row_count",
      +      "assembled_query",
      +      "domain",
      +      "dataset_id"
      +    ]
      +  },
      +  {
      +    "required": [
      +      "error"
      +    ]
      +  }
      +]
    • addedOutput schema / properties / error
      Added value: +{
      +  "additionalProperties": {},
      +  "description": "Present when the call failed. Absent on success.",
      +  "properties": {
      +    "code": {
      +      "description": "JSON-RPC error code for this failure.",
      +      "maximum": 9007199254740991,
      +      "minimum": -9007199254740991,
      +      "type": "integer"
      +    },
      +    "data": {
      +      "additionalProperties": {},
      +      "properties": {
      +        "reason": {
      +          "description": "Machine-readable failure mode. Declared by this tool: `invalid_id`: Dataset ID does not match the four-by-four pattern. `not_found`: Dataset does not exist on this domain. `soql_error`: SoQL syntax error or unknown column name. `rate_limited`: SODA endpoint returned 429. Other values are possible when a failure originates below the handler.",
      +          "examples": [
      +            "invalid_id",
      +            "not_found",
      +            "soql_error",
      +            "rate_limited"
      +          ],
      +          "type": "string"
      +        },
      +        "recovery": {
      +          "additionalProperties": {},
      +          "description": "Actionable next step for the caller.",
      +          "properties": {
      +            "hint": {
      +              "type": "string"
      +            }
      +          },
      +          "required": [
      +            "hint"
      +          ],
      +          "type": "object"
      +        },
      +        "retryable": {
      +          "description": "Whether retrying may succeed.",
      +          "type": "boolean"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "message": {
      +      "description": "Human-readable description of what went wrong.",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "code",
      +    "message"
      +  ],
      +  "type": "object"
      +}
    • removedOutput schema / required
      Removed value: -[
      -  "rows",
      -  "row_count",
      -  "assembled_query",
      -  "domain",
      -  "dataset_id"
      -]
  5. Changed2 schema fields changed
    • changedOutput schema / properties / canvas_id / description
      Previous value: -"DataCanvas token when results spilled (requires CANVAS_PROVIDER_TYPE=duckdb). Pass to socrata_dataframe_query for SQL over the full result set."New value: +"DataCanvas token when results spilled (requires CANVAS_PROVIDER_TYPE=duckdb). Pass to socrata_dataframe_query to run SQL over the staged rows — a bounded copy of the matching set (up to 50,000 rows, reported in canvas_row_count), not the full set when total_count exceeds that cap. Page with offset to reach rows beyond it."
    • addedOutput schema / properties / canvas_row_count
      Added value: +{
      +  "description": "Rows staged onto the DataCanvas — a bounded copy of the matching result set (capped at 50,000). Fewer than total_count when the match exceeds the cap. Present only when canvas_id is.",
      +  "type": "number"
      +}
  6. Changed2 schema fields changed
    • changedOutput schema / properties / total_count / description
      Previous value: -"Total matching rows when result is truncated (row_count < total_count). Absent when the full result fits."New value: +"Total matching source rows when a plain row query is truncated (row_count < total_count). Absent when the full result fits and for grouped/aggregate queries (group set), where a source-row count would not describe the returned groups."
    • changedOutput schema / properties / truncated / description
      Previous value: -"True when rows filled the limit — more rows match (see total_count). Spills to canvas when enabled."New value: +"True when rows filled the limit — more rows may match (see total_count when present). Spills to canvas when enabled."
  7. Changed3 schema fields changed
    • addedOutput schema / properties / cap
      Added value: +{
      +  "description": "The row limit that was applied when capped.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / shown
      Added value: +{
      +  "description": "Rows returned in this response when capped.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / truncated
      Added value: +{
      +  "description": "True when rows filled the limit — more rows match (see total_count). Spills to canvas when enabled.",
      +  "type": "boolean"
      +}
  8. Changed1 schema field changed
    • addedOutput schema / properties / notice
      Added value: +{
      +  "description": "Guidance when the query returned zero rows — suggests narrowing or reviewing the SoQL. Absent on non-empty result sets.",
      +  "type": "string"
      +}
  9. First observed

TDQS

A4.8/5.0
Behavior5/5

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

Beyond the readOnly and idempotent annotations, the description discloses notable behaviors: rows are returned along with the assembled SoQL string, API field names are required rather than display labels, all SODA 2.1 row values are strings even for numeric columns, and large result sets spill to DataCanvas under certain conditions. This gives the agent important operational knowledge annotations alone do not provide.

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?

The description is long but every sentence carries operational value and the main purpose is front-loaded. The details about field naming, string coercion, distinct-value enumeration, and spill behavior are dense but not redundant, and no filler is present.

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 an 11-parameter tool with an output schema and readOnly annotations, the description covers the critical ambiguities: domain scoping, API field name usage, quoting by data type, pagination, and post-spill analysis. The presence of an output schema means return-value details do not need to be repeated, and the description is complete enough for an agent to invoke the tool correctly.

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

Parameters5/5

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

Although schema coverage is 100%, the description adds substantial meaning beyond the schema: it explains the distinction between search and where, provides concrete quoting rules based on data_type, gives select alias examples, specifies a distinct-value pattern, and clarifies how limit interacts with DataCanvas spill behavior.

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 opens with a specific verb and resource: 'Execute a SoQL query against any dataset on any Socrata portal.' It also distinguishes the querying role by contrasting quick full-text search with structured select/where/group/having/order control, making it clearly distinct from sibling tools like socrata_get_dataset and socrata_dataframe_query.

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?

The description gives explicit usage guidance: use search for quick lookup, use structured clauses for analytical control, use where for field-specific filtering, and use a specific pattern for distinct values. It also directs spill-over analysis to socrata_dataframe_describe and socrata_dataframe_query. However, it does not explicitly state when this tool should not be used in favor of metadata-oriented siblings.

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

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.