@cyanheads/nonprofit-explorer-mcp-server
Search and explore 1.8M+ US nonprofits, fetch Form 990 financials, and access IRS filing history via MCP. STDIO or Streamable HTTP.
3 Tools
Overview
IRS Form 990 data for 1.8M+ tax-exempt organizations, via the ProPublica Nonprofit Explorer API. Search by name, fetch an org's financial snapshot, and pull its full filing history from any MCP client. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
| Tool | Description |
|---|
nonprofit_search | Search 1.8M+ IRS-recognized tax-exempt organizations by name, keyword, city, or phrase with optional state, NTEE sector, and 501(c) filters |
nonprofit_get_organization | Full profile for one org by EIN: legal identity, IRS classification, ruling date, and a financial snapshot from the most recent Form 990 |
nonprofit_get_filings | All Form 990 filings for an org by EIN: year-by-year financials, revenue breakdown, executive compensation, and source PDF links |
Capability reference
- Full-text query — supports quoted phrases (
"Red Cross"), required terms (+evanston), excluded terms (-dental)
- Optional filters: US state/territory or military postal code (
ZZ for foreign entities; a code outside that set is rejected rather than silently returning national results), NTEE major sector (1–10), 501(c) subsection code (3 covers both public charities and private foundations — see foundation_type on nonprofit_get_organization to tell them apart)
- Paginated at 25 per page (
page, zero-indexed); num_pages, per_page, and page_offset track position
- API caps total results at 10,000 —
total_results === 10000 means the actual count may be higher, and a page whose offset reaches that ceiling is refused (pagination_ceiling)
- Zero matches and a page past the last one both succeed with an empty
organizations array and a notice explaining which case it is
- Returns EINs — pass to
nonprofit_get_organization or nonprofit_get_filings for details
- Accepts EIN as integer (
530196605) or string with or without hyphen ("53-0196605"); use nonprofit_search first if you only have an org name
- Returns legal identity, address, NTEE code, 501(c) type, and IRS ruling date
- IRS Business Master File standing: deductibility (including the deductible-by-treaty case), exemption status, and public-charity vs. private-foundation classification — each decoded from its IRS code with the raw code retained
- Financial snapshot from the most recent Form 990: revenue, expenses, assets, liabilities, net assets, plus the source PDF link
filing_count shows how many filings with extracted data are on record
- Data lags 1–2 years —
tax_prd_yr in the snapshot is the fiscal year of the filing, not the current year
- All Form 990 filings with extracted data, sorted newest first — per filing: revenue, expenses, assets, liabilities, net assets, revenue breakdown (contributions, program service, investment income), and the source PDF link
program_expense_ratio is always null — ProPublica returns no Form 990 Part IX program-service expense total, so the program/management/fundraising split is only in the source PDF
- Executive compensation summary with field-name transparency and a note pointing to Schedule J for per-officer detail
filings_pdf_only lists older filings with a PDF but no extracted data
- An EIN that resolves to a real org with no 990 on record returns an empty
filings array plus a notice, not an error
- Data lags 1–2 years — always cite
tax_prd_yr (fiscal year) when presenting figures
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.
ProPublica Nonprofit Explorer / IRS-specific:
- Keyless access — ProPublica Nonprofit Explorer API requires no API key
- Covers 1.8M+ IRS-recognized tax-exempt organizations
- IRS Form 990 data: annual filings for public charities (990), small orgs (990-EZ), and private foundations (990-PF)
- Source filing PDF link on every filing record, except where IRS PDF processing lags the extracted data and
pdf_url is still null
- Data sourced from ProPublica Nonprofit Explorer, derived from IRS Form 990 filings; data lags 1–2 years
Agent-friendly output:
- Provenance on every response —
data_source attribution on all tool outputs, ProPublica URL for direct verification
- Filing-year clarity —
tax_prd_yr prominently labeled as fiscal year with explicit lag caveat in every financial response
- Null values are rendered, not dropped — the formatted text names why a value is absent (never recorded by the IRS, not extracted from the filing, not carried by that form type), and
structuredContent keeps an explicit null rather than omitting the key
- Field-name transparency on compensation —
field_name and form_type exposed so agents know exactly which IRS field was read
Getting started
Public Hosted Instance
A public instance is available at https://nonprofit-explorer.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP, with this client config:
{
"mcpServers": {
"nonprofit-explorer-mcp-server": {
"type": "streamable-http",
"url": "https://nonprofit-explorer.caseyjhand.com/mcp"
}
}
}
Self-Hosted / Local
Add the following to your MCP client configuration file.
{
"mcpServers": {
"nonprofit-explorer-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/nonprofit-explorer-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"nonprofit-explorer-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/nonprofit-explorer-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"nonprofit-explorer-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"ghcr.io/cyanheads/nonprofit-explorer-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
Prerequisites
- Bun v1.3.14 or higher (or Node.js v24+).
- No API key required — ProPublica Nonprofit Explorer is a keyless public API.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/nonprofit-explorer-mcp-server.git
- Navigate into the directory:
cd nonprofit-explorer-mcp-server
- Install dependencies:
- Configure environment:
Configuration
All configuration is validated at startup. Key environment variables:
| Variable | Description | Default |
|---|
MCP_TRANSPORT_TYPE | Transport: stdio or http | stdio |
MCP_HTTP_PORT | HTTP server port | 3010 |
MCP_HTTP_HOST | HTTP server hostname | 127.0.0.1 |
MCP_HTTP_ENDPOINT_PATH | HTTP endpoint path | /mcp |
MCP_PUBLIC_URL | Public origin override for TLS-terminating reverse-proxy deployments | — |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.) | info |
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 |
No server-specific required variables. ProPublica Nonprofit Explorer is a keyless public API.
See .env.example for the full list of optional overrides.
Running the server
Local development
-
Build and run:
bun run rebuild
bun run start:stdio
bun run start:http
-
Run checks and tests:
bun run devcheck
bun run test
bun run lint:mcp
Docker
docker build -t nonprofit-explorer-mcp-server .
docker run --rm -p 3010:3010 nonprofit-explorer-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/nonprofit-explorer-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 and inits the service. |
src/mcp-server/tools | Tool definitions (*.tool.ts). Three tools for search and financial data. |
src/services/nonprofit-explorer | ProPublica Nonprofit Explorer API client and domain types. |
tests/ | Unit and integration tests mirroring src/. |
Development guide
See CLAUDE.md/AGENTS.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catch in tool logic
- Use
ctx.log for request-scoped logging, ctx.state for tenant-scoped storage
- Register new tools via the arrays in
createApp() in src/index.ts
- 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.