Skip to main content
Glama

Search People

openstates_search_people
Read-onlyIdempotent

Search state legislators and officials by name, jurisdiction, chamber, or district, or fetch specific people by OCD person ID. Party is reported on every result but cannot be filtered on — narrow by party after the call. Either jurisdiction or id is required — a search spanning all 56 jurisdictions exceeds the upstream timeout, including a name-only one, so scope every call to a single state or to specific person IDs. Use openstates_list_jurisdictions to pick a jurisdiction, or openstates_get_legislators_by_location when you have coordinates but no state. id takes the person IDs that openstates_get_bill sponsorships and openstates_get_committee memberships hand back, and resolves any number of them in one call. Supports name substring matching (case-insensitive). org_classification targets a role type: "upper" for Senate, "lower" for House/Assembly, "executive" for governors and executive officials, and "legislature" for every legislator — both chambers merged into one paginated set (all upper members, then all lower), or the single body in Nebraska and the DC Council, which excludes executive-branch officials. Omitting org_classification is not the same as "legislature": it returns every officeholder, executive officials included. include=offices adds phone, fax, and address. include=links adds website and social links.

Input Schema

NameRequiredDescriptionDefault
idNoOCD person IDs (e.g., "ocd-person/9eddb3cd-868e-42ba-831a-b415fd7ed445"). Required unless jurisdiction is provided — it returns exactly these people, so it scopes the call on its own and needs no jurisdiction alongside it. Resolves the IDs that openstates_search_people results, openstates_get_bill sponsorships[].person.id, and openstates_get_committee memberships[].person_id hand back — any number of them in one call, subject to per_page. An ID Open States does not know matches nothing rather than failing, as does an ID paired with a jurisdiction that person does not belong to.
nameNoName or partial name to match (case-insensitive substring). Narrows within the jurisdiction; it does not substitute for one.
pageNoPage number (1-indexed).
includeNoRelated data to inline. "offices" includes phone, fax, and address. "links" includes website and social links. "other_names" includes alternate/former names, "other_identifiers" cross-system IDs, and "sources" the provenance URLs behind the record.
districtNoDistrict label (e.g., "1", "37", "At-Large"). Formats vary by state.
per_pageNoResults per page. Maximum 20.
jurisdictionNoState name, abbreviation, or OCD-ID. Required unless id is provided — an all-states search exceeds the upstream timeout, so every call must be scoped to a single jurisdiction or to specific person IDs.
org_classificationNoFilter by role type. "upper" = Senate, "lower" = House/Assembly, "executive" = governors and executive officials, "legislature" = every legislator (both chambers merged into one paginated set, all upper members then all lower; the single body in Nebraska and the DC Council; excluding executive officials). Unicameral bodies have no "upper" or "lower" members. Omitting this filter returns every officeholder including executive ones — it is not equivalent to "legislature".

Output Schema

