io.github.cyanheads/usaspending-mcp-server
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_categoryputs eight category sub-routes behind onecategoryenum, andusaspending_disaster_spendingputs five disaster endpoints behinddimension- 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_timeoutorapi_unavailablewith each tool's recovery hint, and a rejected re... - Chaining IDs as explicit fields:
generated_internal_id,agency_slug,recipient.recipient_id,federal_account, andaccount_number, so agents follow the money without parsing display strings - Honest pagination:
page_metadata.has_nexton every list, atotalorcountwhere the upstream publishes one, andtruncated/shown/caponly when rows are known to exist beyond those returned. A full page with no such evidence keepshas_nextw... - 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).
claude mcp add --transport http usaspending-mcp-server 'https://usaspending.caseyjhand.com/mcp'
{
"mcpServers": {
"usaspending-mcp-server": {
"type": "http",
"url": "https://usaspending.caseyjhand.com/mcp"
}
}
}
@cyanheads/usaspending-mcp-serverclaude mcp add usaspending-mcp-server -e 'MCP_LOG_LEVEL=info' -- npx -y @cyanheads/usaspending-mcp-server@0.7.0
{
"mcpServers": {
"usaspending-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/usaspending-mcp-server@0.7.0"
],
"env": {
"MCP_LOG_LEVEL": "info"
}
}
}
}
Environment variables
MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
@cyanheads/usaspending-mcp-serverclaude 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
{
"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_TYPESelects the HTTP transport.MCP_HTTP_HOSTThe hostname for the HTTP server.MCP_HTTP_PORTThe port to run the HTTP server on.MCP_HTTP_ENDPOINT_PATHThe endpoint path for the MCP server.MCP_AUTH_MODEAuthentication mode to use: 'none', 'jwt', or 'oauth'.MCP_LOG_LEVELSets 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
@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
| Tool | Description |
|---|---|
usaspending_list_agencies | List top-tier federal agencies with codes, slugs, and budget totals labelled by reporting year and quarter |
usaspending_autocomplete_filters | Look up NAICS, PSC, CFDA, agency, or recipient codes from a free-text description |
usaspending_search_awards | Search awards by keyword, recipient, agency, award type, NAICS code, assistance listing, PSC, DEF code, location, or date range |
usaspending_get_award | Fetch one award's full record: amounts, recipient, agencies, codes, parent IDV, DEF-code funding |
usaspending_get_award_transactions | List the transactions (modifications, amendments) on an award |
usaspending_get_award_subawards | List the subcontracts or subgrants under a prime award |
usaspending_get_award_federal_accounts | List the Treasury federal accounts that funded an award, with the amount from each |
usaspending_get_idv_awards | List the child orders and sub-IDVs placed under an IDV |
usaspending_search_recipients | Search recipients by name, UEI, or DUNS |
usaspending_get_recipient | Fetch a recipient's profile: address, business types, parent, and award totals |
usaspending_get_agency | Fetch an agency's mission, latest-year budget totals, sub-agencies, and DEF codes |
usaspending_spending_by_geography | Aggregate spending by state, county, or congressional district |
usaspending_spending_by_category | Aggregate spending by NAICS, PSC, agency, CFDA program, or recipient |
usaspending_spending_over_time | Aggregate spending by fiscal year, quarter, or month |
usaspending_disaster_spending | Break down disaster and emergency supplemental spending by agency, program, recipient, or geography |
usaspending_search_federal_accounts | Search federal accounts by title keyword or agency identifier |
usaspending_get_federal_account | Fetch a federal account's budget totals and its Treasury Account Symbol components |
usaspending_get_federal_account_breakdown | Break 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) andorder; returns every agency unless an optional positivelimitis supplied. Withlimit,pagedefaults to 1; without it,pageis ignored.totalalways counts the full directory andhas_nextappears only when paginating - Rows carry
toptier_codeandagency_slug, both accepted byusaspending_get_agency, plusbudget_authority_amount,obligated_amount, andoutlay_amountfor the latest reported period.fiscal_yearandfiscal_quarterpreserve the provider's reporting labels when present
usaspending_autocomplete_filters tool
type(naics,psc,cfda,awarding_agency,recipient) plussearch_text;limit1–500, default 10- Rows carry
codeandname, anduei/dunsfor recipients; no match fails asno_match. Acfdacode goes inassistance_listingsand apsccode inpsc_codesonusaspending_search_awardsand the three spending analytics tools - Agency rows carry the matched agency's own
name,abbreviation, andtier(toptierorsubtier), its parent'stoptier_nameandtoptier_code, andsubtier_codewhen supplied. Passnametoagency_nameon award search or spending analytics to match that agency; passtoptier_namefor the whole department. Agency results combine top-tier then sub-tier matches under onelimit; office matches are excluded naicsmatches 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 as93.866, fromusaspending_autocomplete_filterstype: cfda),psc_codes(1–4 characters, where a prefix such asY1covers the codes under it; contracts and IDVs only),def_codes(Disaster Emergency Fund Codes such asZ; PSC and DEF codes are sent uppercased),time_period(YYYY-MM-DDfrom 2007-10-01 on; either end may be given alone), andlocation_filter(countrydefaults toUSA, and a territory code such asPRIbecomesUSAplus its state;stateas a postal or 2-digit FIPS code,FM/MH/PW/UMand armed-forcesAA/AE/APincluded, or under another country as that country's own 2-letter subdivision code such asONwithCAN;countyas 3 digits withstateor the 5-digit FIPS code alone; echoed asapplied_location);award_type_codesdefaults to contracts (A–D) and must stay in one group: IDVsIDV_A–IDV_E, grants02–05/F001/F002, direct payments06/10/F006/F007, loans07/08/F003/F004, or other assistance09/11/-1/F005/F008/F009/F010;limitup to 100 - Rows carry
generated_internal_idforusaspending_get_awardandagency_slugforusaspending_get_agency; loan rows carryloan_value,subsidy_cost, andissued_datein place of amounts and dates. There is no total, andpage_metadata.has_nextis true on any full page. The nestedfiltersobject takes the analytics tools'filterskeys, exceptrecipient_id, and wins per field over the flat ones. Failures areassistance_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, andinvalid_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) sortdepends on the group: loans takeLoan Value(default),Subsidy Cost,Issued Date,Recipient Name, orAwarding Agency; the othersAward Amount(default),Total Outlays,Start Date,End Date(not IDVs),Recipient Name, orAwarding Agency. Page numbers stop at a 50,000-result offset (pagination_limit_exceeded); past it, page with thelast_record_sort_value+last_record_unique_idcursor, returned below a 10,000-result offset
usaspending_get_award tool
award_idis agenerated_unique_award_id, thegenerated_internal_idfrom search; an unknown ID fails asaward_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_valueandtotal_subsidy_cost, where supplied assistance_listingslists every Assistance Listing on an assistance award, in upstream order, asnumber,title, andobligation; anumbergoes inusaspending_search_awardsassistance_listingsrecipientcarriesuei,parent_uei,business_categories(category names, not thebusiness_typescodes ofusaspending_get_recipient), and a three-lettercountry_code,county_name,congressional_code, andzip5on itslocation.place_of_performancealso carries a country code, county name, and congressional code; a location with no fields upstream is omittedrecipient.recipient_idandrecipient.parent_recipient_idchain tousaspending_get_recipientandparent_award.generated_unique_award_idto the parent IDV;category: "idv"awards list their children viausaspending_get_idv_awards
usaspending_get_award_transactions tool
award_idplussort(action_date,federal_action_obligation,modification_number);limitup to 100- Rows carry a string
id(ASST_TXorCONT_TX),action_date,modification_number,action_type, and a signedfederal_action_obligation(negative is a deobligation). Loan transactions also carryface_value_loan_guaranteeandoriginal_loan_subsidy_cost; assistance transactions carrycfda_numberwhen supplied
usaspending_get_award_subawards tool
award_idplussort(subaward_number,description,action_date,amount,recipient_name);limitup to 100- Rows carry
id,subaward_number,description,amount,action_date, andrecipient_name; the upstream listing supplies no recipient UEI or location.subaward_countonusaspending_get_awardsays whether any exist
usaspending_get_award_federal_accounts tool
award_idis agenerated_unique_award_id;limitup to 100, withpage_metadata.countas the total- Rows carry
federal_account(AGENCY-MAIN, e.g.080-0120) forusaspending_get_federal_account,total_transaction_obligated_amount, and the funding agency with itsfunding_agency_slug
usaspending_get_idv_awards tool
- Parent IDV
award_id;typeischild_awards(task and delivery orders, the default),child_idvs, orgrandchild_awards;limitup to 100 - Rows carry
generated_unique_award_idforusaspending_get_award,obligated_amount, and performance dates; there is no total, andhas_nextis true on any full page
usaspending_search_recipients tool
keywordmatches names, UEI, or DUNS, partial matches included; surrounding whitespace is trimmed, and blank text applies no keyword filter with a notice. Optionalaward_typestill scopes the totals;limitup to 100- Rows carry
id(a hash suffixed-Pparent,-Cchild, or-Rstandalone) forusaspending_get_recipient, plusuei,duns,recipient_level, andamount;page_metadata.totalis the full match count
usaspending_get_recipient tool
recipient_idfromusaspending_search_recipientsorusaspending_get_award; optionalfiscal_year(2001–2030) scopes the totals to that fiscal year, which otherwise cover the trailing 12 months; an unknown ID fails asrecipient_not_found- Returns address,
business_types,parent_name/parent_uei,alternate_names,total_transaction_amount,total_transactions, and loan face-value totals, withperiodnaming the window (FY2020ortrailing 12 months). Totals span every award type; for totals by type, useusaspending_spending_over_timewithfilters.recipient_idandaward_type_codes
usaspending_get_agency tool
- One of
toptier_code(e.g.097) oragency_slug(e.g.department-of-defense);pagewalks the sub-agency list 10 at a time. Failures aremissing_input,conflicting_input(both identifiers sent), andagency_not_found - Returns
mission, plusbudgetary_resources_amount,obligated_amount, andoutlay_amountfor the most recentfiscal_yearwith reported budget data (a newly opened year with no amounts yet is skipped),sub_agencieswith obligations and transaction and new-award counts for that same year (sub_agency_fiscal_yearnames it; without a budget year within 5 seconds the breakdown covers the current fiscal year), anddef_codes - A failed budget or sub-agency request still returns the overview: the missing fields are omitted and
unavailable_sectionsnames each section with itsreason(api_unavailable,api_timeout, orupstream_error) and whether a retry may load it
usaspending_spending_by_geography tool
scope(place_of_performance,recipient_location) andgeo_layer(state,county,district) are required;filterstakeskeywords,award_type_codes,agency_name,recipient_id,naics_codes,assistance_listings,psc_codes,def_codes(the same code filters asusaspending_search_awards, echoed asapplied_*), andtime_period_start/time_period_end(YYYY-MM-DD; either alone fills the other, as inusaspending_search_awards,applied_time_period_*echoes the range sent, a start after the end fails asdate_range_inverted, and a range starting before 2007-10-01 fails asdate_before_earliest);limit1–500, default 50- Award types may mix groups. When every one named is a contract or IDV,
assistance_listingsfails asassistance_listings_type_mismatch; when every one is assistance,psc_codesfails aspsc_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, andper_capita, ranked by amount;total_areas_availablecounts every match before the cap shape_codes(1–500) returns only the listed areas, in theshape_codeform of the layer: postal code forstate(NY), 5-digit state + county FIPS forcounty(36117), 4-digit state FIPS + district fordistrict(3623). Selection runs over every matched area, so it reaches areas ranked pastlimit; the codes are echoed asapplied_shape_codes, and a code that matches no area is named in thenotice- With no filters, every award type is aggregated and
applied_award_type_defaultsays so;subawards: trueswitches to subaward data
usaspending_spending_by_category tool
categoryisnaics,psc,awarding_agency,awarding_subagency,funding_agency,funding_subagency,cfda, orrecipient_duns; takes the samefiltersobject asusaspending_spending_by_geography;limitup to 100- Rows carry
id,code,name, andamount, ranked by obligation;recipient_dunsrows carry the DUNS ascodeplusrecipient_idandueiwhen upstream has them, andrecipient_idchains tousaspending_get_recipient
usaspending_spending_over_time tool
groupisfiscal_year,quarter, ormonth(fiscal month, where 1 is October); the samefiltersobject, withaward_type_codesdefaulting to contracts, soassistance_listingsneeds an assistance group named;subawards: trueswitches to subaward data- Rows carry
time_period,aggregated_amount, and per-typecontracts,grants,direct_payments,idvs,loans, andother
usaspending_disaster_spending tool
dimensionisoverview,agency,cfda,recipient, orgeography;filters.def_codesis optional foroverviewand required for every other dimension (missing_def_codeswhen absent/empty). Codes such as["L", "M", "N", "O", "P"]isolate COVID-19 funding and are echoed asapplied_def_codes.limitis up to 100 on every dimension butoverview;spending_type(award, the default, ortotal) applies to agency only, and geography takesfilters.geo_layer(state,county)- Rows carry
obligation,outlay, andaward_count, plustotal_budgetary_resourceson agency rows underspending_type: total;overviewreturns totals andfunding_by_def_code. A recipient row'sidchains tousaspending_get_recipient. Recipientfilters.querynarrows by search text; it is trimmed and echoed asapplied_query, with blanks applying no query. A recipient total of 10,000 is a reachable ceiling and a lower bound on possible matches, flaggedtruncated; narrow withfilters.queryto reach the tail. Geography areas are ranked byaggregated_amountand paged withlimitandpage, with the full area count astotal; a page with areas below it is flaggedtruncated, andtruncationCeilingis the lowest amount shown. Spending with no recorded place of performance ranks as one unattributed area - Agency, cfda, and recipient also return
totalsacross every matching row:obligation,outlay, and eithertotal_budgetary_resources(agency,total) oraward_count. Overview can still time out with codes supplied: narrowfilters.def_codes, retry later, or use the agency breakdown withspending_type: totalfor obligations, outlays, and budgetary resources - Notices preserve upstream messages, ignored filters, cap guidance, and empty-page recovery on both output surfaces.
queryis ignored outside recipient,geo_layeroutside geography, andaward_type_codeson 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
keywordand 3-digitagency_identifier;sort_fieldisaccount_name,account_number,budgetary_resources(default), ormanaging_agency;limitup to 100 - Rows carry
account_number(e.g.097-8097) for the federal-account tools,managing_agency, andbudgetary_resources;page_metadata.countis the total. Optionalfiscal_yearselects the reporting year; otherwise the provider uses its latest submission year. The returnedfiscal_yearidentifies that period
usaspending_get_federal_account tool
account_codein AGENCY-MAIN format, fromaccount_numberin search results orfederal_accounton an award; an unknown code fails asaccount_not_found- Optional
fiscal_yearselects the reporting year; otherwise the provider uses the current federal fiscal year. Returnstotal_obligated_amount,total_gross_outlay_amount, andtotal_budgetary_resourcesfor the returnedfiscal_year, pluschildren: 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_codeplusdimension(program_activityorobject_class);limitup to 100, withpage_metadata.totalas the row count- Rows carry
code,name, andobligations;program_activityrows addtype, eitherPAC/PANorPARK - Optional
fiscal_yearscopes financial reporting periods to October 1 through September 30, echoed intime_periodandperiod. Omission coversall 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_categoryputs eight category sub-routes behind onecategoryenum, andusaspending_disaster_spendingputs five disaster endpoints behinddimension- 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_timeoutorapi_unavailablewith 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, andaccount_number, so agents follow the money without parsing display strings - Honest pagination:
page_metadata.has_nexton every list, atotalorcountwhere the upstream publishes one, andtruncated/shown/caponly when rows are known to exist beyond those returned. A full page with no such evidence keepshas_nextwithout 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
- Clone the repository:
git clone https://github.com/cyanheads/usaspending-mcp-server.git
- Navigate into the directory:
cd usaspending-mcp-server
- Install dependencies:
bun install
- 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.
| Variable | Description | Default |
|---|---|---|
USASPENDING_BASE_URL | USAspending.gov API v2 base URL. | https://api.usaspending.gov/api/v2/ |
USASPENDING_TIMEOUT_MS | Per-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_MS | Wall-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_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | HTTP server port. | 3010 |
MCP_SESSION_MODE | HTTP session mode: stateless, stateful, or auto. | stateless |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.). | info |
LOG_TOOL_FAILURE_PAYLOADS | Log 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_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. | false |
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT | Opt-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
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point: registers the tools and initializes the USAspending service. |
src/config | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools/definitions | Tool definitions (*.tool.ts) plus shared filter, date, pagination, and formatting helpers. |
src/services/usaspending | USAspending.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/catchin tool logic - Use
ctx.logfor request-scoped logging,ctx.statefor 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.