io.github.cyanheads/usaspending-mcp-server

Official registry Marketing and sales

Access US federal award, recipient, agency, and spending analytics data from USAspending.gov.

What can you do with io.github.cyanheads/usaspending-mcp-server?

  • USAspending.gov API v2, keyless: the data is public under the DATA Act
  • Award search and the spending analytics tools cover action dates from 2007-10-01 on (an earlier start date fails as date_before_earliest), and DoD contract data lags publication by 90 days
  • usaspending_spending_by_category puts eight category sub-routes behind one category enum, and usaspending_disaster_spending puts five disaster endpoints behind dimension
  • Each request runs under one wall-clock budget (45 s by default); a slow answer gets the whole budget in one attempt, and only fast failures are retried. Failures surface as api_timeout or api_unavailable with each tool's recovery hint, and a rejected re...
  • Chaining IDs as explicit fields: generated_internal_id, agency_slug, recipient.recipient_id, federal_account, and account_number, so agents follow the money without parsing display strings
  • Honest pagination: page_metadata.has_next on every list, a total or count where the upstream publishes one, and truncated / shown / cap only when rows are known to exist beyond those returned. A full page with no such evidence keeps has_next w...
  • Empty results are notices, not errors: account funding, account breakdown, and recipient search distinguish a known zero total from an empty page past the total, which directs callers to an earlier page with the same filters. Without a total, notices descri...
  • Typed failures with recovery hints: award_not_found, recipient_not_found, agency_not_found, account_not_found, no_match, conflicting_input, date_before_earliest, date_range_inverted, unsupported_sort, assistance_listings_type_mismatch, `...

Install

Add this to your client's MCP configuration (Claude Desktop: claude_desktop_config.json; Cursor: .cursor/mcp.json; VS Code and others use the same "mcpServers" shape).

Remote (streamable-http)
Claude Code
claude mcp add --transport http usaspending-mcp-server 'https://usaspending.caseyjhand.com/mcp'
JSON configuration (Claude Desktop, Cursor, VS Code)
{
    "mcpServers": {
        "usaspending-mcp-server": {
            "type": "http",
            "url": "https://usaspending.caseyjhand.com/mcp"
        }
    }
}
NPM package @cyanheads/usaspending-mcp-server
Claude Code
claude mcp add usaspending-mcp-server -e 'MCP_LOG_LEVEL=info' -- npx -y @cyanheads/usaspending-mcp-server@0.7.0
JSON configuration (Claude Desktop, Cursor, VS Code)
{
    "mcpServers": {
        "usaspending-mcp-server": {
            "command": "npx",
            "args": [
                "-y",
                "@cyanheads/usaspending-mcp-server@0.7.0"
            ],
            "env": {
                "MCP_LOG_LEVEL": "info"
            }
        }
    }
}

Environment variables

  • MCP_LOG_LEVEL Sets the minimum log level for output (e.g., 'debug', 'info', 'warn').
NPM package @cyanheads/usaspending-mcp-server
Claude Code
claude mcp add usaspending-mcp-server -e 'MCP_TRANSPORT_TYPE=<MCP_TRANSPORT_TYPE>' -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/usaspending-mcp-server@0.7.0
JSON configuration (Claude Desktop, Cursor, VS Code)
{
    "mcpServers": {
        "usaspending-mcp-server": {
            "command": "npx",
            "args": [
                "-y",
                "@cyanheads/usaspending-mcp-server@0.7.0"
            ],
            "env": {
                "MCP_TRANSPORT_TYPE": "<MCP_TRANSPORT_TYPE>",
                "MCP_HTTP_HOST": "127.0.0.1",
                "MCP_HTTP_PORT": "3010",
                "MCP_HTTP_ENDPOINT_PATH": "/mcp",
                "MCP_AUTH_MODE": "none",
                "MCP_LOG_LEVEL": "info"
            }
        }
    }
}

Environment variables

  • MCP_TRANSPORT_TYPE Selects the HTTP transport.
  • MCP_HTTP_HOST The hostname for the HTTP server.
  • MCP_HTTP_PORT The port to run the HTTP server on.
  • MCP_HTTP_ENDPOINT_PATH The endpoint path for the MCP server.
  • MCP_AUTH_MODE Authentication mode to use: 'none', 'jwt', or 'oauth'.
  • MCP_LOG_LEVEL Sets the minimum log level for output (e.g., 'debug', 'info', 'warn').

Documentation

From the project's README on GitHub, refreshed weekly. Links open on GitHub.

Contents
  1. @cyanheads/usaspending-mcp-server
  2. Overview
  3. Capability reference
  4. Features
  5. Getting started
  6. Configuration
  7. Running the server
  8. Project structure
  9. Development guide
  10. Contributing
  11. License

@cyanheads/usaspending-mcp-server

Access US federal award, recipient, agency, and spending analytics data from USAspending.gov via MCP. STDIO or Streamable HTTP.

18 Tools

Public Hosted Server: https://usaspending.caseyjhand.com/mcp


Overview

Where federal money goes, from USAspending.gov: awards, recipients, agencies, and spending. Search and trace awards down to transactions, subawards, and funding accounts; profile recipients and agencies; and aggregate spending by geography, category, time, and disaster appropriation.

Tools
ToolDescription
usaspending_list_agenciesList top-tier federal agencies with codes, slugs, and budget totals labelled by reporting year and quarter
usaspending_autocomplete_filtersLook up NAICS, PSC, CFDA, agency, or recipient codes from a free-text description
usaspending_search_awardsSearch awards by keyword, recipient, agency, award type, NAICS code, assistance listing, PSC, DEF code, location, or date range
usaspending_get_awardFetch one award's full record: amounts, recipient, agencies, codes, parent IDV, DEF-code funding
usaspending_get_award_transactionsList the transactions (modifications, amendments) on an award
usaspending_get_award_subawardsList the subcontracts or subgrants under a prime award
usaspending_get_award_federal_accountsList the Treasury federal accounts that funded an award, with the amount from each
usaspending_get_idv_awardsList the child orders and sub-IDVs placed under an IDV
usaspending_search_recipientsSearch recipients by name, UEI, or DUNS
usaspending_get_recipientFetch a recipient's profile: address, business types, parent, and award totals
usaspending_get_agencyFetch an agency's mission, latest-year budget totals, sub-agencies, and DEF codes
usaspending_spending_by_geographyAggregate spending by state, county, or congressional district
usaspending_spending_by_categoryAggregate spending by NAICS, PSC, agency, CFDA program, or recipient
usaspending_spending_over_timeAggregate spending by fiscal year, quarter, or month
usaspending_disaster_spendingBreak down disaster and emergency supplemental spending by agency, program, recipient, or geography
usaspending_search_federal_accountsSearch federal accounts by title keyword or agency identifier
usaspending_get_federal_accountFetch a federal account's budget totals and its Treasury Account Symbol components
usaspending_get_federal_account_breakdownBreak a federal account's obligations down by program activity or object class

Capability reference

usaspending_list_agencies tool
  • Takes sort (agency_name, budget_authority_amount, obligated_amount, outlay_amount) and order; returns every agency unless an optional positive limit is supplied. With limit, page defaults to 1; without it, page is ignored. total always counts the full directory and has_next appears only when paginating
  • Rows carry toptier_code and agency_slug, both accepted by usaspending_get_agency, plus budget_authority_amount, obligated_amount, and outlay_amount for the latest reported period. fiscal_year and fiscal_quarter preserve the provider's reporting labels when present

usaspending_autocomplete_filters tool
  • type (naics, psc, cfda, awarding_agency, recipient) plus search_text; limit 1–500, default 10
  • Rows carry code and name, and uei / duns for recipients; no match fails as no_match. A cfda code goes in assistance_listings and a psc code in psc_codes on usaspending_search_awards and the three spending analytics tools
  • Agency rows carry the matched agency's own name, abbreviation, and tier (toptier or subtier), its parent's toptier_name and toptier_code, and subtier_code when supplied. Pass name to agency_name on award search or spending analytics to match that agency; pass toptier_name for the whole department. Agency results combine top-tier then sub-tier matches under one limit; office matches are excluded
  • naics matches official NAICS title text: "software" resolves, "cybersecurity" does not, so search with the industry term a title would use

usaspending_search_awards tool
  • Filters: keyword, agency_name, recipient_name, naics_codes, assistance_listings (Assistance Listing numbers such as 93.866, from usaspending_autocomplete_filters type: cfda), psc_codes (1–4 characters, where a prefix such as Y1 covers the codes under it; contracts and IDVs only), def_codes (Disaster Emergency Fund Codes such as Z; PSC and DEF codes are sent uppercased), time_period (YYYY-MM-DD from 2007-10-01 on; either end may be given alone), and location_filter (country defaults to USA, and a territory code such as PRI becomes USA plus its state; state as a postal or 2-digit FIPS code, FM/MH/PW/UM and armed-forces AA/AE/AP included, or under another country as that country's own 2-letter subdivision code such as ON with CAN; county as 3 digits with state or the 5-digit FIPS code alone; echoed as applied_location); award_type_codes defaults to contracts (A–D) and must stay in one group: IDVs IDV_A–IDV_E, grants 02–05/F001/F002, direct payments 06/10/F006/F007, loans 07/08/F003/F004, or other assistance 09/11/-1/F005/F008/F009/F010; limit up to 100
  • Rows carry generated_internal_id for usaspending_get_award and agency_slug for usaspending_get_agency; loan rows carry loan_value, subsidy_cost, and issued_date in place of amounts and dates. There is no total, and page_metadata.has_next is true on any full page. The nested filters object takes the analytics tools' filters keys, except recipient_id, and wins per field over the flat ones. Failures are assistance_listings_type_mismatch (listings with a non-assistance group), psc_codes_type_mismatch (PSC codes with an assistance group), unsupported_sort, date_range_inverted, date_before_earliest, and invalid_location (an unknown state, a 3-digit county without a state, a county under an armed-forces code (AA/AE/AP), a county or FIPS-number state under another country, or parts naming different states)
  • sort depends on the group: loans take Loan Value (default), Subsidy Cost, Issued Date, Recipient Name, or Awarding Agency; the others Award Amount (default), Total Outlays, Start Date, End Date (not IDVs), Recipient Name, or Awarding Agency. Page numbers stop at a 50,000-result offset (pagination_limit_exceeded); past it, page with the last_record_sort_value + last_record_unique_id cursor, returned below a 10,000-result offset

usaspending_get_award tool
  • award_id is a generated_unique_award_id, the generated_internal_id from search; an unknown ID fails as award_not_found
  • Returns category, total_obligation, total_outlays, total_account_obligation, total_account_outlay, base_exercised_options, subaward_count, NAICS / PSC codes, account_obligations_by_defc, account_outlays_by_defc, and, on loans, total_loan_value and total_subsidy_cost, where supplied
  • assistance_listings lists every Assistance Listing on an assistance award, in upstream order, as number, title, and obligation; a number goes in usaspending_search_awards assistance_listings
  • recipient carries uei, parent_uei, business_categories (category names, not the business_types codes of usaspending_get_recipient), and a three-letter country_code, county_name, congressional_code, and zip5 on its location. place_of_performance also carries a country code, county name, and congressional code; a location with no fields upstream is omitted
  • recipient.recipient_id and recipient.parent_recipient_id chain to usaspending_get_recipient and parent_award.generated_unique_award_id to the parent IDV; category: "idv" awards list their children via usaspending_get_idv_awards

usaspending_get_award_transactions tool
  • award_id plus sort (action_date, federal_action_obligation, modification_number); limit up to 100
  • Rows carry a string id (ASST_TX or CONT_TX), action_date, modification_number, action_type, and a signed federal_action_obligation (negative is a deobligation). Loan transactions also carry face_value_loan_guarantee and original_loan_subsidy_cost; assistance transactions carry cfda_number when supplied

usaspending_get_award_subawards tool
  • award_id plus sort (subaward_number, description, action_date, amount, recipient_name); limit up to 100
  • Rows carry id, subaward_number, description, amount, action_date, and recipient_name; the upstream listing supplies no recipient UEI or location. subaward_count on usaspending_get_award says whether any exist

usaspending_get_award_federal_accounts tool
  • award_id is a generated_unique_award_id; limit up to 100, with page_metadata.count as the total
  • Rows carry federal_account (AGENCY-MAIN, e.g. 080-0120) for usaspending_get_federal_account, total_transaction_obligated_amount, and the funding agency with its funding_agency_slug

usaspending_get_idv_awards tool
  • Parent IDV award_id; type is child_awards (task and delivery orders, the default), child_idvs, or grandchild_awards; limit up to 100
  • Rows carry generated_unique_award_id for usaspending_get_award, obligated_amount, and performance dates; there is no total, and has_next is true on any full page

usaspending_search_recipients tool
  • keyword matches names, UEI, or DUNS, partial matches included; surrounding whitespace is trimmed, and blank text applies no keyword filter with a notice. Optional award_type still scopes the totals; limit up to 100
  • Rows carry id (a hash suffixed -P parent, -C child, or -R standalone) for usaspending_get_recipient, plus uei, duns, recipient_level, and amount; page_metadata.total is the full match count

usaspending_get_recipient tool
  • recipient_id from usaspending_search_recipients or usaspending_get_award; optional fiscal_year (2001–2030) scopes the totals to that fiscal year, which otherwise cover the trailing 12 months; an unknown ID fails as recipient_not_found
  • Returns address, business_types, parent_name / parent_uei, alternate_names, total_transaction_amount, total_transactions, and loan face-value totals, with period naming the window (FY2020 or trailing 12 months). Totals span every award type; for totals by type, use usaspending_spending_over_time with filters.recipient_id and award_type_codes

usaspending_get_agency tool
  • One of toptier_code (e.g. 097) or agency_slug (e.g. department-of-defense); page walks the sub-agency list 10 at a time. Failures are missing_input, conflicting_input (both identifiers sent), and agency_not_found
  • Returns mission, plus budgetary_resources_amount, obligated_amount, and outlay_amount for the most recent fiscal_year with reported budget data (a newly opened year with no amounts yet is skipped), sub_agencies with obligations and transaction and new-award counts for that same year (sub_agency_fiscal_year names it; without a budget year within 5 seconds the breakdown covers the current fiscal year), and def_codes
  • A failed budget or sub-agency request still returns the overview: the missing fields are omitted and unavailable_sections names each section with its reason (api_unavailable, api_timeout, or upstream_error) and whether a retry may load it

usaspending_spending_by_geography tool
  • scope (place_of_performance, recipient_location) and geo_layer (state, county, district) are required; filters takes keywords, award_type_codes, agency_name, recipient_id, naics_codes, assistance_listings, psc_codes, def_codes (the same code filters as usaspending_search_awards, echoed as applied_*), and time_period_start / time_period_end (YYYY-MM-DD; either alone fills the other, as in usaspending_search_awards, applied_time_period_* echoes the range sent, a start after the end fails as date_range_inverted, and a range starting before 2007-10-01 fails as date_before_earliest); limit 1–500, default 50
  • Award types may mix groups. When every one named is a contract or IDV, assistance_listings fails as assistance_listings_type_mismatch; when every one is assistance, psc_codes fails as psc_codes_type_mismatch. Code-filtered amounts cover whole matching awards, and DEF-filtered totals can be negative
  • Rows carry shape_code, display_name, aggregated_amount, population, and per_capita, ranked by amount; total_areas_available counts every match before the cap
  • shape_codes (1–500) returns only the listed areas, in the shape_code form of the layer: postal code for state (NY), 5-digit state + county FIPS for county (36117), 4-digit state FIPS + district for district (3623). Selection runs over every matched area, so it reaches areas ranked past limit; the codes are echoed as applied_shape_codes, and a code that matches no area is named in the notice
  • With no filters, every award type is aggregated and applied_award_type_default says so; subawards: true switches to subaward data

usaspending_spending_by_category tool
  • category is naics, psc, awarding_agency, awarding_subagency, funding_agency, funding_subagency, cfda, or recipient_duns; takes the same filters object as usaspending_spending_by_geography; limit up to 100
  • Rows carry id, code, name, and amount, ranked by obligation; recipient_duns rows carry the DUNS as code plus recipient_id and uei when upstream has them, and recipient_id chains to usaspending_get_recipient

usaspending_spending_over_time tool
  • group is fiscal_year, quarter, or month (fiscal month, where 1 is October); the same filters object, with award_type_codes defaulting to contracts, so assistance_listings needs an assistance group named; subawards: true switches to subaward data
  • Rows carry time_period, aggregated_amount, and per-type contracts, grants, direct_payments, idvs, loans, and other

usaspending_disaster_spending tool
  • dimension is overview, agency, cfda, recipient, or geography; filters.def_codes is optional for overview and required for every other dimension (missing_def_codes when absent/empty). Codes such as ["L", "M", "N", "O", "P"] isolate COVID-19 funding and are echoed as applied_def_codes. limit is up to 100 on every dimension but overview; spending_type (award, the default, or total) applies to agency only, and geography takes filters.geo_layer (state, county)
  • Rows carry obligation, outlay, and award_count, plus total_budgetary_resources on agency rows under spending_type: total; overview returns totals and funding_by_def_code. A recipient row's id chains to usaspending_get_recipient. Recipient filters.query narrows by search text; it is trimmed and echoed as applied_query, with blanks applying no query. A recipient total of 10,000 is a reachable ceiling and a lower bound on possible matches, flagged truncated; narrow with filters.query to reach the tail. Geography areas are ranked by aggregated_amount and paged with limit and page, with the full area count as total; a page with areas below it is flagged truncated, and truncationCeiling is the lowest amount shown. Spending with no recorded place of performance ranks as one unattributed area
  • Agency, cfda, and recipient also return totals across every matching row: obligation, outlay, and either total_budgetary_resources (agency, total) or award_count. Overview can still time out with codes supplied: narrow filters.def_codes, retry later, or use the agency breakdown with spending_type: total for obligations, outlays, and budgetary resources
  • Notices preserve upstream messages, ignored filters, cap guidance, and empty-page recovery on both output surfaces. query is ignored outside recipient, geo_layer outside geography, and award_type_codes on overview. An empty page whose offset reaches a positive total directs callers to an earlier page with the same filters; an empty interior page reports the total without claiming exhaustion, and an absent total stays unknown

usaspending_search_federal_accounts tool
  • Optional keyword and 3-digit agency_identifier; sort_field is account_name, account_number, budgetary_resources (default), or managing_agency; limit up to 100
  • Rows carry account_number (e.g. 097-8097) for the federal-account tools, managing_agency, and budgetary_resources; page_metadata.count is the total. Optional fiscal_year selects the reporting year; otherwise the provider uses its latest submission year. The returned fiscal_year identifies that period

usaspending_get_federal_account tool
  • account_code in AGENCY-MAIN format, from account_number in search results or federal_account on an award; an unknown code fails as account_not_found
  • Optional fiscal_year selects the reporting year; otherwise the provider uses the current federal fiscal year. Returns total_obligated_amount, total_gross_outlay_amount, and total_budgetary_resources for the returned fiscal_year, plus children: one entry per Treasury Account Symbol with its own amounts. A year without financial data retains account metadata and a notice, without substituting another year

usaspending_get_federal_account_breakdown tool
  • account_code plus dimension (program_activity or object_class); limit up to 100, with page_metadata.total as the row count
  • Rows carry code, name, and obligations; program_activity rows add type, either PAC/PAN or PARK
  • Optional fiscal_year scopes financial reporting periods to October 1 through September 30, echoed in time_period and period. Omission covers all available periods

All three federal-account tools accept an integer fiscal_year from 2001 through the current federal fiscal year (which rolls over October 1); blank form values mean omitted. Search and detail budget totals use different upstream calculations and need not match even for the same year.

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.

USAspending-specific:

  • USAspending.gov API v2, keyless: the data is public under the DATA Act
  • Award search and the spending analytics tools cover action dates from 2007-10-01 on (an earlier start date fails as date_before_earliest), and DoD contract data lags publication by 90 days
  • usaspending_spending_by_category puts eight category sub-routes behind one category enum, and usaspending_disaster_spending puts five disaster endpoints behind dimension
  • Each request runs under one wall-clock budget (45 s by default); a slow answer gets the whole budget in one attempt, and only fast failures are retried. Failures surface as api_timeout or api_unavailable with each tool's recovery hint, and a rejected request carries USAspending's own explanation in the error message

Agent-friendly output:

  • Chaining IDs as explicit fields: generated_internal_id, agency_slug, recipient.recipient_id, federal_account, and account_number, so agents follow the money without parsing display strings
  • Honest pagination: page_metadata.has_next on every list, a total or count where the upstream publishes one, and truncated / shown / cap only when rows are known to exist beyond those returned. A full page with no such evidence keeps has_next without claiming truncation
  • Empty results are notices, not errors: account funding, account breakdown, and recipient search distinguish a known zero total from an empty page past the total, which directs callers to an earlier page with the same filters. Without a total, notices describe only the page; award search never supplies a total. The ID-keyed list tools (transactions, subawards, funding accounts, IDV children, account breakdown) return an empty list for an unknown ID rather than failing
  • Typed failures with recovery hints: award_not_found, recipient_not_found, agency_not_found, account_not_found, no_match, conflicting_input, date_before_earliest, date_range_inverted, unsupported_sort, assistance_listings_type_mismatch, psc_codes_type_mismatch, invalid_location, pagination_limit_exceeded, incomplete_cursor, missing_def_codes

Getting started

Public Hosted Instance

A public instance is available at https://usaspending.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 usaspending-mcp-server https://usaspending.caseyjhand.com/mcp

For Cline (cline_mcp_settings.json):

{
  "mcpServers": {
    "usaspending-mcp-server": {
      "type": "streamableHttp",
      "url": "https://usaspending.caseyjhand.com/mcp"
    }
  }
}

For Cursor (mcp.json):

{
  "mcpServers": {
    "usaspending-mcp-server": {
      "url": "https://usaspending.caseyjhand.com/mcp"
    }
  }
}

Claude Desktop adds remote servers under Settings → Connectors.

Self-Hosted / Local

Add the following to your MCP client configuration file. No API key is required.

{
  "mcpServers": {
    "usaspending-mcp-server": {
      "type": "stdio",
      "command": "bunx",
      "args": ["@cyanheads/usaspending-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info"
      }
    }
  }
}

Or with npx (no Bun required):

{
  "mcpServers": {
    "usaspending-mcp-server": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@cyanheads/usaspending-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info"
      }
    }
  }
}

Or with Docker:

{
  "mcpServers": {
    "usaspending-mcp-server": {
      "type": "stdio",
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "MCP_TRANSPORT_TYPE=stdio",
        "ghcr.io/cyanheads/usaspending-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+).
  • No API key or account: USAspending.gov is open to anonymous requests.
Installation
  1. Clone the repository:
git clone https://github.com/cyanheads/usaspending-mcp-server.git
  1. Navigate into the directory:
cd usaspending-mcp-server
  1. Install dependencies:
bun install
  1. Configure environment (optional):
cp .env.example .env
# edit .env if you need to override defaults

Configuration

No variable is required; the defaults work out of the box.

VariableDescriptionDefault
USASPENDING_BASE_URLUSAspending.gov API v2 base URL.https://api.usaspending.gov/api/v2/
USASPENDING_TIMEOUT_MSPer-attempt HTTP timeout, in ms (1000–120000). Each attempt is cut at this or at the time left in the request budget, whichever is smaller; a timed-out attempt is not retried.45000
USASPENDING_RETRY_BUDGET_MSWall-clock budget for one request, every attempt and backoff included, in ms (1000–300000). Fast failures such as a 503 retry inside it.45000, or USASPENDING_TIMEOUT_MS when higher
MCP_TRANSPORT_TYPETransport: stdio or http.stdio
MCP_HTTP_PORTHTTP server port.3010
MCP_SESSION_MODEHTTP session mode: stateless, stateful, or auto.stateless
MCP_AUTH_MODEAuthentication: none, jwt, or oauth.none
MCP_LOG_LEVELLog level (debug, info, warning, error, etc.).info
LOG_TOOL_FAILURE_PAYLOADSLog each failed tool call's arguments and result, redacted by key name and capped at LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES (default 16384). A secret inside a free-form value is not redacted.false
LOGS_DIRDirectory for log files (Node.js only).<project-root>/logs
STORAGE_PROVIDER_TYPEStorage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1.in-memory
OTEL_ENABLEDEnable OpenTelemetry.false
OTEL_EXPORTER_OTLP_LOGS_ENDPOINTOpt-in OTLP log export endpoint; the base OTEL_EXPORTER_OTLP_ENDPOINT never enables it.—

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
    bun run test       # Vitest test suite
    bun run lint:mcp   # Validate MCP definitions against spec
Docker
docker build -t usaspending-mcp-server .
docker run --rm -p 3010:3010 usaspending-mcp-server

The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/usaspending-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.

Project structure

DirectoryPurpose
src/index.tscreateApp() entry point: registers the tools and initializes the USAspending service.
src/configServer-specific environment variable parsing and validation with Zod.
src/mcp-server/tools/definitionsTool definitions (*.tool.ts) plus shared filter, date, pagination, and formatting helpers.
src/services/usaspendingUSAspending.gov API client: request timeouts, retry budget, raw response types.
tests/Unit tests for tools, the service, config, and scripts.

Development guide

See CLAUDE.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 barrel in src/mcp-server/tools/definitions/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.

Frequently asked questions

What is io.github.cyanheads/usaspending-mcp-server?

Access US federal award, recipient, agency, and spending analytics data from USAspending.gov.

How do I install io.github.cyanheads/usaspending-mcp-server?

It runs as a remote server. In Claude Code: claude mcp add --transport http usaspending-mcp-server 'https://usaspending.caseyjhand.com/mcp'. For other clients, paste the JSON configuration from this page into their MCP settings.

Does io.github.cyanheads/usaspending-mcp-server need an API key?

Its registry entry lists no required key or secret. Some features may still need an account with the service it connects to.

Is io.github.cyanheads/usaspending-mcp-server open source?

Yes. Its code is on GitHub under the Apache-2.0 license.

Who maintains io.github.cyanheads/usaspending-mcp-server?

It is published by cyanheads. AI.tn lists it but does not maintain or endorse it.

From the official MCP Registry. Listing is not an endorsement: review a server's code and permissions before giving it access to your data.