Skip to main content
Glama

nonprofit-explorer-mcp-server

Search Nonprofits

nonprofit_search
Read-only

Search 1.8M+ IRS-recognized tax-exempt organizations by name, keyword, city, or phrase. Optionally narrow by US state, NTEE major sector (1–10), or 501(c) subsection type. Returns EINs — pass them to nonprofit_get_organization or nonprofit_get_filings for details. Results are paginated at 25 per page; use the page parameter and num_pages to paginate. Total results cap at 10,000 in the API; if total_results === 10000 the actual count may be higher. A zero-match query and a page past the last one both return an empty organizations array with a notice rather than an error; only a page whose offset reaches that 10,000 cap is refused. Supports quoted phrases ("Red Cross"), required terms (+evanston), excluded terms (-dental). Data from ProPublica Nonprofit Explorer, sourced from IRS Form 990 filings.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pageNoZero-indexed page number. 25 results per page. Total pages is in num_pages. Increment to paginate large result sets.
queryYesKeyword search string. Searched against org name, the secondary name line, and city in order of relevance. Supports: quoted phrases ("Red Cross"), required terms (+evanston), excluded terms (-dental). Empty string returns all orgs within the active filters.
stateNoTwo-letter US state, territory, or military postal code (e.g., "WA", "NY", "PR"). Case-insensitive — normalized to uppercase before filtering. A code outside that set is rejected rather than silently returning national results. Restricts results to orgs headquartered in that state. "ZZ" (foreign address) is accepted, but no organization in the index currently carries it.
ntee_categoryNoNTEE (National Taxonomy of Exempt Entities) major group integer (1–10). 1=Arts/Culture/Humanities, 2=Education, 3=Environment/Animals, 4=Health, 5=Human Services, 6=International/Foreign Affairs, 7=Public/Societal Benefit, 8=Religion Related, 9=Mutual/Membership Benefit, 10=Unknown/Unclassified.
subsection_codeNo501(c) subsection code. "3" = charitable/religious/educational organization (most common — includes both public charities and private foundations; nonprofit_get_organization returns foundation_type to tell them apart), "4" = social welfare org, "6" = business league/trade association, "92" = 4947(a)(1) nonexempt charitable trust. Filters by tax status, not sector.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
errorNoPresent when the call failed. Absent on success.
noticeNoPresent when the response needs a caveat the domain fields cannot carry: a page that returned no organizations (distinguishing a zero-match query from a page past the end of the result set, and naming the next call), a total_results sitting on the API result ceiling rather than counting matches, or both at once in one string. Absent when the page is populated and the total is an exact count.
cur_pageNoCurrent page (zero-indexed).
per_pageNoResults per page applied by the API (25).
num_pagesNoTotal pages available (total_results / 25, ceiling). The last valid page is num_pages - 1.
data_sourceNoProPublica + IRS attribution text.
page_offsetNoZero-indexed offset of the first result on this page. Requests are refused once this reaches 10,000.
organizationsNoMatching organizations for the current page.
total_resultsNoTotal matching orgs (up to 10,000 — the API ceiling). If 10000, actual count may be higher.
active_filtersNoActive filters echoed back for verification.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed17 schema fields changed
    • removedOutput schema / properties / active_filters / properties / ntee_category / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / properties / active_filters / properties / ntee_category / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / properties / active_filters / properties / state / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / properties / active_filters / properties / state / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / properties / active_filters / properties / subsection_code / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / properties / active_filters / properties / subsection_code / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `invalid_state`: The state filter is not a US state, territory, or military postal code (or ZZ for foreign entities) `pagination_ceiling`: The requested page is at or beyond ProPublica's 10,000-result offset ceiling `upstream_error`: ProPublica API returns a 500 or network error Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `invalid_state`: The state filter is not a US state, territory, or military postal code (or ZZ for foreign entities). `pagination_ceiling`: The requested page is at or beyond ProPublica's 10,000-result offset ceiling. `upstream_error`: ProPublica API returns a 500 or network error. Other values are possible when a failure originates below the handler."
    • removedOutput schema / properties / organizations / items / properties / city / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / properties / organizations / items / properties / city / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / properties / organizations / items / properties / ntee_code / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / properties / organizations / items / properties / ntee_code / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / properties / organizations / items / properties / state / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / properties / organizations / items / properties / state / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / properties / organizations / items / properties / sub_name / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / properties / organizations / items / properties / sub_name / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / properties / organizations / items / properties / subseccd / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / properties / organizations / items / properties / subseccd / type
      Added value: +[
      +  "number",
      +  "null"
      +]
  2. 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": [
      +      "total_results",
      +      "num_pages",
      +      "cur_page",
      +      "per_page",
      +      "page_offset",
      +      "organizations",
      +      "active_filters",
      +      "data_source"
      +    ]
      +  },
      +  {
      +    "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_state`: The state filter is not a US state, territory, or military postal code (or ZZ for foreign entities) `pagination_ceiling`: The requested page is at or beyond ProPublica's 10,000-result offset ceiling `upstream_error`: ProPublica API returns a 500 or network error Other values are possible when a failure originates below the handler.",
      +          "examples": [
      +            "invalid_state",
      +            "pagination_ceiling",
      +            "upstream_error"
      +          ],
      +          "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: -[
      -  "total_results",
      -  "num_pages",
      -  "cur_page",
      -  "per_page",
      -  "page_offset",
      -  "organizations",
      -  "active_filters",
      -  "data_source"
      -]
  3. Changed5 schema fields changed
    • changedInput schema / properties / query / description
      Previous value: -"Keyword search string. Searched against org name, alternate name, and city in order of relevance. Supports: quoted phrases (\"Red Cross\"), required terms (+evanston), excluded terms (-dental). Empty string returns all orgs within the active filters."New value: +"Keyword search string. Searched against org name, the secondary name line, and city in order of relevance. Supports: quoted phrases (\"Red Cross\"), required terms (+evanston), excluded terms (-dental). Empty string returns all orgs within the active filters."
    • changedInput schema / properties / subsection_code / description
      Previous value: -"501(c) subsection code. \"3\" = public charity (most common — donations tax-deductible), \"4\" = social welfare org, \"6\" = business league/trade association, \"92\" = 4947(a)(1) nonexempt charitable trust. Filters by tax status, not sector."New value: +"501(c) subsection code. \"3\" = charitable/religious/educational organization (most common — includes both public charities and private foundations; nonprofit_get_organization returns foundation_type to tell them apart), \"4\" = social welfare org, \"6\" = business league/trade association, \"92\" = 4947(a)(1) nonexempt charitable trust. Filters by tax status, not sector."
    • changedOutput schema / properties / notice / description
      Previous value: -"Present when the page carried no organizations — distinguishes a zero-match query from a page past the end of the result set, and names the next call."New value: +"Present when the response needs a caveat the domain fields cannot carry: a page that returned no organizations (distinguishing a zero-match query from a page past the end of the result set, and naming the next call), a total_results sitting on the API result ceiling rather than counting matches, or both at once in one string. Absent when the page is populated and the total is an exact count."
    • changedOutput schema / properties / organizations / items / properties / sub_name / description
      Previous value: -"Alternate or subtitle name, or chapter identifier. Null when absent."New value: +"The legal name with the IRS Business Master File secondary name line appended — a division, service-center, or chapter identifier, not a separate trade name the org operates under. Null when the org has no secondary name line."
    • changedOutput schema / properties / organizations / items / properties / subseccd / description
      Previous value: -"501(c) subsection code (e.g., 3 = public charity). Null when not classified."New value: +"501(c) subsection code (e.g., 3 = charitable organization). Null when not classified."
  4. Changed6 schema fields changed
    • changedInput schema / properties / state / description
      Previous value: -"Two-letter US state abbreviation (e.g., \"WA\", \"NY\"). Use \"ZZ\" for foreign entities. Restricts results to orgs headquartered in that state."New value: +"Two-letter US state, territory, or military postal code (e.g., \"WA\", \"NY\", \"PR\"). Case-insensitive — normalized to uppercase before filtering. A code outside that set is rejected rather than silently returning national results. Restricts results to orgs headquartered in that state. \"ZZ\" (foreign address) is accepted, but no organization in the index currently carries it."
    • addedOutput schema / properties / notice
      Added value: +{
      +  "description": "Present when the page carried no organizations — distinguishes a zero-match query from a page past the end of the result set, and names the next call.",
      +  "type": "string"
      +}
    • changedOutput schema / properties / num_pages / description
      Previous value: -"Total pages available (total_results / 25, ceiling)."New value: +"Total pages available (total_results / 25, ceiling). The last valid page is num_pages - 1."
    • addedOutput schema / properties / page_offset
      Added value: +{
      +  "description": "Zero-indexed offset of the first result on this page. Requests are refused once this reaches 10,000.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / per_page
      Added value: +{
      +  "description": "Results per page applied by the API (25).",
      +  "type": "number"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "total_results",
      -  "num_pages",
      -  "cur_page",
      -  "organizations",
      -  "active_filters",
      -  "data_source"
      -]New value: +[
      +  "total_results",
      +  "num_pages",
      +  "cur_page",
      +  "per_page",
      +  "page_offset",
      +  "organizations",
      +  "active_filters",
      +  "data_source"
      +]
  5. First observed

TDQS

A4.7/5.0
Behavior5/5

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

Annotations provide readOnlyHint=true, and the description adds substantial behavioral context: pagination at 25 per page, a 10,000-result cap, behavior for zero-match queries versus pages past the last, and query syntax. This goes well beyond what the annotation alone conveys.

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 information-dense but every sentence earns its place: purpose, filters, pagination, edge cases, query syntax, and data source are all covered without redundancy. The main purpose is front-loaded, followed by operational details.

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?

Given the rich input schema and output schema, the description fully covers what an agent needs: how to search, what filters exist, how pagination works, how results can be used downstream, and unusual response behaviors. No critical operational detail 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 description coverage is 100%, so the schema already documents all parameters well. The description summarizes filters and query operators but does not add significant meaning beyond the schema's detailed parameter descriptions.

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 states a specific verb and resource: search 1.8M+ IRS-recognized tax-exempt organizations by name, keyword, city, or phrase. It clearly distinguishes this search tool from the sibling detail tools by noting that it returns EINs to pass to nonprofit_get_organization or nonprofit_get_filings.

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?

The description explicitly routes the agent: use this search to find nonprofit EINs, then pass them to the sibling detail tools. It also clarifies pagination behavior, result caps, and edge-case responses, making it clear when this tool is appropriate.

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.