@cliwant/mcp-sam-gov 1.8.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +5 -5
- package/README.ko.md +5 -5
- package/README.md +8 -7
- package/dist/arcgis-feature.d.ts +68 -0
- package/dist/arcgis-feature.d.ts.map +1 -0
- package/dist/arcgis-feature.js +206 -0
- package/dist/arcgis-feature.js.map +1 -0
- package/dist/arcgis-hub.d.ts +90 -0
- package/dist/arcgis-hub.d.ts.map +1 -0
- package/dist/arcgis-hub.js +210 -0
- package/dist/arcgis-hub.js.map +1 -0
- package/dist/bonfire.d.ts +69 -0
- package/dist/bonfire.d.ts.map +1 -0
- package/dist/bonfire.js +208 -0
- package/dist/bonfire.js.map +1 -0
- package/dist/ecfr.d.ts +14 -0
- package/dist/ecfr.d.ts.map +1 -1
- package/dist/ecfr.js +127 -1
- package/dist/ecfr.js.map +1 -1
- package/dist/opengov.d.ts +96 -0
- package/dist/opengov.d.ts.map +1 -0
- package/dist/opengov.js +244 -0
- package/dist/opengov.js.map +1 -0
- package/dist/pricing.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +189 -3
- package/dist/server.js.map +1 -1
- package/dist/socrata.d.ts +27 -16
- package/dist/socrata.d.ts.map +1 -1
- package/dist/socrata.js +128 -18
- package/dist/socrata.js.map +1 -1
- package/package.json +2 -2
- package/src/arcgis-feature.ts +232 -0
- package/src/arcgis-hub.ts +270 -0
- package/src/bonfire.ts +245 -0
- package/src/ecfr.ts +154 -1
- package/src/opengov.ts +309 -0
- package/src/server.ts +203 -3
- package/src/socrata.ts +132 -18
package/dist/server.js
CHANGED
|
@@ -38,6 +38,10 @@ import * as ckan from "./ckan.js";
|
|
|
38
38
|
import * as echo from "./echo.js";
|
|
39
39
|
import * as datagov from "./datagov.js";
|
|
40
40
|
import * as datagovCatalog from "./datagov-catalog.js";
|
|
41
|
+
import * as arcgisHub from "./arcgis-hub.js";
|
|
42
|
+
import * as opengov from "./opengov.js";
|
|
43
|
+
import * as bonfire from "./bonfire.js";
|
|
44
|
+
import * as arcgisFeature from "./arcgis-feature.js";
|
|
41
45
|
import * as govinfo from "./govinfo.js";
|
|
42
46
|
import * as fpds from "./fpds.js";
|
|
43
47
|
import * as nih from "./nih.js";
|
|
@@ -86,7 +90,7 @@ import { realpathSync } from "node:fs";
|
|
|
86
90
|
const SERVER_NAME = "mcp-sam-gov";
|
|
87
91
|
// Kept in lockstep with package.json / manifest.json / server.json.
|
|
88
92
|
// Keep in sync with package.json "version" (asserted at release; see CHANGELOG).
|
|
89
|
-
const SERVER_VERSION = "1.
|
|
93
|
+
const SERVER_VERSION = "1.10.0";
|
|
90
94
|
// ─── Tool input schemas (Zod) ────────────────────────────────────
|
|
91
95
|
const SamSearchInput = z.object({
|
|
92
96
|
query: z.string().optional().describe("Free-text title query"),
|
|
@@ -456,6 +460,21 @@ const EcfrSearchInput = z.object({
|
|
|
456
460
|
perPage: z.number().min(1).max(20).optional(),
|
|
457
461
|
});
|
|
458
462
|
const EcfrListTitlesInput = z.object({});
|
|
463
|
+
const EcfrGetSectionInput = z.object({
|
|
464
|
+
titleNumber: z
|
|
465
|
+
.number()
|
|
466
|
+
.int()
|
|
467
|
+
.min(1)
|
|
468
|
+
.max(50)
|
|
469
|
+
.describe("CFR title (1–50). e.g. 2 = federal financial assistance (grants), 29 = Labor, 26 = IRS. For FAR/DFARS (title 48) prefer far_clause_lookup."),
|
|
470
|
+
section: z
|
|
471
|
+
.string()
|
|
472
|
+
.describe("The section citation, e.g. '200.1' (2 CFR 200.1) or '52.204-21' — the part number is the pre-dot integer. Charclass-validated (^[0-9]{1,3}\\.[0-9]{1,4}(-[0-9]{1,4})?$)."),
|
|
473
|
+
date: z
|
|
474
|
+
.string()
|
|
475
|
+
.optional()
|
|
476
|
+
.describe("Optional eCFR issue date YYYY-MM-DD; omit to use the title's LATEST issue (disclosed in _meta)."),
|
|
477
|
+
});
|
|
459
478
|
// FAR / DFARS clause lookup (eCFR versioner full endpoint)
|
|
460
479
|
const FarClauseLookupInput = z.object({
|
|
461
480
|
clauseNumber: z
|
|
@@ -2493,6 +2512,107 @@ const DatagovSearchDatasetsInput = z.object({
|
|
|
2493
2512
|
.optional()
|
|
2494
2513
|
.describe("Opaque continuation cursor (→ after) — pass back the _meta.nextCursor from the previous page. Pagination is a cursor, NOT a numeric offset (offset/nextOffset are null); nextCursor:null means the last page. A bad token (spaces/'../'/'%') ⇒ invalid_input pre-fetch."),
|
|
2495
2514
|
});
|
|
2515
|
+
// ─── ArcGIS Hub (hub.arcgis.com — keyless SLED dataset discovery) ─
|
|
2516
|
+
// Loop cycle 9. A GLOBAL, OPEN publishing platform (non-US / non-gov publishers
|
|
2517
|
+
// included) — DISCOVERY ONLY, provenance surfaced per-row + disclosed every
|
|
2518
|
+
// response. Fixed-host SSRF (no per-jurisdiction host vector). q ≥ 2 chars.
|
|
2519
|
+
const ArcgisHubDiscoverInput = z.object({
|
|
2520
|
+
query: z
|
|
2521
|
+
.string()
|
|
2522
|
+
.min(2)
|
|
2523
|
+
.max(500)
|
|
2524
|
+
.describe("Keyword search over ArcGIS Hub datasets (→ q), e.g. 'procurement contract', 'zoning permits'. REQUIRED, ≥2 non-whitespace chars (a broad scan of the whole global Hub is refused)."),
|
|
2525
|
+
openDataOnly: z
|
|
2526
|
+
.boolean()
|
|
2527
|
+
.default(true)
|
|
2528
|
+
.describe("When true (default), filter to items the publisher designated as open data (→ filter[openData]=true) — the B2G-relevant subset. Set false to broaden to ALL shared items (vet the publisher even more)."),
|
|
2529
|
+
limit: z
|
|
2530
|
+
.number()
|
|
2531
|
+
.int()
|
|
2532
|
+
.min(1)
|
|
2533
|
+
.max(100)
|
|
2534
|
+
.default(20)
|
|
2535
|
+
.describe("Datasets per page (→ page[size]), 1..100, default 20."),
|
|
2536
|
+
offset: z
|
|
2537
|
+
.number()
|
|
2538
|
+
.int()
|
|
2539
|
+
.min(0)
|
|
2540
|
+
.default(0)
|
|
2541
|
+
.describe("0-based record offset (→ page[start]=offset+1). Page with _meta.pagination.nextOffset; totalAvailable is the exact Hub match count."),
|
|
2542
|
+
});
|
|
2543
|
+
// ─── OpenGov Procurement (api.procurement.opengov.com — keyless SLED bids) ─
|
|
2544
|
+
// SLED bid campaign. 525+ US state/local portals' live solicitations via the
|
|
2545
|
+
// public portal's own anonymous backend API (the key-gated api-key API is NOT
|
|
2546
|
+
// used). Fixed-host SSRF. governmentCode = the portal slug from list_governments.
|
|
2547
|
+
const OpengovListGovernmentsInput = z.object({
|
|
2548
|
+
state: z
|
|
2549
|
+
.string()
|
|
2550
|
+
.length(2)
|
|
2551
|
+
.optional()
|
|
2552
|
+
.describe("2-letter US state filter (client-side), e.g. 'CA', 'FL'. Optional."),
|
|
2553
|
+
query: z
|
|
2554
|
+
.string()
|
|
2555
|
+
.min(1)
|
|
2556
|
+
.max(120)
|
|
2557
|
+
.optional()
|
|
2558
|
+
.describe("Case-insensitive name substring filter (client-side), e.g. 'county', 'school'. Optional."),
|
|
2559
|
+
limit: z.number().int().min(1).max(200).default(50).describe("Portals per page, 1..200, default 50."),
|
|
2560
|
+
offset: z.number().int().min(0).default(0).describe("0-based offset; page with _meta.pagination.nextOffset. totalAvailable = exact filtered portal count."),
|
|
2561
|
+
});
|
|
2562
|
+
const OpengovSearchSolicitationsInput = z.object({
|
|
2563
|
+
governmentCode: z
|
|
2564
|
+
.string()
|
|
2565
|
+
.min(1)
|
|
2566
|
+
.max(64)
|
|
2567
|
+
.regex(opengov.OPENGOV_CODE_RE)
|
|
2568
|
+
.describe("The OpenGov portal slug (from opengov_list_governments `code`), e.g. 'santacruzca', 'orlando', 'u-46'. REQUIRED. Lowercase alnum/hyphen; a bad slug ⇒ invalid_input pre-fetch."),
|
|
2569
|
+
limit: z.number().int().min(1).max(100).default(50).describe("Solicitations per page, 1..100, default 50 (→ API page size)."),
|
|
2570
|
+
offset: z.number().int().min(0).default(0).describe("0-based offset (snapped to the API's fixed page boundary). Page with _meta.pagination.nextOffset."),
|
|
2571
|
+
});
|
|
2572
|
+
// ─── Bonfire (Euna) — keyless per-org open-opportunity RSS (SLED bids) ─
|
|
2573
|
+
// SLED bid campaign. Thousands of US state/local govs on Bonfire expose a keyless
|
|
2574
|
+
// RSS of open opportunities at {org}.bonfirehub.com/opportunities/rss. Ships a
|
|
2575
|
+
// curated 187-org seed directory. Fixed-suffix SSRF. org = charclass slug.
|
|
2576
|
+
const BonfireListOrganizationsInput = z.object({
|
|
2577
|
+
state: z.string().length(2).optional().describe("2-letter US state filter (client-side), e.g. 'TX', 'CA'. Optional."),
|
|
2578
|
+
query: z.string().min(1).max(120).optional().describe("Case-insensitive name substring filter (client-side), e.g. 'county', 'ISD'. Optional."),
|
|
2579
|
+
limit: z.number().int().min(1).max(200).default(50).describe("Orgs per page, 1..200, default 50."),
|
|
2580
|
+
offset: z.number().int().min(0).default(0).describe("0-based offset; page with _meta.pagination.nextOffset."),
|
|
2581
|
+
});
|
|
2582
|
+
const BonfireSearchOpportunitiesInput = z.object({
|
|
2583
|
+
org: z
|
|
2584
|
+
.string()
|
|
2585
|
+
.min(1)
|
|
2586
|
+
.max(64)
|
|
2587
|
+
.regex(bonfire.BONFIRE_ORG_RE)
|
|
2588
|
+
.describe("The Bonfire org subdomain slug (from bonfire_list_organizations `org`), e.g. 'harriscountytx', 'broward', 'u-46'. REQUIRED. Lowercase alnum/hyphen; a bad slug ⇒ invalid_input pre-fetch."),
|
|
2589
|
+
limit: z.number().int().min(1).max(200).default(50).describe("Opportunities per page, 1..200, default 50. The RSS is the complete open set; this pages over it."),
|
|
2590
|
+
offset: z.number().int().min(0).default(0).describe("0-based offset; page with _meta.pagination.nextOffset. totalAvailable = the exact open-opportunity count."),
|
|
2591
|
+
});
|
|
2592
|
+
// ─── ArcGIS REST feature query (curated service allowlist — SLED bids/GIS) ─
|
|
2593
|
+
// Generic ArcGIS FeatureServer/MapServer layer query over a curated allowlist.
|
|
2594
|
+
// First payload: DC OCP PASS procurement layers (live solicitations/contracts/PO/
|
|
2595
|
+
// payments). `service` is an enum (SSRF core); where/outFields filter the layer.
|
|
2596
|
+
const ArcgisFeatureQueryInput = z.object({
|
|
2597
|
+
service: z
|
|
2598
|
+
.enum(arcgisFeature.ARCGIS_SERVICES.map((s) => s.key))
|
|
2599
|
+
.describe("The curated ArcGIS layer (SSRF allowlist enum). DC OCP PASS: 'dc_pass_solicitations' (live solicitations ~25k), 'dc_pass_contracts', 'dc_pass_purchase_orders', 'dc_pass_payments'. Other US local govs: 'asheville_purchase_orders'/'asheville_po_summary' (Asheville NC), 'bellevue_vendor_payments'/'bellevue_awarded_contracts' (Bellevue WA), 'miamidade_purchase_orders_2025'/'miamidade_purchase_orders_2017' (Miami-Dade FL, current/2017), 'suffolk_county_ny_contracts_2018' (Suffolk County NY), 'matsu_borough_ak_checkbook' (Matanuska-Susitna Borough AK), 'lasvegas_checkbook' (Las Vegas NV ~373k), 'baltimore_checkbook' (Baltimore City MD ~367k), 'naperville_vendor_payments' (Naperville IL ~127k), 'worcester_ma_checkbook_fy25' (Worcester MA FY25), 'lasvegas_purchasing_contracts' (Las Vegas NV contract register), 'txdot_construction_projects' (Texas DOT, awarded construction company ~85k), 'akdot_construction_awards'/'akdot_aashtoware_proposals' (Alaska DOT&PF bid awards/proposals), 'iowadot_public_bid_awards' (Iowa DOT public bid), 'okdot_cirb_contract_status' (Oklahoma DOT CIRB contract status), 'topeka_checkbook_aggregate' (Topeka KS checkbook FY2015–2023 ~332k). 23 curated services (state DOT bid/award registers: TX/AK/IA/OK + municipal checkbooks/contracts)."),
|
|
2600
|
+
where: z
|
|
2601
|
+
.string()
|
|
2602
|
+
.min(1)
|
|
2603
|
+
.max(500)
|
|
2604
|
+
.optional()
|
|
2605
|
+
.describe("ArcGIS SQL-ish filter (default '1=1'), e.g. \"SOLICITATIONTITLE LIKE '%security%'\" or \"DUE_DATE > 1750000000000\". Filters the read-only layer; a malformed clause ⇒ invalid_input (surfaced)."),
|
|
2606
|
+
outFields: z
|
|
2607
|
+
.string()
|
|
2608
|
+
.min(1)
|
|
2609
|
+
.max(500)
|
|
2610
|
+
.optional()
|
|
2611
|
+
.describe("Comma-separated fields to return (default '*' = all). e.g. 'SOLICITATIONNUMBER,SOLICITATIONTITLE,DUE_DATE,NIGPCODE'."),
|
|
2612
|
+
orderByFields: z.string().min(1).max(200).optional().describe("ArcGIS orderByFields, e.g. 'DUE_DATE DESC'. Optional."),
|
|
2613
|
+
limit: z.number().int().min(1).max(1000).default(50).describe("Records per page (→ resultRecordCount), 1..1000, default 50."),
|
|
2614
|
+
offset: z.number().int().min(0).default(0).describe("0-based offset (→ resultOffset). Page with _meta.pagination.nextOffset; totalAvailable = the layer's exact match count."),
|
|
2615
|
+
});
|
|
2496
2616
|
// ─── GovInfo (api.govinfo.gov — the api.data.gov keyed trio's 3rd API) ─
|
|
2497
2617
|
// ADR-0010. Same DATA_GOV_API_KEY/DEMO_KEY/X-Api-Key discipline as the datagov
|
|
2498
2618
|
// trio (shared datagovKey.ts seam). `collection` is grammar-checked here AND
|
|
@@ -4507,13 +4627,19 @@ export const TOOLS = [
|
|
|
4507
4627
|
inputSchema: FedRegPublicInspectionInput,
|
|
4508
4628
|
handler: (input) => fedreg.publicInspection(input),
|
|
4509
4629
|
}),
|
|
4510
|
-
// ━━━ eCFR (
|
|
4630
|
+
// ━━━ eCFR (6) ━━━
|
|
4511
4631
|
defineTool({
|
|
4512
4632
|
name: "ecfr_search",
|
|
4513
|
-
description: "Full-text search across the entire CFR (Code of Federal Regulations). Use for
|
|
4633
|
+
description: "Full-text search across the entire CFR (Code of Federal Regulations). Use for DISCOVERY — pass titleNumber=48 for FAR (Federal Acquisition Regulation), titleNumber=2 for federal financial assistance, etc. Returns a ranked EXCERPT (snippet, not full text) + section path + ecfrUrl per hit. To then read the COMPLETE text of a hit: for a FAR/DFARS clause (title 48) use far_clause_lookup (adds prescription + revision); for any other title's section use ecfr_get_section; or open the ecfrUrl.",
|
|
4514
4634
|
inputSchema: EcfrSearchInput,
|
|
4515
4635
|
handler: (input) => ecfr.search(input),
|
|
4516
4636
|
}),
|
|
4637
|
+
defineTool({
|
|
4638
|
+
name: "ecfr_get_section",
|
|
4639
|
+
description: "Get the FULL in-force text of ONE CFR section by citation (the companion to ecfr_search, which returns only snippets). Input titleNumber (1–50) + section (e.g. '200.1' → 2 CFR 200.1, uniform grants guidance; '1601.1' → 29 CFR labor) + optional issue date (default = the title's latest). Returns { citation, alternateReference, heading, fullText, issueDate, ecfrUrl }. ★For a FAR/DFARS clause (title 48) prefer far_clause_lookup — it adds the prescription, revision, and FAR-overhaul-risk this generic tool does not; use ecfr_get_section for the OTHER 49 titles (grants/labor/IRS/SBA/…). HONESTY: text is the eCFR's own, de-XMLed (no fabrication); a nonexistent section ⇒ not_found (never a fake/wrong section); the resolved issue date is disclosed (the title's latest is a moving target); a bad section format ⇒ invalid_input (SSRF charclass); an outage ⇒ throws. Keyless.",
|
|
4640
|
+
inputSchema: EcfrGetSectionInput,
|
|
4641
|
+
handler: (input) => ecfr.getSection(input),
|
|
4642
|
+
}),
|
|
4517
4643
|
defineTool({
|
|
4518
4644
|
name: "ecfr_list_titles",
|
|
4519
4645
|
description: "List all 50 CFR titles with name + last_amended_on date. Use to discover what's in each title (Title 48 = FAR, Title 32 = National Defense, Title 14 = Aeronautics, etc.).",
|
|
@@ -5057,6 +5183,66 @@ export const TOOLS = [
|
|
|
5057
5183
|
inputSchema: DatagovSearchDatasetsInput,
|
|
5058
5184
|
handler: (input) => datagovCatalog.searchDatasets(input),
|
|
5059
5185
|
}),
|
|
5186
|
+
// ━━━ ArcGIS Hub (hub.arcgis.com) — keyless SLED dataset DISCOVERY (loop cycle 9) ━━━
|
|
5187
|
+
// A NEW discovery platform: much US state/local/regional/tribal (SLED) open data
|
|
5188
|
+
// — GIS/infrastructure/permits/boundaries/procurement — lives on ArcGIS Hub, NOT
|
|
5189
|
+
// Socrata/CKAN. Fixed-host SSRF (no per-jurisdiction host vector). ★PROVENANCE: the
|
|
5190
|
+
// Hub is GLOBAL + OPEN (non-US/non-gov publishers), so this is a DISCOVERY aid, not
|
|
5191
|
+
// a curated official-source allowlist — per-row owner/orgName/source/region are
|
|
5192
|
+
// surfaced for vetting + the disclosure rides every response. P1: totalAvailable =
|
|
5193
|
+
// meta.total (exact Hub count). DISCOVERY ONLY (row-query on arbitrary ArcGIS hosts
|
|
5194
|
+
// is a planned, separately-guarded addition).
|
|
5195
|
+
defineTool({
|
|
5196
|
+
name: "arcgis_hub_discover_datasets",
|
|
5197
|
+
description: "Discover ArcGIS Hub datasets by keyword — the SLED/GIS open-data layer that Socrata and CKAN do NOT cover (keyless; hub.arcgis.com/api/v3/datasets). Much US state/local/regional/tribal open data (GIS, infrastructure, permits, zoning, boundaries, procurement) is published on ArcGIS Hub. Input `query` (→q, REQUIRED, ≥2 non-whitespace chars — a broad whole-Hub scan is refused), `openDataOnly` (default TRUE → filter[openData]=true, the B2G-relevant designated-open-data subset; false broadens to all shared items), `limit` (1..100, def 20 → page[size]), `offset` (0-based → page[start]=offset+1). Returns { query, openDataOnly, datasets:[{ id, name, description, owner, orgName, source, region, type, sector, keywords, downloadable, hasApi, created, modified, landingPage, itemId }] } + honest _meta. ★PROVENANCE (the crux — a DIFFERENT trust posture from our other sources): ArcGIS Hub is a GLOBAL, OPEN publishing platform — results include NON-US and NON-GOVERNMENTAL publishers. This is a DISCOVERY aid, NOT a curated official-source allowlist (unlike socrata_query): the per-row owner/orgName/source/region are surfaced VERBATIM so you can VET the publisher before relying on the data, and the global-platform caveat rides EVERY response. DISCOVERY ONLY — metadata + links; to read rows follow the dataset on its own ArcGIS endpoint (a guarded row-query tool is a planned addition). HONESTY: totalAvailable = the EXACT Hub match count (meta.total, NEVER data.length — P1); pagination is a 0-based offset (nextOffset when more remain); every scalar null-never-empty, booleans null-preserving, counts null-never-0; a genuine no-match ⇒ complete:true/returned:0; a 429 ⇒ rate_limited / 5xx/timeout ⇒ upstream_unavailable THROWS (never a fake empty); a 200 non-JSON / non-array data ⇒ schema_drift.",
|
|
5198
|
+
inputSchema: ArcgisHubDiscoverInput,
|
|
5199
|
+
handler: (input) => arcgisHub.discoverDatasets(input),
|
|
5200
|
+
}),
|
|
5201
|
+
// ━━━ OpenGov Procurement (api.procurement.opengov.com) — keyless SLED bids ━━━
|
|
5202
|
+
// SLED bid campaign (from the exhaustive US state+local bid-site research). 525+
|
|
5203
|
+
// state/local government portals' LIVE solicitations, via the public portal's OWN
|
|
5204
|
+
// anonymous backend REST API — the key-gated official api-key API is NOT touched
|
|
5205
|
+
// (genuinely keyless, live-verified). Fixed-host SSRF. Two tools: a directory
|
|
5206
|
+
// (one keyless GET returns all ~560 orgs) + per-org solicitations.
|
|
5207
|
+
defineTool({
|
|
5208
|
+
name: "opengov_list_governments",
|
|
5209
|
+
description: "List the government portals on OpenGov Procurement (formerly ProcureNow) — the directory for opengov_search_solicitations (keyless; api.procurement.opengov.com). OpenGov Procurement hosts the live open-solicitation portals of 525+ US state/local governments (cities, counties, school & special districts across 42 states + DC). The WHOLE directory arrives in ONE keyless GET and is filtered client-side: `state` (2-letter), `query` (case-insensitive name substring); `limit`(1..200)/`offset`. Only ACTIVE, non-internal portals are returned. Output: { governments:[{ code, name, city, state, website }] } + honest _meta. Feed a result's `code` to opengov_search_solicitations. HONESTY: this consumes ONLY the anonymous endpoints the public portal itself calls (the official key-gated api-key API is NOT used) — genuinely keyless; totalAvailable is the EXACT filtered portal count (never the page length); a 429/5xx/timeout THROWS (never a fake empty); a non-array body ⇒ schema_drift.",
|
|
5210
|
+
inputSchema: OpengovListGovernmentsInput,
|
|
5211
|
+
handler: (input) => opengov.listGovernments(input),
|
|
5212
|
+
}),
|
|
5213
|
+
defineTool({
|
|
5214
|
+
name: "opengov_search_solicitations",
|
|
5215
|
+
description: "List a government's public solicitations on OpenGov Procurement (keyless; api.procurement.opengov.com, POST /project/list with the required publicView gate). Input `governmentCode` (the portal slug from opengov_list_governments, e.g. 'santacruzca', 'orlando', 'u-46'; REQUIRED), `limit`(1..100)/`offset`. Returns { governmentCode, solicitations:[{ id, title, solicitationNumber, status, type, department, releaseDate, proposalDeadline, contactName, link }] } + honest _meta. ★STATUS: `status` is surfaced VERBATIM — **open = currently ACCEPTING responses**; pending/evaluation/closed are ALSO returned (publicView shows all public projects), so filter status==='open' for live bids. `link` is the public portal page. HONESTY: totalAvailable = the API's `count` = the org's TOTAL public-project count (all statuses), NEVER the page length and NOT an open-only count (a note discloses this); pagination is the API's fixed page (offset is snapped to the page boundary, disclosed); a genuine no-match ⇒ complete:true/returned:0; a 429/5xx/timeout THROWS (never a fake empty); a non-array `projects` ⇒ schema_drift; a bad `governmentCode` ⇒ invalid_input pre-fetch. Genuinely keyless (the key-gated official API is NOT used).",
|
|
5216
|
+
inputSchema: OpengovSearchSolicitationsInput,
|
|
5217
|
+
handler: (input) => opengov.searchSolicitations(input),
|
|
5218
|
+
}),
|
|
5219
|
+
// ━━━ Bonfire (Euna) — keyless per-org open-opportunity RSS (SLED bids) ━━━
|
|
5220
|
+
// SLED bid campaign. Thousands of US state/local govs on Bonfire expose a keyless
|
|
5221
|
+
// RSS of open opportunities. Ships a curated 187-org live-verified seed directory
|
|
5222
|
+
// (Bonfire's authoritative org API is auth-gated → out of bounds). Fixed-suffix
|
|
5223
|
+
// SSRF (.bonfirehub.com). RSS = the complete open set (totalAvailable honest).
|
|
5224
|
+
defineTool({
|
|
5225
|
+
name: "bonfire_list_organizations",
|
|
5226
|
+
description: "List US governments on the Bonfire (Euna) eProcurement platform — the directory for bonfire_search_opportunities (keyless). Bonfire hosts thousands of US state/local governments' open-bid portals, each with a keyless RSS feed. Filter the curated seed by `state` (2-letter) / `query` (case-insensitive name substring); `limit`(1..200)/`offset`. Output: { organizations:[{ org, name, state }] }. Feed a result's `org` to bonfire_search_opportunities. ★HONESTY: this is a CURATED, live-verified SEED of 187 US orgs — Bonfire has NO keyless org-list API (its authoritative directory is auth-gated, out of bounds), and Euna markets up to ~900 US orgs, so the seed is PARTIAL (disclosed in _meta); probe `{slug}.bonfirehub.com/opportunities/rss` to extend. totalAvailable = the exact filtered seed count.",
|
|
5227
|
+
inputSchema: BonfireListOrganizationsInput,
|
|
5228
|
+
handler: (input) => bonfire.listOrganizations(input),
|
|
5229
|
+
}),
|
|
5230
|
+
defineTool({
|
|
5231
|
+
name: "bonfire_search_opportunities",
|
|
5232
|
+
description: "List a government's currently-OPEN solicitations on Bonfire (keyless; {org}.bonfirehub.com/opportunities/rss, RSS 2.0). Input `org` (the subdomain slug from bonfire_list_organizations, e.g. 'harriscountytx', 'broward', 'u-46'; REQUIRED), `limit`(1..200)/`offset`. Returns { org, opportunities:[{ referenceNumber, name, description, closeDate, link, pubDate }] } + honest _meta. HONESTY: the RSS is the COMPLETE set of the org's currently-open opportunities (no server pagination), so totalAvailable = the exact open-opportunity count (never a page length) and this tool pages over it client-side; an empty feed (returned 0) means no open opportunities right now (honest empty, complete:true); `closeDate` is parsed best-effort from the description; a 429/5xx/404/timeout THROWS (never a fake empty); a 200 non-RSS body ⇒ schema_drift; a bad `org` ⇒ invalid_input pre-fetch. Fixed-suffix SSRF (.bonfirehub.com) + redirect:error. Keyless (Bonfire's auth-gated directory API is NOT used).",
|
|
5233
|
+
inputSchema: BonfireSearchOpportunitiesInput,
|
|
5234
|
+
handler: (input) => bonfire.searchOpportunities(input),
|
|
5235
|
+
}),
|
|
5236
|
+
// ━━━ ArcGIS REST feature query (curated allowlist) — SLED bids/GIS ━━━
|
|
5237
|
+
// Generic query companion to arcgis_hub_discover_datasets. First payload: the DC
|
|
5238
|
+
// OCP PASS procurement layers (live solicitations + contracts/PO/payments), a
|
|
5239
|
+
// keyless live-solicitation feed via ArcGIS REST. `service` enum = SSRF core.
|
|
5240
|
+
defineTool({
|
|
5241
|
+
name: "arcgis_feature_query",
|
|
5242
|
+
description: "Query rows from a curated US-government ArcGIS REST feature layer (keyless) — the QUERY companion to arcgis_hub_discover_datasets (which discovers Hub datasets). A large amount of SLED procurement/GIS data lives on ArcGIS. First payload: the **DC Office of Contracting & Procurement 'PASS'** layers — `dc_pass_solicitations` (DC's LIVE open solicitations, ~25k: SOLICITATIONNUMBER, SOLICITATIONTITLE, DUE_DATE, OPENDATE, CLOSEDATE, NIGPCODE, CONTRACTINGOFFICER, AWARD_TO, 46 fields), `dc_pass_contracts` (~50k), `dc_pass_purchase_orders` (~275k), `dc_pass_payments` (~1.55M). Inputs: `service` (the allowlist ENUM — the SSRF core, never a free host), `where` (ArcGIS SQL-ish filter, default '1=1', e.g. \"SOLICITATIONTITLE LIKE '%security%'\"), `outFields` (default '*'), `orderByFields`, `limit`(1..1000)/`offset`. Returns { service, records:[{…attributes verbatim…}] } + honest _meta. HONESTY: totalAvailable = the layer's EXACT match count (a returnCountOnly companion query, never the page length; a count failure ⇒ null + note, rows still returned); ★ArcGIS date fields are epoch MILLISECONDS and a negative/sentinel (≈1900) is a placeholder — surfaced verbatim, never coerced; a genuine no-match ⇒ complete:true/returned:0; a 429/5xx/timeout THROWS; an ArcGIS {error} body (e.g. a bad where) ⇒ invalid_input/upstream (surfaced, never a fake empty); a non-array features ⇒ schema_drift. SSRF: fixed allowlist base + hostname assertion + redirect:error (where/outFields cannot alter the host).",
|
|
5243
|
+
inputSchema: ArcgisFeatureQueryInput,
|
|
5244
|
+
handler: (input) => arcgisFeature.featureQuery(input),
|
|
5245
|
+
}),
|
|
5060
5246
|
// ━━━ GovInfo (api.govinfo.gov) — the api.data.gov keyed trio's 3rd API (3) ━━━ ADR-0010
|
|
5061
5247
|
// GPO-authoritative bulk publications (BILLS/PLAW/USCODE/CREC/CFR-FR editions/
|
|
5062
5248
|
// BUDGET/GAOREPORTS) with PDF/XML/MODS downloads + provenance. 2nd consumer of the
|