NameRequiredDescriptionDefault
pageNoCurrent page returned.
errorNoPresent when the call failed. Absent on success.
noticeNoRecovery hint when results are empty. Absent when results are returned.
maxPageNoTotal pages available.
resultsNoLegislators matching the search criteria.
paginationNoPagination metadata.
totalCountNoTotal legislators matching the query across all pages.
appliedFiltersNoFilters applied to this query as the server received them, for agent self-verification of zero or unexpected results.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed3 schema fields changed
    • changedInput schema / properties / org_classification / description
      Previous value: -"Filter by role type. \"upper\" = Senate, \"lower\" = House/Assembly, \"executive\" = governors and executive officials, \"legislature\" = every legislator (both chambers merged into one paginated set, all upper members then all lower, excluding executive officials). Omitting this filter returns every officeholder including executive ones — it is not equivalent to \"legislature\"."New value: +"Filter by role type. \"upper\" = Senate, \"lower\" = House/Assembly, \"executive\" = governors and executive officials, \"legislature\" = every legislator (both chambers merged into one paginated set, all upper members then all lower; the single body in Nebraska and the DC Council; excluding executive officials). Unicameral bodies have no \"upper\" or \"lower\" members. Omitting this filter returns every officeholder including executive ones — it is not equivalent to \"legislature\"."
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `upstream_timeout`: Open States did not answer within the per-request timeout — the query is too broad. `invalid_page`: Open States rejected the request as not found — page is past the last page for this query. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `upstream_timeout`: Open States did not answer within the per-request timeout — the query is too broad. `invalid_page`: Open States rejected the request as not found — page is past the last page for this query. `rate_limited`: The shared Open States API key reached a request cap — Open States' per-minute or daily limit, or this server's own daily budget. Other values are possible when a failure originates below the handler."
    • changedOutput schema / properties / error / properties / data / properties / reason / examples
      Previous value: -[
      -  "upstream_timeout",
      -  "invalid_page"
      -]New value: +[
      +  "upstream_timeout",
      +  "invalid_page",
      +  "rate_limited"
      +]
  2. Changed1 schema field changed
    • changedOutput schema / properties / results / items / properties / current_role / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "district": {
      -        "anyOf": [
      -          {
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "District label or null when undistricted."
      -      },
      -      "division_id": {
      -        "anyOf": [
      -          {
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "OCD division the district maps to (e.g., \"ocd-division/country:us/state:wa/sldu:37\"). Null when undistricted, absent when upstream omits it."
      -      },
      -      "org_classification": {
      -        "description": "Chamber classification (e.g., \"upper\", \"lower\").",
      -        "type": "string"
      -      },
      -      "title": {
      -        "description": "Role title (e.g., \"Senator\", \"Representative\").",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "title",
      -      "org_classification",
      -      "district"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "district": {
      +        "description": "District label or null when undistricted.",
      +        "type": [
      +          "string",
      +          "null"
      +        ]
      +      },
      +      "division_id": {
      +        "description": "OCD division the district maps to (e.g., \"ocd-division/country:us/state:wa/sldu:37\"). Null when undistricted, absent when upstream omits it.",
      +        "type": [
      +          "string",
      +          "null"
      +        ]
      +      },
      +      "org_classification": {
      +        "description": "Chamber classification (e.g., \"upper\", \"lower\").",
      +        "type": "string"
      +      },
      +      "title": {
      +        "description": "Role title (e.g., \"Senator\", \"Representative\").",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "title",
      +      "org_classification",
      +      "district"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
  3. 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": [
      +      "results",
      +      "pagination",
      +      "totalCount",
      +      "page",
      +      "maxPage",
      +      "appliedFilters"
      +    ]
      +  },
      +  {
      +    "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: `upstream_timeout`: Open States did not answer within the per-request timeout — the query is too broad. `invalid_page`: Open States rejected the request as not found — page is past the last page for this query. Other values are possible when a failure originates below the handler.",
      +          "examples": [
      +            "upstream_timeout",
      +            "invalid_page"
      +          ],
      +          "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: -[
      -  "results",
      -  "pagination",
      -  "totalCount",
      -  "page",
      -  "maxPage",
      -  "appliedFilters"
      -]
  4. Changed10 schema fields changed
    • addedInput schema / properties / id
      Added value: +{
      +  "description": "OCD person IDs (e.g., \"ocd-person/9eddb3cd-868e-42ba-831a-b415fd7ed445\"). Required unless jurisdiction is provided — it returns exactly these people, so it scopes the call on its own and needs no jurisdiction alongside it. Resolves the IDs that openstates_search_people results, openstates_get_bill sponsorships[].person.id, and openstates_get_committee memberships[].person_id hand back — any number of them in one call, subject to per_page. An ID Open States does not know matches nothing rather than failing, as does an ID paired with a jurisdiction that person does not belong to.",
      +  "items": {
      +    "minLength": 1,
      +    "type": "string"
      +  },
      +  "minItems": 1,
      +  "type": "array"
      +}
    • changedInput schema / properties / jurisdiction / description
      Previous value: -"State name, abbreviation, or OCD-ID. Required — an all-states search exceeds the upstream timeout, so every call must be scoped to a single jurisdiction."New value: +"State name, abbreviation, or OCD-ID. Required unless id is provided — an all-states search exceeds the upstream timeout, so every call must be scoped to a single jurisdiction or to specific person IDs."
    • removedInput schema / required
      Removed value: -[
      -  "jurisdiction"
      -]
    • addedOutput schema / properties / appliedFilters / properties / id
      Added value: +{
      +  "description": "Person IDs filtered on, as received. Absent when none were supplied.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • changedOutput schema / properties / results / items / properties / family_name / description
      Previous value: -"Family (last) name."New value: +"Family (last) name. Empty string when Open States recorded none."
    • changedOutput schema / properties / results / items / properties / given_name / description
      Previous value: -"Given (first) name."New value: +"Given (first) name. Empty string when Open States recorded none."
    • changedOutput schema / properties / results / items / properties / links / items / properties / note / description
      Previous value: -"Link description (e.g., \"website\", \"twitter\")."New value: +"Link description (e.g., \"website\", \"twitter\"). Empty string when Open States recorded no description — common on person links."
    • changedOutput schema / properties / results / items / properties / openstates_url / description
      Previous value: -"Open States profile URL."New value: +"Open States profile URL. Empty string when Open States recorded none."
    • changedOutput schema / properties / results / items / properties / other_names / items / properties / note / description
      Previous value: -"Note describing the alternate name."New value: +"Note describing the alternate name. Empty string when Open States recorded no note."
    • changedOutput schema / properties / results / items / properties / sources / items / properties / note / description
      Previous value: -"Source note."New value: +"Source note. Empty string when Open States recorded no note."
  5. Changed3 schema fields changed
    • changedInput schema / properties / jurisdiction / description
      Previous value: -"State name, abbreviation, or OCD-ID. Required — an all-states search exceeds the upstream timeout, so omitting it is rejected before any request is issued."New value: +"State name, abbreviation, or OCD-ID. Required — an all-states search exceeds the upstream timeout, so every call must be scoped to a single jurisdiction."
    • addedInput schema / properties / jurisdiction / minLength
      Added value: +1
    • addedInput schema / required
      Added value: +[
      +  "jurisdiction"
      +]
  6. Changed4 schema fields changed
    • changedInput schema / properties / jurisdiction / description
      Previous value: -"State name, abbreviation, or OCD-ID. Omitting searches across all states."New value: +"State name, abbreviation, or OCD-ID. Required — an all-states search exceeds the upstream timeout, so omitting it is rejected before any request is issued."
    • changedInput schema / properties / name / description
      Previous value: -"Name or partial name to match (case-insensitive substring)."New value: +"Name or partial name to match (case-insensitive substring). Narrows within the jurisdiction; it does not substitute for one."
    • changedOutput schema / properties / results / items / properties / current_role / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "district": {
      -        "anyOf": [
      -          {
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "District label or null when undistricted."
      -      },
      -      "org_classification": {
      -        "description": "Chamber classification (e.g., \"upper\", \"lower\").",
      -        "type": "string"
      -      },
      -      "title": {
      -        "description": "Role title (e.g., \"Senator\", \"Representative\").",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "title",
      -      "org_classification",
      -      "district"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "district": {
      +        "anyOf": [
      +          {
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "District label or null when undistricted."
      +      },
      +      "division_id": {
      +        "anyOf": [
      +          {
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "OCD division the district maps to (e.g., \"ocd-division/country:us/state:wa/sldu:37\"). Null when undistricted, absent when upstream omits it."
      +      },
      +      "org_classification": {
      +        "description": "Chamber classification (e.g., \"upper\", \"lower\").",
      +        "type": "string"
      +      },
      +      "title": {
      +        "description": "Role title (e.g., \"Senator\", \"Representative\").",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "title",
      +      "org_classification",
      +      "district"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • addedOutput schema / properties / results / items / properties / image
      Added value: +{
      +  "description": "Official headshot URL. Absent when no photo is published.",
      +  "type": "string"
      +}
  7. Changed4 schema fields changed
    • changedInput schema / properties / include / description
      Previous value: -"Related data to inline. \"offices\" includes phone, fax, and address. \"links\" includes website and social links."New value: +"Related data to inline. \"offices\" includes phone, fax, and address. \"links\" includes website and social links. \"other_names\" includes alternate/former names, \"other_identifiers\" cross-system IDs, and \"sources\" the provenance URLs behind the record."
    • addedOutput schema / properties / results / items / properties / other_identifiers
      Added value: +{
      +  "description": "Cross-system identifiers when include=other_identifiers is requested.",
      +  "items": {
      +    "additionalProperties": false,
      +    "description": "Alternate identifier record.",
      +    "properties": {
      +      "identifier": {
      +        "description": "Alternate identifier.",
      +        "type": "string"
      +      },
      +      "scheme": {
      +        "description": "Identifier scheme (the issuing system).",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "identifier",
      +      "scheme"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / results / items / properties / other_names
      Added value: +{
      +  "description": "Alternate/former names when include=other_names is requested.",
      +  "items": {
      +    "additionalProperties": false,
      +    "description": "Alternate name record.",
      +    "properties": {
      +      "name": {
      +        "description": "Alternate or former name.",
      +        "type": "string"
      +      },
      +      "note": {
      +        "description": "Note describing the alternate name.",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "name",
      +      "note"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / results / items / properties / sources
      Added value: +{
      +  "description": "Provenance sources when include=sources is requested.",
      +  "items": {
      +    "additionalProperties": false,
      +    "description": "Source record.",
      +    "properties": {
      +      "note": {
      +        "description": "Source note.",
      +        "type": "string"
      +      },
      +      "url": {
      +        "description": "Source URL.",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "url",
      +      "note"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
  8. Changed1 schema field changed
    • changedInput schema / properties / org_classification / description
      Previous value: -"Filter by role type. \"upper\" = Senate, \"lower\" = House/Assembly, \"legislature\" = all legislators, \"executive\" = governors and executive officials."New value: +"Filter by role type. \"upper\" = Senate, \"lower\" = House/Assembly, \"executive\" = governors and executive officials, \"legislature\" = every legislator (both chambers merged into one paginated set, all upper members then all lower, excluding executive officials). Omitting this filter returns every officeholder including executive ones — it is not equivalent to \"legislature\"."
  9. Changed2 schema fields changed
    • addedOutput schema / properties / appliedFilters
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "Filters applied to this query as the server received them, for agent self-verification of zero or unexpected results.",
      +  "properties": {
      +    "district": {
      +      "description": "District filter as received.",
      +      "type": "string"
      +    },
      +    "jurisdiction": {
      +      "description": "Jurisdiction filter as received.",
      +      "type": "string"
      +    },
      +    "name": {
      +      "description": "Name filter as received.",
      +      "type": "string"
      +    },
      +    "org_classification": {
      +      "description": "Role-type filter as received.",
      +      "type": "string"
      +    },
      +    "page": {
      +      "description": "Page number requested.",
      +      "type": "number"
      +    },
      +    "per_page": {
      +      "description": "Results per page requested.",
      +      "type": "number"
      +    }
      +  },
      +  "required": [
      +    "page",
      +    "per_page"
      +  ],
      +  "type": "object"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "results",
      -  "pagination",
      -  "totalCount",
      -  "page",
      -  "maxPage"
      -]New value: +[
      +  "results",
      +  "pagination",
      +  "totalCount",
      +  "page",
      +  "maxPage",
      +  "appliedFilters"
      +]
  10. Changed3 schema fields changed
    • addedOutput schema / properties / totalCount
      Added value: +{
      +  "description": "Total legislators matching the query across all pages.",
      +  "type": "number"
      +}
    • removedOutput schema / properties / totalItems
      Removed value: -{
      -  "description": "Total legislators matching the query across all pages.",
      -  "type": "number"
      -}
    • changedOutput schema / required
      Previous value: -[
      -  "results",
      -  "pagination",
      -  "totalItems",
      -  "page",
      -  "maxPage"
      -]New value: +[
      +  "results",
      +  "pagination",
      +  "totalCount",
      +  "page",
      +  "maxPage"
      +]
  11. Changed6 schema fields changed
    • addedOutput schema / properties / maxPage
      Added value: +{
      +  "description": "Total pages available.",
      +  "type": "number"
      +}
    • removedOutput schema / properties / message
      Removed value: -{
      -  "description": "Recovery hint when results are empty. Absent when results are returned.",
      -  "type": "string"
      -}
    • addedOutput schema / properties / notice
      Added value: +{
      +  "description": "Recovery hint when results are empty. Absent when results are returned.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / page
      Added value: +{
      +  "description": "Current page returned.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / totalItems
      Added value: +{
      +  "description": "Total legislators matching the query across all pages.",
      +  "type": "number"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "results",
      -  "pagination"
      -]New value: +[
      +  "results",
      +  "pagination",
      +  "totalItems",
      +  "page",
      +  "maxPage"
      +]
  12. First observed

TDQS

A4.5/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent/openWorld, so the bar is lower, yet the description adds real operational context: the upstream timeout on unscoped searches, that unknown IDs match nothing rather than erroring, that 'legislature' merges both chambers into one paginated set in a fixed order, and that include=offices/links inlines contact data. This is behavior an agent cannot infer from the annotations.

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

Conciseness3/5

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

Purpose and the jurisdiction/id requirement are front-loaded well, but the paragraph runs long and the entire org_classification explanation (upper/lower/executive/legislature, Nebraska, DC Council, omission semantics) duplicates the schema description word-for-word — space that buys nothing for the agent.

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 needs no explanation. For an 8-parameter, open-world search tool the description covers scoping constraints, failure modes, pagination caps, and sibling routing — nothing an agent needs to call it correctly is missing.

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%, so the schema already documents all eight parameters, and much of the description's parameter text (org_classification enum meanings, include values, name substring matching) restates the schema verbatim. The one genuinely additive piece is the cross-tool provenance of the id values, which the schema also covers. Baseline 3 is correct here.

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 (search state legislators and officials) plus the alternate retrieval mode (fetch by OCD person ID), and names the dimensions filterable (name, jurisdiction, chamber, district). An agent can distinguish it from openstates_get_legislators_by_location and the search_* 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 Guidelines5/5

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

Explicit routing: 'Use openstates_list_jurisdictions to pick a jurisdiction, or openstates_get_legislators_by_location when you have coordinates but no state.' It also states a hard when-not ('Party is reported on every result but cannot be filtered on — narrow by party after the call') and the mandatory scoping rule with the reason (all-56-jurisdiction search exceeds the upstream timeout).

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.