gov-data-mcp 1.1.3 → 1.2.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.md +92 -8
- package/package.json +2 -2
- package/src/catalog.json +308 -49
- package/src/index.js +30 -4
- package/src/presets.js +162 -0
- package/src/tools.js +51 -9
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# gov-data-mcp
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**122 US government open-data tools, as one MCP server.**
|
|
4
4
|
|
|
5
5
|
EPA, FEMA, USGS, NOAA, FAA, USACE, FDIC, HUD, NRCS, HRSA, CMS, county assessor rolls and state licensing boards — all reachable as agent-callable tools, all reading directly from official government APIs and bulk files. No scraping, no HTML parsing, no rate-limit roulette.
|
|
6
6
|
|
|
@@ -49,13 +49,97 @@ Claude Desktop reads `claude_desktop_config.json`; Claude Code reads `.mcp.json`
|
|
|
49
49
|
| `parcel-owner-lookup` | Assessor-roll owner of record for an address |
|
|
50
50
|
| `license-verifier` | 19 professional licensing boards across 9 states + OIG exclusions |
|
|
51
51
|
|
|
52
|
-
**Plus three tools that reach the other
|
|
52
|
+
**Plus three tools that reach the other 110:**
|
|
53
53
|
|
|
54
54
|
- `search-gov-data-tools` — find a tool by keyword, agency or topic
|
|
55
55
|
- `describe-gov-data-tool` — full input schema for any tool in the catalog
|
|
56
56
|
- `run-gov-data-tool` — run any tool in the catalog
|
|
57
57
|
|
|
58
|
-
The catalog is bundled, so discovery costs nothing. Ask your agent *"what government data tools do you have for flood risk?"* and it will search all
|
|
58
|
+
The catalog is bundled, so discovery costs nothing. Ask your agent *"what government data tools do you have for flood risk?"* and it will search all 122.
|
|
59
|
+
|
|
60
|
+
<!-- PRESETS:START -->
|
|
61
|
+
## Vertical presets
|
|
62
|
+
|
|
63
|
+
The full server is the right default for a general-purpose agent. For an agent that serves one kind of buyer, a **preset** narrows the whole surface — the named tools *and* what `search-gov-data-tools` / `describe-gov-data-tool` / `run-gov-data-tool` can reach — to one shelf, and announces itself to the client under its own server name and description. Same package, same catalog, same release; nothing to install separately. Pass `--preset <name>` or set `GOV_DATA_MCP_PRESET`. An unknown preset name refuses to start rather than guessing. `npx gov-data-mcp --list-presets` prints the current list as JSON.
|
|
64
|
+
|
|
65
|
+
| Preset | Server name | Tools | For |
|
|
66
|
+
|---|---|---|---|
|
|
67
|
+
| `phase1-esa` | `gov-data-mcp-phase1-esa` | 11 + 3 meta | Phase I ESA — Environmental Due Diligence |
|
|
68
|
+
| `cre-leads` | `gov-data-mcp-cre-leads` | 12 + 3 meta | CRE & Local Business Leads — Who Just Changed State |
|
|
69
|
+
| `compliance` | `gov-data-mcp-compliance` | 12 + 3 meta | KYB, Sanctions & Financial Compliance Screening |
|
|
70
|
+
|
|
71
|
+
### `phase1-esa` — Phase I ESA — Environmental Due Diligence
|
|
72
|
+
|
|
73
|
+
US government environmental records for Phase I Environmental Site Assessments and property due diligence: EPA Superfund / RCRA / UST / brownfield records at ASTM E1527-21 search distances, state tank and spill registries, historic land use from FRS SIC/NAICS, USGS historical topographic map coverage, NWI wetlands, Clean Water Act §404 surface water, RCRA corrective-action cleanups, orphaned wells, FEMA hazard risk and NFIP flood-loss history, plus a twenty-layer go / caution / no-go site verdict. Every tool reads the official source directly and reports what it could not check as null, never as clear.
|
|
74
|
+
|
|
75
|
+
**11 tools:** [site-due-diligence-bundle](https://apify.com/malonestar/site-due-diligence-bundle) · [epa-contaminated-site-screener](https://apify.com/malonestar/epa-contaminated-site-screener) · [historic-land-use-sic-contaminant-screener](https://apify.com/malonestar/historic-land-use-sic-contaminant-screener) · [state-tank-spill-registry-screener](https://apify.com/malonestar/state-tank-spill-registry-screener) · [usgs-historical-topo-records-review](https://apify.com/malonestar/usgs-historical-topo-records-review) · [epa-rcra-corrective-action-cleanup-monitor](https://apify.com/malonestar/epa-rcra-corrective-action-cleanup-monitor) · [orphaned-well-proximity-screener](https://apify.com/malonestar/orphaned-well-proximity-screener) · [fws-wetlands-proximity-screener](https://apify.com/malonestar/fws-wetlands-proximity-screener) · [nhd-surface-water-404-screener](https://apify.com/malonestar/nhd-surface-water-404-screener) · [fema-nri-county-risk-profile](https://apify.com/malonestar/fema-nri-county-risk-profile) · [nfip-flood-loss-risk-screener](https://apify.com/malonestar/nfip-flood-loss-risk-screener) — plus `search-gov-data-tools`, `describe-gov-data-tool`, `run-gov-data-tool`, scoped to this list.
|
|
76
|
+
|
|
77
|
+
Claude Desktop (`claude_desktop_config.json`), Claude Code (`.mcp.json`) and Cursor (`.cursor/mcp.json`) all take the same block:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"mcpServers": {
|
|
82
|
+
"gov-data-phase1-esa": {
|
|
83
|
+
"command": "npx",
|
|
84
|
+
"args": ["-y", "gov-data-mcp", "--preset", "phase1-esa"],
|
|
85
|
+
"env": { "APIFY_TOKEN": "apify_api_..." }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Or, with the environment variable instead of the flag: `"args": ["-y", "gov-data-mcp"]` and `"env": { "APIFY_TOKEN": "apify_api_...", "GOV_DATA_MCP_PRESET": "phase1-esa" }`.
|
|
92
|
+
|
|
93
|
+
Command line: `npx gov-data-mcp --preset phase1-esa`
|
|
94
|
+
|
|
95
|
+
### `cre-leads` — CRE & Local Business Leads — Who Just Changed State
|
|
96
|
+
|
|
97
|
+
Lead-generation feeds built from official state and county registers: new and pending liquor licenses, verified new business openings from Secretary of State and tax rosters, WARN layoff notices, newly licensed real estate agents, licensed childcare providers with contacts, parcel owner of record, absentee-owner lists, distressed-property signal stacks, NYC deed transfers and landlord registries, city business licenses and professional license verification. Delta modes return only what changed since the last run, so a scheduled agent pays for new leads, not the same roster twice.
|
|
98
|
+
|
|
99
|
+
**12 tools:** [liquor-license-new-openings-tracker](https://apify.com/malonestar/liquor-license-new-openings-tracker) · [sos-registry-monitor](https://apify.com/malonestar/sos-registry-monitor) · [warn-layoff-aggregator](https://apify.com/malonestar/warn-layoff-aggregator) · [realtor-license-roster-delta](https://apify.com/malonestar/realtor-license-roster-delta) · [childcare-provider-leads](https://apify.com/malonestar/childcare-provider-leads) · [parcel-owner-lookup](https://apify.com/malonestar/parcel-owner-lookup) · [absentee-owner-lead-list-builder](https://apify.com/malonestar/absentee-owner-lead-list-builder) · [distressed-property-signal-stacker](https://apify.com/malonestar/distressed-property-signal-stacker) · [acris-deed-transfer-intel](https://apify.com/malonestar/acris-deed-transfer-intel) · [nyc-landlord-registry-lead-list](https://apify.com/malonestar/nyc-landlord-registry-lead-list) · [city-business-license-leads](https://apify.com/malonestar/city-business-license-leads) · [license-verifier](https://apify.com/malonestar/license-verifier) — plus `search-gov-data-tools`, `describe-gov-data-tool`, `run-gov-data-tool`, scoped to this list.
|
|
100
|
+
|
|
101
|
+
Claude Desktop (`claude_desktop_config.json`), Claude Code (`.mcp.json`) and Cursor (`.cursor/mcp.json`) all take the same block:
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"mcpServers": {
|
|
106
|
+
"gov-data-cre-leads": {
|
|
107
|
+
"command": "npx",
|
|
108
|
+
"args": ["-y", "gov-data-mcp", "--preset", "cre-leads"],
|
|
109
|
+
"env": { "APIFY_TOKEN": "apify_api_..." }
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Or, with the environment variable instead of the flag: `"args": ["-y", "gov-data-mcp"]` and `"env": { "APIFY_TOKEN": "apify_api_...", "GOV_DATA_MCP_PRESET": "cre-leads" }`.
|
|
116
|
+
|
|
117
|
+
Command line: `npx gov-data-mcp --preset cre-leads`
|
|
118
|
+
|
|
119
|
+
### `compliance` — KYB, Sanctions & Financial Compliance Screening
|
|
120
|
+
|
|
121
|
+
Know-your-business and compliance screening from primary US government registers: company existence across Secretary of State registries, the Trade.gov Consolidated Screening List (OFAC SDN, BIS, State) as a delta, the DHS UFLPA Entity List, state Medicaid and HHS-OIG exclusion lists, professional license verification, GLEIF LEI ownership graphs, FDIC / NCUA institution health, FDIC structure changes, SEC investment-adviser registrations, PCAOB auditor engagements and SEC Regulation CF / A+ offering lifecycles. A screen that could not reach its source fails loudly rather than returning a clean sheet.
|
|
122
|
+
|
|
123
|
+
**12 tools:** [kyb-company-verifier](https://apify.com/malonestar/kyb-company-verifier) · [consolidated-screening-list-delta](https://apify.com/malonestar/consolidated-screening-list-delta) · [uflpa-entity-list-monitor](https://apify.com/malonestar/uflpa-entity-list-monitor) · [medicaid-exclusion-screener](https://apify.com/malonestar/medicaid-exclusion-screener) · [license-verifier](https://apify.com/malonestar/license-verifier) · [gleif-ownership-graph](https://apify.com/malonestar/gleif-ownership-graph) · [fdic-ncua-health-rollup](https://apify.com/malonestar/fdic-ncua-health-rollup) · [fdic-structure-change-delta-monitor](https://apify.com/malonestar/fdic-structure-change-delta-monitor) · [ria-registration-delta-monitor](https://apify.com/malonestar/ria-registration-delta-monitor) · [pcaob-auditor-engagement-monitor](https://apify.com/malonestar/pcaob-auditor-engagement-monitor) · [reg-cf-lifecycle-monitor](https://apify.com/malonestar/reg-cf-lifecycle-monitor) · [reg-a-plus-lifecycle-monitor](https://apify.com/malonestar/reg-a-plus-lifecycle-monitor) — plus `search-gov-data-tools`, `describe-gov-data-tool`, `run-gov-data-tool`, scoped to this list.
|
|
124
|
+
|
|
125
|
+
Claude Desktop (`claude_desktop_config.json`), Claude Code (`.mcp.json`) and Cursor (`.cursor/mcp.json`) all take the same block:
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"mcpServers": {
|
|
130
|
+
"gov-data-compliance": {
|
|
131
|
+
"command": "npx",
|
|
132
|
+
"args": ["-y", "gov-data-mcp", "--preset", "compliance"],
|
|
133
|
+
"env": { "APIFY_TOKEN": "apify_api_..." }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Or, with the environment variable instead of the flag: `"args": ["-y", "gov-data-mcp"]` and `"env": { "APIFY_TOKEN": "apify_api_...", "GOV_DATA_MCP_PRESET": "compliance" }`.
|
|
140
|
+
|
|
141
|
+
Command line: `npx gov-data-mcp --preset compliance`
|
|
142
|
+
<!-- PRESETS:END -->
|
|
59
143
|
|
|
60
144
|
## Example prompts
|
|
61
145
|
|
|
@@ -103,7 +187,7 @@ The underlying actors carry the same discipline: per-source status on every row,
|
|
|
103
187
|
<!-- COVERAGE:START -->
|
|
104
188
|
## Coverage
|
|
105
189
|
|
|
106
|
-
**
|
|
190
|
+
**122 tools**, every one reading an official US government API or bulk file. The MCP server exposes 15 of them directly — twelve named tools plus `search-gov-data-tools`, `describe-gov-data-tool` and `run-gov-data-tool`, which reach the rest — because agents choose badly when handed more than about twenty tools.
|
|
107
191
|
|
|
108
192
|
Each entry links to its full input/output schema, pricing and worked examples.
|
|
109
193
|
|
|
@@ -127,9 +211,9 @@ Each entry links to its full input/output schema, pricing and worked examples.
|
|
|
127
211
|
|
|
128
212
|
[ssurgo-soil-suitability-screener](https://apify.com/malonestar/ssurgo-soil-suitability-screener) · [usda-cdl-farmland-siting-screener](https://apify.com/malonestar/usda-cdl-farmland-siting-screener) · [usgs-groundwater-depth-screener](https://apify.com/malonestar/usgs-groundwater-depth-screener) · [usgs-nwis-streamflow-monitor](https://apify.com/malonestar/usgs-nwis-streamflow-monitor) · [water-rights-availability-screener](https://apify.com/malonestar/water-rights-availability-screener)
|
|
129
213
|
|
|
130
|
-
**Banking, lending & credit** (
|
|
214
|
+
**Banking, lending & credit** (9)
|
|
131
215
|
|
|
132
|
-
[bank-enforcement-tracker](https://apify.com/malonestar/bank-enforcement-tracker) · [fdic-branch-network-churn-rollup](https://apify.com/malonestar/fdic-branch-network-churn-rollup) · [fdic-ncua-health-rollup](https://apify.com/malonestar/fdic-ncua-health-rollup) · [fdic-sod-deposit-market-share-rollup](https://apify.com/malonestar/fdic-sod-deposit-market-share-rollup) · [fdic-structure-change-delta-monitor](https://apify.com/malonestar/fdic-structure-change-delta-monitor) · [fhlbank-membership-delta-monitor](https://apify.com/malonestar/fhlbank-membership-delta-monitor) · [hmda-fair-lending-disparity-rollup](https://apify.com/malonestar/hmda-fair-lending-disparity-rollup) · [sba-loan-portfolio-explorer](https://apify.com/malonestar/sba-loan-portfolio-explorer)
|
|
216
|
+
[bank-enforcement-tracker](https://apify.com/malonestar/bank-enforcement-tracker) · [fdic-branch-network-churn-rollup](https://apify.com/malonestar/fdic-branch-network-churn-rollup) · [fdic-ncua-health-rollup](https://apify.com/malonestar/fdic-ncua-health-rollup) · [fdic-sod-deposit-market-share-rollup](https://apify.com/malonestar/fdic-sod-deposit-market-share-rollup) · [fdic-structure-change-delta-monitor](https://apify.com/malonestar/fdic-structure-change-delta-monitor) · [fhlbank-membership-delta-monitor](https://apify.com/malonestar/fhlbank-membership-delta-monitor) · [hmda-fair-lending-disparity-rollup](https://apify.com/malonestar/hmda-fair-lending-disparity-rollup) · [sba-loan-portfolio-explorer](https://apify.com/malonestar/sba-loan-portfolio-explorer) · [ucc-lapse-refinance-window](https://apify.com/malonestar/ucc-lapse-refinance-window)
|
|
133
217
|
|
|
134
218
|
**Securities, audit, pensions & sanctions** (10)
|
|
135
219
|
|
|
@@ -151,9 +235,9 @@ Each entry links to its full input/output schema, pricing and worked examples.
|
|
|
151
235
|
|
|
152
236
|
[cdc-nndss-outbreak-monitor](https://apify.com/malonestar/cdc-nndss-outbreak-monitor) · [clinical-trials-meta-search](https://apify.com/malonestar/clinical-trials-meta-search) · [cms-open-payments](https://apify.com/malonestar/cms-open-payments) · [cms-part-d-prescriber-delta](https://apify.com/malonestar/cms-part-d-prescriber-delta) · [drug-shortage-delta-monitor](https://apify.com/malonestar/drug-shortage-delta-monitor) · [nadac-price-movers](https://apify.com/malonestar/nadac-price-movers) · [usmin-mine-feature-proximity-screener](https://apify.com/malonestar/usmin-mine-feature-proximity-screener)
|
|
153
237
|
|
|
154
|
-
**Patents, IP & company data** (
|
|
238
|
+
**Patents, IP & company data** (5)
|
|
155
239
|
|
|
156
|
-
[npm-package-health-scorer](https://apify.com/malonestar/npm-package-health-scorer) · [ptab-trial-tracker](https://apify.com/malonestar/ptab-trial-tracker) · [sbom-vulnerability-rollup](https://apify.com/malonestar/sbom-vulnerability-rollup) · [uspto-patent-lapse-fto-monitor](https://apify.com/malonestar/uspto-patent-lapse-fto-monitor)
|
|
240
|
+
[ca-data-broker-registry-delta](https://apify.com/malonestar/ca-data-broker-registry-delta) · [npm-package-health-scorer](https://apify.com/malonestar/npm-package-health-scorer) · [ptab-trial-tracker](https://apify.com/malonestar/ptab-trial-tracker) · [sbom-vulnerability-rollup](https://apify.com/malonestar/sbom-vulnerability-rollup) · [uspto-patent-lapse-fto-monitor](https://apify.com/malonestar/uspto-patent-lapse-fto-monitor)
|
|
157
241
|
|
|
158
242
|
**Labor & enforcement** (3)
|
|
159
243
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gov-data-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"mcpName": "io.github.malonestar/gov-data-mcp",
|
|
5
5
|
"description": "MCP server exposing published US government open-data tools (EPA, FEMA, USGS, NOAA, FAA, USACE, FDIC, HUD, state licensing boards) as agent-callable tools, backed by Apify Actors.",
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
20
|
"start": "node src/index.js",
|
|
21
|
-
"test": "node --test test/tools.test.js test/apify.test.js test/catalog.test.js test/agent-surface.test.js",
|
|
21
|
+
"test": "node --test test/tools.test.js test/apify.test.js test/catalog.test.js test/agent-surface.test.js test/presets.test.js",
|
|
22
22
|
"catalog": "node tools/gen-catalog.cjs",
|
|
23
23
|
"check:catalog": "node tools/check-catalog-live.cjs",
|
|
24
24
|
"readme": "node tools/gen-readme-coverage.cjs"
|
package/src/catalog.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generatedAt": "2026-09-
|
|
2
|
+
"generatedAt": "2026-09-26T23:20:31.028Z",
|
|
3
3
|
"owner": "malonestar",
|
|
4
|
-
"count":
|
|
4
|
+
"count": 122,
|
|
5
5
|
"actors": [
|
|
6
6
|
{
|
|
7
7
|
"slug": "absentee-owner-lead-list-builder",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"categories": [
|
|
85
85
|
"REAL_ESTATE",
|
|
86
86
|
"LEAD_GENERATION",
|
|
87
|
-
"
|
|
87
|
+
"BUSINESS"
|
|
88
88
|
],
|
|
89
89
|
"storeUrl": "https://apify.com/malonestar/acris-deed-transfer-intel",
|
|
90
90
|
"pricing": {
|
|
@@ -770,6 +770,99 @@
|
|
|
770
770
|
}
|
|
771
771
|
}
|
|
772
772
|
},
|
|
773
|
+
{
|
|
774
|
+
"slug": "ca-data-broker-registry-delta",
|
|
775
|
+
"actorId": "malonestar/ca-data-broker-registry-delta",
|
|
776
|
+
"title": "California Data Broker Registry Monitor — CPPA Delete Act Delta",
|
|
777
|
+
"description": "California data broker registry API (CPPA / Delete Act): every registered data broker with 2026 disclosure flags (GenAI, foreign actor, minors, geolocation, biometric), DSAR metrics, first-registered year, new/lapsed/renamed/changed delta and is-this-company-registered verification.",
|
|
778
|
+
"categories": [
|
|
779
|
+
"BUSINESS",
|
|
780
|
+
"DEVELOPER_TOOLS",
|
|
781
|
+
"AGENTS"
|
|
782
|
+
],
|
|
783
|
+
"storeUrl": "https://apify.com/malonestar/ca-data-broker-registry-delta",
|
|
784
|
+
"pricing": {
|
|
785
|
+
"model": "PAY_PER_EVENT",
|
|
786
|
+
"event": "apify-default-dataset-item",
|
|
787
|
+
"unit": "Data broker registry row",
|
|
788
|
+
"usdPerUnit": 0.01,
|
|
789
|
+
"usdPer1000": 10,
|
|
790
|
+
"tierDiscountsUsdPerUnit": {
|
|
791
|
+
"FREE": 0.01,
|
|
792
|
+
"BRONZE": 0.008,
|
|
793
|
+
"SILVER": 0.007,
|
|
794
|
+
"GOLD": 0.0055,
|
|
795
|
+
"PLATINUM": 0.0055,
|
|
796
|
+
"DIAMOND": 0.0055
|
|
797
|
+
},
|
|
798
|
+
"actorStartUsd": null,
|
|
799
|
+
"since": "2026-09-26T22:00:01.299Z"
|
|
800
|
+
},
|
|
801
|
+
"inputSchema": {
|
|
802
|
+
"type": "object",
|
|
803
|
+
"properties": {
|
|
804
|
+
"mode": {
|
|
805
|
+
"type": "string",
|
|
806
|
+
"description": "registry = the full CPPA registrant list (filterable) with 2026 disclosure flags, DSAR metrics and registration history. delta = only what changed since your last run: new, lapsed, renamed and changed registrants (the first run compares against CPPA's own 2025 export, so it is a real delta). verify = check names[] against the registry and get a three-valued is_registered per name. Example: \"registry\".",
|
|
807
|
+
"enum": [
|
|
808
|
+
"registry",
|
|
809
|
+
"delta",
|
|
810
|
+
"verify"
|
|
811
|
+
]
|
|
812
|
+
},
|
|
813
|
+
"flags": {
|
|
814
|
+
"type": "array",
|
|
815
|
+
"description": "Optional. Keep only registrants that filed Yes on EVERY listed flag. Keys: collects_minors, collects_account_logins, collects_government_ids, collects_citizenship_data, collects_union_membership, collects_sexual_orientation, collects_gender_identity, collects_biometric, collects_precise_geolocation, collects_reproductive_health, sold_to_foreign_actor, sold_to_federal_government, sold_to_state_governments, sold_to_law_enforcement, sold_to_genai_developer, regulated_fcra, regulated_glba, regulated_iippa, regulated_cmia, regulated_hipaa. An unknown key fails the run before any download.",
|
|
816
|
+
"items": {
|
|
817
|
+
"type": "string"
|
|
818
|
+
}
|
|
819
|
+
},
|
|
820
|
+
"nameQuery": {
|
|
821
|
+
"type": "string",
|
|
822
|
+
"description": "Optional substring match on the registered name or DBA (case, punctuation and Inc/LLC suffixes ignored). Example: \"transunion\"."
|
|
823
|
+
},
|
|
824
|
+
"websiteQuery": {
|
|
825
|
+
"type": "string",
|
|
826
|
+
"description": "Optional substring match on the filed website, e.g. \"acxiom.com\"."
|
|
827
|
+
},
|
|
828
|
+
"state": {
|
|
829
|
+
"type": "string",
|
|
830
|
+
"description": "Optional. 2-letter code or full name (\"CA\" and \"California\" both match the same registrants — CPPA stores both spellings)."
|
|
831
|
+
},
|
|
832
|
+
"country": {
|
|
833
|
+
"type": "string",
|
|
834
|
+
"description": "Optional exact match on the filed country, as CPPA publishes it in upper case (UNITED STATES, UNITED KINGDOM, CANADA...)."
|
|
835
|
+
},
|
|
836
|
+
"eventTypes": {
|
|
837
|
+
"type": "array",
|
|
838
|
+
"description": "delta mode only. Optional subset of new, lapsed, renamed, changed. Empty = all four.",
|
|
839
|
+
"items": {
|
|
840
|
+
"type": "string"
|
|
841
|
+
}
|
|
842
|
+
},
|
|
843
|
+
"names": {
|
|
844
|
+
"type": "array",
|
|
845
|
+
"description": "verify mode. One entry per company; you get one row per entry with is_registered true / false / null (null = fuzzy candidates exist, see evidence — review, do not treat as negative). Max 500. Example: [\"Acxiom\",\"LexisNexis\",\"Oracle America\"].",
|
|
846
|
+
"items": {
|
|
847
|
+
"type": "string"
|
|
848
|
+
}
|
|
849
|
+
},
|
|
850
|
+
"includeHistory": {
|
|
851
|
+
"type": "boolean",
|
|
852
|
+
"description": "Also read CPPA's 2024 and 2025 exports and the legacy OAG 2020-2023 registry to fill first_registered_year / date, registration_years_seen and in_registry_* on every row. Three extra small downloads. Default on. Applied by default if omitted: true."
|
|
853
|
+
},
|
|
854
|
+
"maxResults": {
|
|
855
|
+
"type": "integer",
|
|
856
|
+
"description": "Hard cap on rows emitted and billed (1-5000). The full registry is ~600 rows; every row carries matched_rows_total and results_truncated so a capped answer is never mistaken for the whole list. Example: 100.",
|
|
857
|
+
"minimum": 1,
|
|
858
|
+
"maximum": 5000
|
|
859
|
+
}
|
|
860
|
+
},
|
|
861
|
+
"required": [
|
|
862
|
+
"mode"
|
|
863
|
+
]
|
|
864
|
+
}
|
|
865
|
+
},
|
|
773
866
|
{
|
|
774
867
|
"slug": "calfire-fhsz-screener",
|
|
775
868
|
"actorId": "malonestar/calfire-fhsz-screener",
|
|
@@ -1055,11 +1148,11 @@
|
|
|
1055
1148
|
"slug": "childcare-provider-leads",
|
|
1056
1149
|
"actorId": "malonestar/childcare-provider-leads",
|
|
1057
1150
|
"title": "Childcare Provider Leads — Daycare Contact Lists + Compliance",
|
|
1058
|
-
"description": "Licensed childcare provider lead lists from official state licensing data
|
|
1151
|
+
"description": "Licensed childcare provider lead lists from official state licensing data in 9 states: TX, NY, CA, PA, MA, CT, WA, DE, VT. Phone, email and named contacts where published; filter by county, type, capacity, ages. Violation history where the state publishes it. Delta mode flags new programs.",
|
|
1059
1152
|
"categories": [
|
|
1060
1153
|
"LEAD_GENERATION",
|
|
1061
1154
|
"AGENTS",
|
|
1062
|
-
"
|
|
1155
|
+
"BUSINESS"
|
|
1063
1156
|
],
|
|
1064
1157
|
"storeUrl": "https://apify.com/malonestar/childcare-provider-leads",
|
|
1065
1158
|
"pricing": {
|
|
@@ -1084,26 +1177,63 @@
|
|
|
1084
1177
|
"properties": {
|
|
1085
1178
|
"state": {
|
|
1086
1179
|
"type": "string",
|
|
1087
|
-
"description": "REQUIRED. US state to pull licensed childcare providers from
|
|
1180
|
+
"description": "REQUIRED. US state to pull licensed childcare providers from: TX, NY, CA, PA, MA, CT, WA, DE or VT. Name the state explicitly rather than relying on a default. To pull several states in one run, also fill \"Additional states\". Example: \"TX\".",
|
|
1088
1181
|
"enum": [
|
|
1089
|
-
"TX"
|
|
1182
|
+
"TX",
|
|
1183
|
+
"NY",
|
|
1184
|
+
"CA",
|
|
1185
|
+
"PA",
|
|
1186
|
+
"MA",
|
|
1187
|
+
"CT",
|
|
1188
|
+
"WA",
|
|
1189
|
+
"DE",
|
|
1190
|
+
"VT"
|
|
1090
1191
|
]
|
|
1091
1192
|
},
|
|
1193
|
+
"states": {
|
|
1194
|
+
"type": "array",
|
|
1195
|
+
"description": "Optional extra states to include in the same run, in addition to \"State\". maxResults is shared fairly across all requested states (a state that runs out of matches hands its unused share to the others). A state that cannot answer - source down, failed live check, or a filter it cannot apply - is skipped and disclosed on every row (run_states_failed / run_states_failed_reason); the run fails only if no requested state can answer.",
|
|
1196
|
+
"items": {
|
|
1197
|
+
"type": "string",
|
|
1198
|
+
"enum": [
|
|
1199
|
+
"TX",
|
|
1200
|
+
"NY",
|
|
1201
|
+
"CA",
|
|
1202
|
+
"PA",
|
|
1203
|
+
"MA",
|
|
1204
|
+
"CT",
|
|
1205
|
+
"WA",
|
|
1206
|
+
"DE",
|
|
1207
|
+
"VT"
|
|
1208
|
+
],
|
|
1209
|
+
"enumTitles": [
|
|
1210
|
+
"Texas (HHSC CCL — phone + email + violations)",
|
|
1211
|
+
"New York (OCFS + NYC DOHMH — phone)",
|
|
1212
|
+
"California (CDSS CCLD centers — phone + citations)",
|
|
1213
|
+
"Pennsylvania (OCDEL — phone + email + STARS)",
|
|
1214
|
+
"Massachusetts (EEC — phone)",
|
|
1215
|
+
"Connecticut (OEC — phone + inspections + violations)",
|
|
1216
|
+
"Washington (DCYF centers — email + contact)",
|
|
1217
|
+
"Delaware (OCCL — phone + citations)",
|
|
1218
|
+
"Vermont (CDD — phone + email + STARS + vacancies)"
|
|
1219
|
+
]
|
|
1220
|
+
}
|
|
1221
|
+
},
|
|
1092
1222
|
"county": {
|
|
1093
1223
|
"type": "string",
|
|
1094
|
-
"description": "Filter to one county (case-insensitive, e.g. \"Harris\", \"
|
|
1224
|
+
"description": "Filter to one county (case-insensitive, e.g. \"Harris\", \"Kings\" or \"Brooklyn\", \"Los Angeles\", \"Chester\"). Leave empty for statewide. Connecticut and Massachusetts publish NO county field, so a county filter makes those states fail loudly rather than return an unfiltered statewide list. A county that does not exist returns 0 rows, which is a valid answer. Example: \"Harris\"."
|
|
1095
1225
|
},
|
|
1096
1226
|
"operationType": {
|
|
1097
1227
|
"type": "string",
|
|
1098
|
-
"description": "Exact operation type (case-insensitive).
|
|
1228
|
+
"description": "Exact operation type as the state names it (case-insensitive). Examples - TX: \"Licensed Center\", \"Licensed Child-Care Home\"; NY: \"Day Care Center\", \"Group Family Day Care\", \"Family Day Care\", \"School Age Child Care\" (or DCC/GFDC/FDC/SACC); PA: \"Child Care Center\", \"Family Child Care Home\", \"Group Child Care Home\"; CT: \"Child Care Center\", \"Family Child Care Home\"; DE: \"Licensed Child Care Center\"; VT: \"CBCCPP\", \"Registered FCCH\", \"Licensed Provider\"; WA: \"CHILD CARE CENTER\", \"SCHOOL-AGE PROGRAM\"; MA: \"Center-based Care\", \"Family Child Care\"; CA: \"DAY CARE CENTER\", \"INFANT CENTER\", \"SCHOOL-AGE DC CENTER\". Leave empty for all types. Example: \"Licensed Center\"."
|
|
1099
1229
|
},
|
|
1100
1230
|
"agesServed": {
|
|
1101
1231
|
"type": "string",
|
|
1102
|
-
"description": "
|
|
1232
|
+
"description": "Ages-served filter, e.g. \"Infant\", \"Toddler\", \"Pre-Kindergarten\", \"School\". TX and DE match the published ages text; NY and VT match programs with licensed capacity in that age group (Infant, Toddler, Preschool, School). PA, CT, WA, MA and CA publish no usable ages field, so this filter makes those states fail loudly rather than return unfiltered rows. Leave empty for any."
|
|
1103
1233
|
},
|
|
1104
1234
|
"minCapacity": {
|
|
1105
1235
|
"type": "integer",
|
|
1106
|
-
"description": "Only include operations whose published total licensed capacity is at or above this number (e.g. 50 targets larger centers). 0 = no minimum. Operations for which
|
|
1236
|
+
"description": "Only include operations whose published total licensed capacity is at or above this number (e.g. 50 targets larger centers). 0 = no minimum. Operations for which the state publishes NO capacity are KEPT and marked capacity_filter_applied=\"kept_unknown_capacity\" rather than silently deleted - e.g. 141 of the 236 Texas Child Placing Agencies have no published capacity. Applied by default if omitted: 0.",
|
|
1107
1237
|
"minimum": 0,
|
|
1108
1238
|
"maximum": 10000
|
|
1109
1239
|
},
|
|
@@ -1115,7 +1245,7 @@
|
|
|
1115
1245
|
},
|
|
1116
1246
|
"includeCompliance": {
|
|
1117
1247
|
"type": "boolean",
|
|
1118
|
-
"description": "Also
|
|
1248
|
+
"description": "Also attach each state's published compliance record. TX: 2-year non-compliance join (deficiency_count_2y, high_risk_flag ...) - the lifetime counts HHSC publishes on the roster row are emitted either way. CT: inspection + violation history. DE: non-compliance findings (last ~5 years). CA: CCLD facility page (status, contact, licensee, inspections, Type A/B citations, complaints). NY, PA, VT, WA and MA publish no compliance dataset: those rows read violations_status=\"not_published\" with NULL counts, never 0. Example: true."
|
|
1119
1249
|
},
|
|
1120
1250
|
"highRiskThreshold": {
|
|
1121
1251
|
"type": "integer",
|
|
@@ -1125,7 +1255,7 @@
|
|
|
1125
1255
|
},
|
|
1126
1256
|
"mode": {
|
|
1127
1257
|
"type": "string",
|
|
1128
|
-
"description": "\"roster\" (default) returns the current filtered provider list. \"new_operations\" keeps a baseline of seen operation IDs in the NAMED key-value store \"childcare-provider-leads-state\", scoped to your filter combination, and after the first seeding run emits only newly licensed operations. Every row carries delta_baseline_status so a seeding run is distinguishable from an incremental one. Applied by default if omitted: \"roster\".",
|
|
1258
|
+
"description": "\"roster\" (default) returns the current filtered provider list. \"new_operations\" keeps a baseline of seen operation IDs in the NAMED key-value store \"childcare-provider-leads-state\", scoped to your state and filter combination (one baseline per state), and after the first seeding run emits only newly licensed operations. Every row carries delta_baseline_status so a seeding run is distinguishable from an incremental one. Applied by default if omitted: \"roster\".",
|
|
1129
1259
|
"enum": [
|
|
1130
1260
|
"roster",
|
|
1131
1261
|
"new_operations"
|
|
@@ -1133,7 +1263,7 @@
|
|
|
1133
1263
|
},
|
|
1134
1264
|
"activeOnly": {
|
|
1135
1265
|
"type": "boolean",
|
|
1136
|
-
"description": "Only include currently
|
|
1266
|
+
"description": "Only include currently operating programs (TX operation_status = Y; NY not Suspended; CT ACTIVE; WA Active; MA not Expired). PA, DE, VT and CA publish current rosters only. Disable to include all statuses where the state publishes them. Applied by default if omitted: true."
|
|
1137
1267
|
}
|
|
1138
1268
|
},
|
|
1139
1269
|
"required": [
|
|
@@ -1148,7 +1278,7 @@
|
|
|
1148
1278
|
"description": "New business-license lead feed across Chicago, LA, SF, NYC and Seattle. Normalizes municipal open data into one schema with new-vs-renewal and active-vs-dead licence flags, owner mailing address, NAICS, phone where published, plus per-city coverage and freshness on every row.",
|
|
1149
1279
|
"categories": [
|
|
1150
1280
|
"LEAD_GENERATION",
|
|
1151
|
-
"
|
|
1281
|
+
"BUSINESS",
|
|
1152
1282
|
"AGENTS"
|
|
1153
1283
|
],
|
|
1154
1284
|
"storeUrl": "https://apify.com/malonestar/city-business-license-leads",
|
|
@@ -5445,7 +5575,7 @@
|
|
|
5445
5575
|
"description": "KYB/AML company verification API. Given a company name, fans out to France (INSEE/RNE), GLEIF LEI, and US state registries and returns, per registry: exists, normalized status, jurisdiction, identifiers (SIREN/LEI), officers, address, and a match-confidence score. Keyless.",
|
|
5446
5576
|
"categories": [
|
|
5447
5577
|
"LEAD_GENERATION",
|
|
5448
|
-
"
|
|
5578
|
+
"BUSINESS",
|
|
5449
5579
|
"AGENTS"
|
|
5450
5580
|
],
|
|
5451
5581
|
"storeUrl": "https://apify.com/malonestar/kyb-company-verifier",
|
|
@@ -5500,7 +5630,7 @@
|
|
|
5500
5630
|
"slug": "license-verifier",
|
|
5501
5631
|
"actorId": "malonestar/license-verifier",
|
|
5502
5632
|
"title": "License Verification API — Nurses, MDs & OIG Exclusions",
|
|
5503
|
-
"description": "Primary source verification for US professional licenses. Search 19 state boards by name or license number: status, expiration, disciplinary actions. Cross-checks the NPPES NPI registry and screens the HHS-OIG exclusion list. Bulk roster screening.",
|
|
5633
|
+
"description": "Primary source verification for US professional licenses. Search 19 state boards by name or license number: status, expiration, disciplinary actions. Cross-checks the NPPES NPI registry and screens the HHS-OIG exclusion list. Bulk roster screening. Newly licensed clinicians feed (roster-delta).",
|
|
5504
5634
|
"categories": [
|
|
5505
5635
|
"BUSINESS",
|
|
5506
5636
|
"AUTOMATION",
|
|
@@ -5604,6 +5734,26 @@
|
|
|
5604
5734
|
"items": {
|
|
5605
5735
|
"type": "string"
|
|
5606
5736
|
}
|
|
5737
|
+
},
|
|
5738
|
+
"mode": {
|
|
5739
|
+
"type": "string",
|
|
5740
|
+
"description": "Leave empty for the classic lookup/roster behaviour. Set \"roster-delta\" for the newly-credentialed feed: every credential ORIGINALLY ISSUED in the last sinceDays on the selected boards, one row each, with NPI cross-walk and OIG screen. The first run seeds a named baseline and emits the window as event_type \"inventory\"; later runs emit only event_type \"newly_licensed\" (a credential absent from the baseline AND issued on/after the previous run minus 7 days). A run against unchanged data emits 0 rows and bills nothing. Boards with an original-issue date: WA (DOH), TX-BON, TX-LVN, TX-APRN, IL, CO, CT, DE, OR (CCB), WA-CPA, WA-CONTRACTOR, NY-NOTARY, NY-COS, NY-APPRAISER. In this mode maxResults is the TOTAL row cap for the run (newest credentials first).",
|
|
5741
|
+
"enum": [
|
|
5742
|
+
"roster-delta"
|
|
5743
|
+
]
|
|
5744
|
+
},
|
|
5745
|
+
"professions": {
|
|
5746
|
+
"type": "array",
|
|
5747
|
+
"description": "roster-delta only. Restrict to these professions, matched case-insensitively on the normalised profession (e.g. \"Registered Nurse\") or as a prefix of the board's raw credential type (\"Registered Nurse\" reaches \"Registered Nurse License\" and \"Registered Nurse Temporary Practice Permit\" but NOT \"Advanced Registered Nurse Practitioner\"). Examples: \"Registered Nurse\", \"Licensed Practical Nurse\", \"Physician And Surgeon\", \"Dentist\", \"Pharmacist\", \"Physical Therapist\". Omit for every profession the board publishes. Changing this filter starts a NEW delta baseline (the baseline is scoped by boards + professions). Example: [\"Registered Nurse\"].",
|
|
5748
|
+
"items": {
|
|
5749
|
+
"type": "string"
|
|
5750
|
+
}
|
|
5751
|
+
},
|
|
5752
|
+
"sinceDays": {
|
|
5753
|
+
"type": "integer",
|
|
5754
|
+
"description": "roster-delta only. How many days back the original-issue-date window reaches (1-400). The seeding run emits this whole window as inventory; later runs emit only credentials issued since the previous run (minus a 7-day publication slack). A non-integer or out-of-range value fails the run before any request is made. Example: 30.",
|
|
5755
|
+
"minimum": 1,
|
|
5756
|
+
"maximum": 400
|
|
5607
5757
|
}
|
|
5608
5758
|
}
|
|
5609
5759
|
}
|
|
@@ -5612,11 +5762,11 @@
|
|
|
5612
5762
|
"slug": "liquor-license-new-openings-tracker",
|
|
5613
5763
|
"actorId": "malonestar/liquor-license-new-openings-tracker",
|
|
5614
5764
|
"title": "Liquor License New Openings Tracker — Bar & Restaurant Leads",
|
|
5615
|
-
"description": "
|
|
5765
|
+
"description": "Bar & restaurant lead events from state liquor registries (TX, NY, FL, CA, WA, OR, CT, CO, MO, Chicago): new_application, newly_issued and closing_detected (expired, surrendered, revoked). Texas openings verified against Comptroller tax receipts (opened_verified). Delta mode emits only changes.",
|
|
5616
5766
|
"categories": [
|
|
5617
5767
|
"LEAD_GENERATION",
|
|
5618
5768
|
"AGENTS",
|
|
5619
|
-
"
|
|
5769
|
+
"BUSINESS"
|
|
5620
5770
|
],
|
|
5621
5771
|
"storeUrl": "https://apify.com/malonestar/liquor-license-new-openings-tracker",
|
|
5622
5772
|
"pricing": {
|
|
@@ -5641,30 +5791,43 @@
|
|
|
5641
5791
|
"properties": {
|
|
5642
5792
|
"states": {
|
|
5643
5793
|
"type": "array",
|
|
5644
|
-
"description": "Which
|
|
5794
|
+
"description": "Which liquor-license registries to query. TX (TABC active + pending), NY (SLA active + pending), FL (DBPR, active only), CA (ABC daily export, active + pending; CA applications carry no date), CO (LED recently approved licenses, active only), MO (ATC new licenses, active only), IL-CHICAGO (City of Chicago newly issued liquor licenses, active only), WA (LCB new-application notices, last 30 days, pending only), OR (OLCC applications in progress, pending only), CT (DCP pending permits, pending only; no date published). A state that lacks the requested feed is reported on every row (run_legs_failed) rather than silently skipped; the run fails only if NO requested state can answer. Example: [\"TX\",\"NY\"].",
|
|
5645
5795
|
"items": {
|
|
5646
5796
|
"type": "string",
|
|
5647
5797
|
"enum": [
|
|
5648
5798
|
"TX",
|
|
5649
5799
|
"NY",
|
|
5650
5800
|
"FL",
|
|
5651
|
-
"CA"
|
|
5801
|
+
"CA",
|
|
5802
|
+
"CO",
|
|
5803
|
+
"OR",
|
|
5804
|
+
"CT",
|
|
5805
|
+
"MO",
|
|
5806
|
+
"WA",
|
|
5807
|
+
"IL-CHICAGO"
|
|
5652
5808
|
],
|
|
5653
5809
|
"enumTitles": [
|
|
5654
5810
|
"Texas (TABC)",
|
|
5655
5811
|
"New York (SLA)",
|
|
5656
5812
|
"Florida (DBPR ABT)",
|
|
5657
|
-
"California (ABC)"
|
|
5813
|
+
"California (ABC)",
|
|
5814
|
+
"Colorado (LED)",
|
|
5815
|
+
"Oregon (OLCC)",
|
|
5816
|
+
"Connecticut (DCP)",
|
|
5817
|
+
"Missouri (ATC)",
|
|
5818
|
+
"Washington (LCB)",
|
|
5819
|
+
"Chicago, IL (city liquor licenses)"
|
|
5658
5820
|
]
|
|
5659
5821
|
}
|
|
5660
5822
|
},
|
|
5661
5823
|
"feed": {
|
|
5662
5824
|
"type": "string",
|
|
5663
|
-
"description": "Which feed to pull. \"pending\" = new license APPLICATIONS (the earliest opening signal
|
|
5825
|
+
"description": "Which feed to pull. \"pending\" = new license APPLICATIONS (the earliest opening signal -- a bar/restaurant typically opens 60-90 days later). \"active\" = recently ISSUED licenses (sorted newest first). \"all\" = pending + active (unchanged: it does NOT include closing). \"closing\" = licenses that EXPIRED, were SURRENDERED, CANCELLED or REVOKED, or are lapsing without a renewal -- a bar, restaurant or store going dark (newest first; each closing row also bills one closing-detected event). Pending is published by TX, NY, CA, WA, OR, CT; active by TX, NY, FL, CA, CO, MO and Chicago; closing by TX, OR and Chicago only -- any other requested state is reported on every row as unable to answer the closing feed, and the run fails if none can. Example: \"pending\".",
|
|
5664
5826
|
"enum": [
|
|
5665
5827
|
"pending",
|
|
5666
5828
|
"active",
|
|
5667
|
-
"all"
|
|
5829
|
+
"all",
|
|
5830
|
+
"closing"
|
|
5668
5831
|
]
|
|
5669
5832
|
},
|
|
5670
5833
|
"mode": {
|
|
@@ -5677,21 +5840,25 @@
|
|
|
5677
5840
|
},
|
|
5678
5841
|
"city": {
|
|
5679
5842
|
"type": "string",
|
|
5680
|
-
"description": "Optional case-insensitive city substring filter (e.g. \"Austin\", \"Brooklyn\", \"
|
|
5843
|
+
"description": "Optional case-insensitive city substring filter (e.g. \"Austin\", \"Brooklyn\", \"Seattle\"). Oregon applications publish no separate city, so for OR the match is against the one-line address. A source that publishes no city refuses the filter for its leg (disclosed on every row) instead of ignoring it."
|
|
5681
5844
|
},
|
|
5682
5845
|
"county": {
|
|
5683
5846
|
"type": "string",
|
|
5684
|
-
"description": "Optional case-insensitive county substring filter (e.g. \"Bexar\", \"Bronx\")."
|
|
5847
|
+
"description": "Optional case-insensitive county substring filter (e.g. \"Bexar\", \"Bronx\"). Published by TX, NY, FL, CA and MO only; any other requested source refuses a county filter for its leg (disclosed on every row) rather than returning its whole state as if filtered."
|
|
5685
5848
|
},
|
|
5686
5849
|
"sinceDate": {
|
|
5687
5850
|
"type": "string",
|
|
5688
|
-
"description": "Optional floor on the notice date. Pending feeds: applications submitted/received on or after this date. Active feeds: licenses issued on or after this date. MUST be YYYY-MM-DD (e.g. 2026-01-15) - any other format is rejected and the run fails without billing, rather than being spliced unverified into a live query. Slash forms are rejected on purpose: 05/06/2026 is ambiguous between US and EU order. California pending applications publish NO date: combining sinceDate with CA pending fails that leg (disclosed on every row) instead of returning an empty result -- use mode \"delta\" to catch new
|
|
5851
|
+
"description": "Optional floor on the notice date. Pending feeds: applications submitted/received on or after this date (WA: LCB notification date). Active feeds: licenses issued on or after this date. MUST be YYYY-MM-DD (e.g. 2026-01-15) - any other format is rejected and the run fails without billing, rather than being spliced unverified into a live query. Slash forms are rejected on purpose: 05/06/2026 is ambiguous between US and EU order. California and Connecticut pending applications publish NO date: combining sinceDate with CA or CT pending fails that leg (disclosed on every row) instead of returning an empty result -- use mode \"delta\" to catch new applications there."
|
|
5689
5852
|
},
|
|
5690
5853
|
"maxResults": {
|
|
5691
5854
|
"type": "integer",
|
|
5692
|
-
"description": "Total cap on records emitted across all selected states and feeds (each record is one billable result).
|
|
5855
|
+
"description": "Total cap on records emitted across all selected states and feeds (each record is one billable result). Each source gets an even share of what is left, so a source that returns fewer rows than its share passes the rest to the next one. Example: 200.",
|
|
5693
5856
|
"minimum": 1,
|
|
5694
5857
|
"maximum": 50000
|
|
5858
|
+
},
|
|
5859
|
+
"verifyOpenings": {
|
|
5860
|
+
"type": "boolean",
|
|
5861
|
+
"description": "Texas only, active feed only. When on (default), every issued TX permit that owes the mixed beverage gross receipts tax (MB, RM, N, NE, NB, NT, D, FB, TB) is joined to the Texas Comptroller's monthly receipts filings: opened_verified reads true when a period with receipts > 0 has been filed, false when at least two obligation periods were due and none carries receipts, and null when it is too early to tell or the permit class never files (beer/wine retailers, package stores). Adds first/latest receipts period, trailing-12-month receipts and the permit's rank in its county. Costs a few extra requests per 50 TX rows and no extra billing; set false to skip it. Applied by default if omitted: true."
|
|
5695
5862
|
}
|
|
5696
5863
|
}
|
|
5697
5864
|
}
|
|
@@ -7158,10 +7325,10 @@
|
|
|
7158
7325
|
"slug": "parcel-owner-lookup",
|
|
7159
7326
|
"actorId": "malonestar/parcel-owner-lookup",
|
|
7160
7327
|
"title": "Parcel Owner Lookup — Address to Owner & Assessor Record",
|
|
7161
|
-
"description": "
|
|
7328
|
+
"description": "Address to parcel ID, owner name, mailing address & assessed value from official assessor rolls: Chicago, Philadelphia, NYC + NC, NY State, WI, CO, MN, AR, MA, CT, VT statewide, Phoenix, Houston, Cleveland, Nashville & DC. Census fallback elsewhere. $0.02/lookup.",
|
|
7162
7329
|
"categories": [
|
|
7163
7330
|
"REAL_ESTATE",
|
|
7164
|
-
"
|
|
7331
|
+
"BUSINESS",
|
|
7165
7332
|
"AGENTS"
|
|
7166
7333
|
],
|
|
7167
7334
|
"storeUrl": "https://apify.com/malonestar/parcel-owner-lookup",
|
|
@@ -7187,7 +7354,7 @@
|
|
|
7187
7354
|
"properties": {
|
|
7188
7355
|
"addresses": {
|
|
7189
7356
|
"type": "array",
|
|
7190
|
-
"description": "US street addresses to resolve to a parcel + owner record, one per line (e.g. '1060 W Addison St, Chicago, IL').
|
|
7357
|
+
"description": "US street addresses to resolve to a parcel + owner record, one per line (e.g. '1060 W Addison St, Chicago, IL'). Matched against the Cook County IL (Chicago), Philadelphia PA and New York City rolls, plus (v1.1) statewide rolls for North Carolina, New York State, Wisconsin, Colorado, Minnesota (opt-in counties), Arkansas, Massachusetts, Connecticut and Vermont and county rolls for Maricopa AZ (Phoenix), Harris TX (Houston), Cuyahoga OH (Cleveland), Nashville TN and Washington DC - routed by the Census-geocoded point's county. Addresses elsewhere fall back to Census geocoding (lat/lon only). Every input address yields exactly one output row; see lookup_status on each row. Example: [\"1060 W Addison St, Chicago, IL\",\"1234 Market St, Philadelphia, PA\",\"350 5th Ave, New York, NY\"].",
|
|
7191
7358
|
"items": {
|
|
7192
7359
|
"type": "string"
|
|
7193
7360
|
}
|
|
@@ -7442,7 +7609,7 @@
|
|
|
7442
7609
|
"slug": "realtor-license-roster-delta",
|
|
7443
7610
|
"actorId": "malonestar/realtor-license-roster-delta",
|
|
7444
7611
|
"title": "Realtor License Roster, New Applicants & Broker Change Delta",
|
|
7445
|
-
"description": "Real estate licensee lead feeds for recruiters:
|
|
7612
|
+
"description": "Real estate licensee lead feeds for recruiters: TX daily license applications, newly licensed agents and broker-change (affiliation) events for TX, FL, CT, CO, NY and DE. Official state licensing data, normalized with license, status, sponsoring broker and address.",
|
|
7446
7613
|
"categories": [
|
|
7447
7614
|
"LEAD_GENERATION",
|
|
7448
7615
|
"REAL_ESTATE",
|
|
@@ -7471,39 +7638,40 @@
|
|
|
7471
7638
|
"properties": {
|
|
7472
7639
|
"states": {
|
|
7473
7640
|
"type": "array",
|
|
7474
|
-
"description": "REQUIRED. US states to pull. Supported: TX (
|
|
7641
|
+
"description": "REQUIRED. US states to pull (two-letter codes; full names also accepted). Supported: TX (daily new applications, new licensees, roster, delta), FL (new licensees, weekly roster, delta), CT (new licensees, roster, delta with broker affiliation), CO (new licensees, roster, delta), DE (new licensees, roster, delta), NY (active roster + broker-change delta; NY publishes no issue date). Several states can be combined; maxResults is split across them. Example: [\"TX\"].",
|
|
7475
7642
|
"items": {
|
|
7476
7643
|
"type": "string"
|
|
7477
7644
|
}
|
|
7478
7645
|
},
|
|
7479
7646
|
"feed": {
|
|
7480
7647
|
"type": "string",
|
|
7481
|
-
"description": "Which lead feed to produce. new_applicants = TREC daily license applications (future agents,
|
|
7648
|
+
"description": "Which lead feed to produce. new_applicants = TREC daily license applications (future agents, TX only). new_licensees = licences first issued in the last daysBack days (TX, FL, CT, CO, DE). roster = a bounded slice of the current licensee roster. delta = compare against the saved baseline and emit newly_licensed + affiliation_change events (first run only seeds the baseline). Leave empty to use each state's own default (TX new_applicants; FL/CT/CO/DE new_licensees; NY roster). If a state does not publish the requested feed it serves the closest one it does publish and says so on every row (feed_requested / feed_resolution / feed_note) instead of failing. Example: \"new_applicants\".",
|
|
7482
7649
|
"enum": [
|
|
7483
7650
|
"new_applicants",
|
|
7651
|
+
"new_licensees",
|
|
7484
7652
|
"roster",
|
|
7485
7653
|
"delta"
|
|
7486
7654
|
]
|
|
7487
7655
|
},
|
|
7488
7656
|
"daysBack": {
|
|
7489
7657
|
"type": "integer",
|
|
7490
|
-
"description": "Look-back window in days for the new_applicants
|
|
7658
|
+
"description": "Look-back window in days for the new_applicants and new_licensees feeds. Anchored to the newest date actually present in the source (not today), so the feed never comes back empty because of publishing lag. Example: 14.",
|
|
7491
7659
|
"minimum": 0,
|
|
7492
7660
|
"maximum": 365
|
|
7493
7661
|
},
|
|
7494
7662
|
"maxResults": {
|
|
7495
7663
|
"type": "integer",
|
|
7496
|
-
"description": "Maximum number of records to push to the dataset (billing is per result). Example: 200.",
|
|
7664
|
+
"description": "Maximum number of records to push to the dataset (billing is per result). When several states are requested the cap is split across them, and budget an earlier state does not use passes to the next. Example: 200.",
|
|
7497
7665
|
"minimum": 1,
|
|
7498
7666
|
"maximum": 50000
|
|
7499
7667
|
},
|
|
7500
7668
|
"name": {
|
|
7501
7669
|
"type": "string",
|
|
7502
|
-
"description": "Optional case-insensitive filter on licensee name (TX: full name; applications: last name; FL: licensee name)."
|
|
7670
|
+
"description": "Optional case-insensitive filter on licensee name (TX: full name; TX applications: last name; FL, CT, NY, DE: licensee name; CO: last name)."
|
|
7503
7671
|
},
|
|
7504
7672
|
"county": {
|
|
7505
7673
|
"type": "string",
|
|
7506
|
-
"description": "Optional case-insensitive county filter, e.g. \"Travis\" or \"Escambia\".
|
|
7674
|
+
"description": "Optional case-insensitive county filter, e.g. \"Travis\" or \"Escambia\". Supported for TX, FL and NY. CT, CO and DE publish no county column: a run that combines a county filter with those states skips them (and says so) rather than returning unfiltered rows."
|
|
7507
7675
|
},
|
|
7508
7676
|
"licenseType": {
|
|
7509
7677
|
"type": "string",
|
|
@@ -7511,11 +7679,11 @@
|
|
|
7511
7679
|
},
|
|
7512
7680
|
"status": {
|
|
7513
7681
|
"type": "string",
|
|
7514
|
-
"description": "Optional case-insensitive license-status filter, e.g. \"Active\". Ignored on the TX applications dataset (it has no status column)."
|
|
7682
|
+
"description": "Optional case-insensitive license-status filter, e.g. \"Active\". Ignored on the TX applications dataset (it has no status column). NY publishes active licences only, so a status filter skips NY."
|
|
7515
7683
|
},
|
|
7516
7684
|
"flRegions": {
|
|
7517
7685
|
"type": "array",
|
|
7518
|
-
"description": "Florida DBPR region numbers 1-14 to download when states includes FL (each region is one weekly CSV
|
|
7686
|
+
"description": "Florida DBPR region numbers 1-14 to download when states includes FL (each region is one weekly CSV of ~4-5 MB). Region 1 is used when empty. Example: [\"1\"].",
|
|
7519
7687
|
"items": {
|
|
7520
7688
|
"type": "string"
|
|
7521
7689
|
}
|
|
@@ -8118,12 +8286,12 @@
|
|
|
8118
8286
|
{
|
|
8119
8287
|
"slug": "sos-registry-monitor",
|
|
8120
8288
|
"actorId": "malonestar/sos-registry-monitor",
|
|
8121
|
-
"title": "
|
|
8122
|
-
"description": "
|
|
8289
|
+
"title": "Verified New Business Openings by State & County (SOS + Tax)",
|
|
8290
|
+
"description": "New business leads from official state data: one row per business that just opened, verified across the Secretary of State charter and the sales-tax permit (first-sales date), with county, NAICS, entity type and a three-valued confidence. TX, CO, CT, NY, OR, PA, DE. Keyless, no anti-bot.",
|
|
8123
8291
|
"categories": [
|
|
8292
|
+
"BUSINESS",
|
|
8124
8293
|
"LEAD_GENERATION",
|
|
8125
|
-
"
|
|
8126
|
-
"AUTOMATION"
|
|
8294
|
+
"AGENTS"
|
|
8127
8295
|
],
|
|
8128
8296
|
"storeUrl": "https://apify.com/malonestar/sos-registry-monitor",
|
|
8129
8297
|
"pricing": {
|
|
@@ -8148,15 +8316,16 @@
|
|
|
8148
8316
|
"properties": {
|
|
8149
8317
|
"mode": {
|
|
8150
8318
|
"type": "string",
|
|
8151
|
-
"description": "search = look up companies by name. new_businesses =
|
|
8319
|
+
"description": "openings = ONE row per business that just opened, resolved across every register the state publishes (TX: SOS charter via the franchise-tax roster + sales-tax permit with first-sales date; other states: the SOS registry) with opened_evidence and a three-valued opened_confidence. search = look up companies by name. new_businesses = raw recently formed entities, one row per registry record. Example: \"openings\". Applied by default if omitted: \"search\".",
|
|
8152
8320
|
"enum": [
|
|
8321
|
+
"openings",
|
|
8153
8322
|
"search",
|
|
8154
8323
|
"new_businesses"
|
|
8155
8324
|
]
|
|
8156
8325
|
},
|
|
8157
8326
|
"states": {
|
|
8158
8327
|
"type": "array",
|
|
8159
|
-
"description": "REQUIRED. State codes to query. Supported: CO, CT, NY, OR, PA, DE (official state open-data
|
|
8328
|
+
"description": "REQUIRED. State codes to query. Supported: TX, CO, CT, NY, OR, PA, DE (official state open-data registers). Every requested state is queried independently and its per-state outcome is reported on the row. Texas is read from two Comptroller rosters (franchise tax + sales-tax permits); all other states publish one register, so their openings never read better than opened_confidence=low. Name at least one -- there is no default. Example: [\"TX\",\"CO\"].",
|
|
8160
8329
|
"items": {
|
|
8161
8330
|
"type": "string"
|
|
8162
8331
|
}
|
|
@@ -8167,7 +8336,7 @@
|
|
|
8167
8336
|
},
|
|
8168
8337
|
"daysBack": {
|
|
8169
8338
|
"type": "integer",
|
|
8170
|
-
"description": "How many days
|
|
8339
|
+
"description": "How many days back to look (new_businesses and openings modes; used when no explicit since date is given). Each register is filtered on its own date column -- see date_basis / opened_evidence on the output. Note: PA republishes roughly monthly and OR/DE lag by days, so widen this if a short window returns nothing. Example: 30. Applied by default if omitted: 7.",
|
|
8171
8340
|
"minimum": 1,
|
|
8172
8341
|
"maximum": 365
|
|
8173
8342
|
},
|
|
@@ -8181,9 +8350,15 @@
|
|
|
8181
8350
|
"minimum": 1,
|
|
8182
8351
|
"maximum": 50000
|
|
8183
8352
|
},
|
|
8353
|
+
"maxResults": {
|
|
8354
|
+
"type": "integer",
|
|
8355
|
+
"description": "Hard ceiling on the number of rows this run may emit and bill, across all states. In openings mode one row = one business; the cap is shared max-min fairly across the requested states (so a Texas run cannot starve Colorado), and within a state rows are ranked by opened_confidence (high first) then newest evidence. Applied once by a single emission planner. Omit it in openings mode and the run caps itself at 200; omit it in search / new_businesses and only maxPerState applies (the pre-2026-09-26 behaviour). Rows carry result_truncated=true when the cap bound. Example: 50.",
|
|
8356
|
+
"minimum": 1,
|
|
8357
|
+
"maximum": 5000
|
|
8358
|
+
},
|
|
8184
8359
|
"monitor": {
|
|
8185
8360
|
"type": "boolean",
|
|
8186
|
-
"description": "When scheduled, emit only entities not seen in previous runs of the same
|
|
8361
|
+
"description": "When scheduled, emit only entities (or, in openings mode, businesses) not seen in previous runs of the same scope -- turns this into a recurring new-business alert. The baseline is kept in a NAMED store scoped to the mode, state set and query, so the first run of a new configuration is a full dump by design (delta_baseline_size reports 0). Applied by default if omitted: false."
|
|
8187
8362
|
},
|
|
8188
8363
|
"socrataAppToken": {
|
|
8189
8364
|
"type": "string",
|
|
@@ -8427,6 +8602,90 @@
|
|
|
8427
8602
|
]
|
|
8428
8603
|
}
|
|
8429
8604
|
},
|
|
8605
|
+
{
|
|
8606
|
+
"slug": "ucc-lapse-refinance-window",
|
|
8607
|
+
"actorId": "malonestar/ucc-lapse-refinance-window",
|
|
8608
|
+
"title": "UCC Lien Lapse Leads: Refinance Window + Lender Rollup",
|
|
8609
|
+
"description": "UCC lien lapse leads for equipment-finance, MCA and factoring brokers: UCC-1 financing statements lapsing in the next N days (continuations honoured, terminated liens excluded) with debtor, lender and collateral, plus a secured-party filings rollup by quarter. CO, CT, OR open data. Keyless.",
|
|
8610
|
+
"categories": [
|
|
8611
|
+
"BUSINESS",
|
|
8612
|
+
"LEAD_GENERATION",
|
|
8613
|
+
"AGENTS"
|
|
8614
|
+
],
|
|
8615
|
+
"storeUrl": "https://apify.com/malonestar/ucc-lapse-refinance-window",
|
|
8616
|
+
"pricing": {
|
|
8617
|
+
"model": "PAY_PER_EVENT",
|
|
8618
|
+
"event": "apify-default-dataset-item",
|
|
8619
|
+
"unit": "UCC lapse lead / rollup row",
|
|
8620
|
+
"usdPerUnit": 0.02,
|
|
8621
|
+
"usdPer1000": 20,
|
|
8622
|
+
"tierDiscountsUsdPerUnit": {
|
|
8623
|
+
"FREE": 0.02,
|
|
8624
|
+
"BRONZE": 0.016,
|
|
8625
|
+
"SILVER": 0.014,
|
|
8626
|
+
"GOLD": 0.011,
|
|
8627
|
+
"PLATINUM": 0.011,
|
|
8628
|
+
"DIAMOND": 0.011
|
|
8629
|
+
},
|
|
8630
|
+
"actorStartUsd": null,
|
|
8631
|
+
"since": "2026-09-26T22:00:50.208Z"
|
|
8632
|
+
},
|
|
8633
|
+
"inputSchema": {
|
|
8634
|
+
"type": "object",
|
|
8635
|
+
"properties": {
|
|
8636
|
+
"states": {
|
|
8637
|
+
"type": "array",
|
|
8638
|
+
"description": "REQUIRED. State codes to query. Shipped: CO (full: debtor + secured party + collateral + lapse), CT (full: debtor + secured party + lapse), OR (partial: secured party + lapse, no debtor table published -- rows link to the filing image). NY, PA, DE, TX, WA publish no UCC dataset and are reported as state_coverage=not_available on the run, never as an empty success. Every state is judged independently and its outcome is stamped on every row. Example: [\"CO\"].",
|
|
8639
|
+
"items": {
|
|
8640
|
+
"type": "string"
|
|
8641
|
+
}
|
|
8642
|
+
},
|
|
8643
|
+
"mode": {
|
|
8644
|
+
"type": "string",
|
|
8645
|
+
"description": "lapse-window = one row per UCC-1 financing statement whose CURRENT lapse date (after continuations; terminated liens excluded) falls inside the next windowDays -- the refinance / re-solicit trigger. secured-party-rollup = initial UCC-1 filings per secured party x quarter over the trailing windowDays (who is lending, how much, where). Example: \"lapse-window\".",
|
|
8646
|
+
"enum": [
|
|
8647
|
+
"lapse-window",
|
|
8648
|
+
"secured-party-rollup"
|
|
8649
|
+
]
|
|
8650
|
+
},
|
|
8651
|
+
"windowDays": {
|
|
8652
|
+
"type": "integer",
|
|
8653
|
+
"description": "lapse-window: liens lapsing between the window start (today, or sinceDate) and start + windowDays. secured-party-rollup: initial filings accepted in the trailing windowDays (or since sinceDate). 1-365. Example: 90.",
|
|
8654
|
+
"minimum": 1,
|
|
8655
|
+
"maximum": 365
|
|
8656
|
+
},
|
|
8657
|
+
"sinceDate": {
|
|
8658
|
+
"type": "string",
|
|
8659
|
+
"description": "Optional. MUST be YYYY-MM-DD (e.g. 2027-01-01); any other format fails the run without billing rather than being spliced unverified into the live query -- slash forms are rejected on purpose because 05/06/2025 is ambiguous. lapse-window: the window starts here instead of today (ask for lapses in a future quarter). secured-party-rollup: count filings accepted on/after this date instead of today - windowDays."
|
|
8660
|
+
},
|
|
8661
|
+
"securedPartyQuery": {
|
|
8662
|
+
"type": "string",
|
|
8663
|
+
"description": "Optional. Keep only rows whose secured party (lender) name contains this text, case-insensitive (e.g. \"Kubota\", \"Wells Fargo\", \"Small Business Administration\"). Applied after each lien is fully assembled, so a lender named only on an amendment still matches."
|
|
8664
|
+
},
|
|
8665
|
+
"debtorCity": {
|
|
8666
|
+
"type": "string",
|
|
8667
|
+
"description": "Optional. Keep only leads whose primary debtor address city equals this (case-insensitive). CO and CT publish debtor cities; OR publishes no debtor table, so an OR leg with this filter is reported as not applicable rather than silently ignored."
|
|
8668
|
+
},
|
|
8669
|
+
"county": {
|
|
8670
|
+
"type": "string",
|
|
8671
|
+
"description": "Optional. None of the shipped portals publishes a county on the filing record; CO carries one only on farm-product collateral records. A state that cannot honour the filter is reported as not applicable on the run, never silently ignored. Prefer debtorCity."
|
|
8672
|
+
},
|
|
8673
|
+
"maxResults": {
|
|
8674
|
+
"type": "integer",
|
|
8675
|
+
"description": "Hard cap on billable rows for the whole run (all states together, soonest lapse first / largest lender first). When more matched, every row carries result_truncated=true. Default 500; prefill 40 so a first free-tier run costs under $1. Example: 40. Applied by default if omitted: 500.",
|
|
8676
|
+
"minimum": 1,
|
|
8677
|
+
"maximum": 5000
|
|
8678
|
+
},
|
|
8679
|
+
"socrataAppToken": {
|
|
8680
|
+
"type": "string",
|
|
8681
|
+
"description": "Optional free Socrata app token to raise rate limits on the state portals."
|
|
8682
|
+
}
|
|
8683
|
+
},
|
|
8684
|
+
"required": [
|
|
8685
|
+
"states"
|
|
8686
|
+
]
|
|
8687
|
+
}
|
|
8688
|
+
},
|
|
8430
8689
|
{
|
|
8431
8690
|
"slug": "uflpa-entity-list-monitor",
|
|
8432
8691
|
"actorId": "malonestar/uflpa-entity-list-monitor",
|
|
@@ -9375,7 +9634,7 @@
|
|
|
9375
9634
|
"description": "Aggregate US state WARN Act layoff & closure notices into one normalized schema and track new / updated / removed deltas. Oregon (HECC export) and Texas (Socrata) live and keyless; CA/NY/WA/WI/IL/NJ scaffolded. For RevOps, recruiting, econ research and CRE. No API key.",
|
|
9376
9635
|
"categories": [
|
|
9377
9636
|
"LEAD_GENERATION",
|
|
9378
|
-
"
|
|
9637
|
+
"BUSINESS",
|
|
9379
9638
|
"AGENTS"
|
|
9380
9639
|
],
|
|
9381
9640
|
"storeUrl": "https://apify.com/malonestar/warn-layoff-aggregator",
|
package/src/index.js
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* here; it is read from src/catalog.json at runtime, because a number in a
|
|
6
6
|
* comment rots the moment a batch ships and nothing fails when it does.
|
|
7
7
|
*
|
|
8
|
-
* Wiring only. All decision logic lives in src/tools.js (pure, offline-tested)
|
|
8
|
+
* Wiring only. All decision logic lives in src/tools.js (pure, offline-tested),
|
|
9
|
+
* src/presets.js (vertical presets: --preset <name> / GOV_DATA_MCP_PRESET, pure)
|
|
9
10
|
* and src/apify.js (fetch injected). A test asserts this file holds no logic
|
|
10
11
|
* beyond dispatch.
|
|
11
12
|
*/
|
|
@@ -18,14 +19,38 @@ import { dirname, join } from 'node:path';
|
|
|
18
19
|
|
|
19
20
|
import { createClient, ApifyError } from './apify.js';
|
|
20
21
|
import { indexCatalog, listTools, searchCatalog, describeTool, resolveCall, formatRunResult, META_TOOLS } from './tools.js';
|
|
22
|
+
import { parseCliArgs, resolvePreset, describePresets, PRESET_ENV } from './presets.js';
|
|
21
23
|
|
|
22
24
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
23
25
|
const pkg = JSON.parse(readFileSync(join(here, '..', 'package.json'), 'utf8'));
|
|
24
26
|
const catalog = JSON.parse(readFileSync(join(here, 'catalog.json'), 'utf8'));
|
|
25
|
-
|
|
27
|
+
|
|
28
|
+
// --preset <name> / GOV_DATA_MCP_PRESET scopes the server to one vertical.
|
|
29
|
+
// Nothing here decides anything: parsing and resolution are pure (presets.js)
|
|
30
|
+
// and an unknown or empty preset stops the process before the transport opens,
|
|
31
|
+
// so a client never connects to a server serving the wrong shelf.
|
|
32
|
+
const cli = parseCliArgs(process.argv.slice(2), process.env);
|
|
33
|
+
if (cli.listPresets) {
|
|
34
|
+
process.stdout.write(JSON.stringify(describePresets(), null, 2) + '\n');
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
if (cli.errors.length) {
|
|
38
|
+
console.error(`[gov-data-mcp] ${cli.errors.join('; ')}. Known presets: ${describePresets().map(p => p.name).join(', ')}. Omit --preset (and ${PRESET_ENV}) for the full catalog.`);
|
|
39
|
+
process.exit(2);
|
|
40
|
+
}
|
|
41
|
+
const chosen = resolvePreset(cli.presetName);
|
|
42
|
+
if (!chosen.ok) {
|
|
43
|
+
console.error(`[gov-data-mcp] ${chosen.error}`);
|
|
44
|
+
process.exit(2);
|
|
45
|
+
}
|
|
46
|
+
const index = indexCatalog(catalog, { preset: chosen.preset, presetName: chosen.name });
|
|
47
|
+
|
|
48
|
+
const identity = chosen.preset
|
|
49
|
+
? { name: chosen.preset.serverName, version: pkg.version, title: chosen.preset.title, description: chosen.preset.description, websiteUrl: 'https://apify.com/malonestar' }
|
|
50
|
+
: { name: 'gov-data-mcp', version: pkg.version };
|
|
26
51
|
|
|
27
52
|
const server = new Server(
|
|
28
|
-
|
|
53
|
+
identity,
|
|
29
54
|
{ capabilities: { tools: {} } },
|
|
30
55
|
);
|
|
31
56
|
|
|
@@ -71,7 +96,8 @@ async function main() {
|
|
|
71
96
|
console.error(`[gov-data-mcp] WARNING: featured tools missing from catalog: ${index.missingFeatured.join(', ')}`);
|
|
72
97
|
}
|
|
73
98
|
await server.connect(new StdioServerTransport());
|
|
74
|
-
|
|
99
|
+
const scope = index.presetName ? ` [preset ${index.presetName}: ${index.actors.length} of ${index.catalogTotal}]` : '';
|
|
100
|
+
console.error(`[${identity.name}] ready — ${index.actors.length} government data tools${scope} (catalog generated ${catalog.generatedAt})`);
|
|
75
101
|
}
|
|
76
102
|
|
|
77
103
|
main().catch(err => {
|
package/src/presets.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vertical presets — the same package, the same catalog, a smaller front door.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS. Agents pick tools badly past about twenty, and the full
|
|
5
|
+
* server already exposes fifteen. A Phase I ESA consultant's agent does not
|
|
6
|
+
* need to weigh a liquor-license feed against a Superfund screen; a sales
|
|
7
|
+
* agent building a CRE lead list does not need wetlands. A preset restricts the
|
|
8
|
+
* WHOLE surface — the named tools AND what search/describe/run can reach — to
|
|
9
|
+
* one buyer's shelf, and announces itself to the client under its own server
|
|
10
|
+
* name and description, so a connector directory can list three products that
|
|
11
|
+
* are, underneath, one npm package with one catalog and one release train.
|
|
12
|
+
*
|
|
13
|
+
* WHY NOT THREE NPM PACKAGES. A first `npm publish` cannot be automated from
|
|
14
|
+
* CI (Trusted Publishing needs the package to already exist), each package
|
|
15
|
+
* would carry its own copy of the catalog to drift, and the Official MCP
|
|
16
|
+
* Registry entry stays singular. One package, one gate, `--preset <name>`.
|
|
17
|
+
*
|
|
18
|
+
* Pure. No I/O. `resolvePreset` and `parseCliArgs` are what index.js calls.
|
|
19
|
+
*
|
|
20
|
+
* Every slug listed here is asserted to exist in the bundled catalog by
|
|
21
|
+
* test/presets.test.js, and the preset count is derived into the README by
|
|
22
|
+
* tools/gen-readme-coverage.cjs — never typed.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
export const PRESET_ENV = 'GOV_DATA_MCP_PRESET';
|
|
26
|
+
|
|
27
|
+
export const PRESETS = {
|
|
28
|
+
'phase1-esa': {
|
|
29
|
+
serverName: 'gov-data-mcp-phase1-esa',
|
|
30
|
+
title: 'Phase I ESA — Environmental Due Diligence',
|
|
31
|
+
description: 'US government environmental records for Phase I Environmental Site Assessments and property due diligence: '
|
|
32
|
+
+ 'EPA Superfund / RCRA / UST / brownfield records at ASTM E1527-21 search distances, state tank and spill registries, '
|
|
33
|
+
+ 'historic land use from FRS SIC/NAICS, USGS historical topographic map coverage, NWI wetlands, Clean Water Act §404 '
|
|
34
|
+
+ 'surface water, RCRA corrective-action cleanups, orphaned wells, FEMA hazard risk and NFIP flood-loss history, plus a '
|
|
35
|
+
+ 'twenty-layer go / caution / no-go site verdict. Every tool reads the official source directly and reports what it '
|
|
36
|
+
+ 'could not check as null, never as clear.',
|
|
37
|
+
tools: [
|
|
38
|
+
'site-due-diligence-bundle',
|
|
39
|
+
'epa-contaminated-site-screener',
|
|
40
|
+
'historic-land-use-sic-contaminant-screener',
|
|
41
|
+
'state-tank-spill-registry-screener',
|
|
42
|
+
'usgs-historical-topo-records-review',
|
|
43
|
+
'epa-rcra-corrective-action-cleanup-monitor',
|
|
44
|
+
'orphaned-well-proximity-screener',
|
|
45
|
+
'fws-wetlands-proximity-screener',
|
|
46
|
+
'nhd-surface-water-404-screener',
|
|
47
|
+
'fema-nri-county-risk-profile',
|
|
48
|
+
'nfip-flood-loss-risk-screener',
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
'cre-leads': {
|
|
52
|
+
serverName: 'gov-data-mcp-cre-leads',
|
|
53
|
+
title: 'CRE & Local Business Leads — Who Just Changed State',
|
|
54
|
+
description: 'Lead-generation feeds built from official state and county registers: new and pending liquor licenses, '
|
|
55
|
+
+ 'verified new business openings from Secretary of State and tax rosters, WARN layoff notices, newly licensed real '
|
|
56
|
+
+ 'estate agents, licensed childcare providers with contacts, parcel owner of record, absentee-owner lists, '
|
|
57
|
+
+ 'distressed-property signal stacks, NYC deed transfers and landlord registries, city business licenses and '
|
|
58
|
+
+ 'professional license verification. Delta modes return only what changed since the last run, so a scheduled agent '
|
|
59
|
+
+ 'pays for new leads, not the same roster twice.',
|
|
60
|
+
tools: [
|
|
61
|
+
'liquor-license-new-openings-tracker',
|
|
62
|
+
'sos-registry-monitor',
|
|
63
|
+
'warn-layoff-aggregator',
|
|
64
|
+
'realtor-license-roster-delta',
|
|
65
|
+
'childcare-provider-leads',
|
|
66
|
+
'parcel-owner-lookup',
|
|
67
|
+
'absentee-owner-lead-list-builder',
|
|
68
|
+
'distressed-property-signal-stacker',
|
|
69
|
+
'acris-deed-transfer-intel',
|
|
70
|
+
'nyc-landlord-registry-lead-list',
|
|
71
|
+
'city-business-license-leads',
|
|
72
|
+
'license-verifier',
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
'compliance': {
|
|
76
|
+
serverName: 'gov-data-mcp-compliance',
|
|
77
|
+
title: 'KYB, Sanctions & Financial Compliance Screening',
|
|
78
|
+
description: 'Know-your-business and compliance screening from primary US government registers: company existence '
|
|
79
|
+
+ 'across Secretary of State registries, the Trade.gov Consolidated Screening List (OFAC SDN, BIS, State) as a delta, '
|
|
80
|
+
+ 'the DHS UFLPA Entity List, state Medicaid and HHS-OIG exclusion lists, professional license verification, GLEIF '
|
|
81
|
+
+ 'LEI ownership graphs, FDIC / NCUA institution health, FDIC structure changes, SEC investment-adviser registrations, '
|
|
82
|
+
+ 'PCAOB auditor engagements and SEC Regulation CF / A+ offering lifecycles. A screen that could not reach its source '
|
|
83
|
+
+ 'fails loudly rather than returning a clean sheet.',
|
|
84
|
+
tools: [
|
|
85
|
+
'kyb-company-verifier',
|
|
86
|
+
'consolidated-screening-list-delta',
|
|
87
|
+
'uflpa-entity-list-monitor',
|
|
88
|
+
'medicaid-exclusion-screener',
|
|
89
|
+
'license-verifier',
|
|
90
|
+
'gleif-ownership-graph',
|
|
91
|
+
'fdic-ncua-health-rollup',
|
|
92
|
+
'fdic-structure-change-delta-monitor',
|
|
93
|
+
'ria-registration-delta-monitor',
|
|
94
|
+
'pcaob-auditor-engagement-monitor',
|
|
95
|
+
'reg-cf-lifecycle-monitor',
|
|
96
|
+
'reg-a-plus-lifecycle-monitor',
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const PRESET_NAMES = Object.keys(PRESETS);
|
|
102
|
+
|
|
103
|
+
/** Agents choose badly past ~20 tools; a preset plus its three meta tools must stay under this. */
|
|
104
|
+
export const MAX_PRESET_TOOLS = 15;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Resolve a preset name to its definition, or an explicit error. Never guesses:
|
|
108
|
+
* "phase1" does not become "phase1-esa", because a server that silently started
|
|
109
|
+
* with the wrong shelf would be the quiet failure this project exists to avoid.
|
|
110
|
+
*/
|
|
111
|
+
export function resolvePreset(name) {
|
|
112
|
+
if (name === undefined || name === null || String(name).trim() === '') return { ok: true, preset: null, name: null };
|
|
113
|
+
const key = String(name).trim();
|
|
114
|
+
const preset = PRESETS[key];
|
|
115
|
+
if (!preset) {
|
|
116
|
+
return {
|
|
117
|
+
ok: false,
|
|
118
|
+
error: `Unknown preset "${key}". Known presets: ${PRESET_NAMES.join(', ')}. `
|
|
119
|
+
+ `Pass --preset <name> or set ${PRESET_ENV}; omit both for the full catalog.`,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return { ok: true, preset, name: key };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Parse the CLI + environment into { presetName, listPresets }. The flag wins
|
|
127
|
+
* over the environment variable, and an empty value is an error rather than
|
|
128
|
+
* "no preset" — `--preset` with nothing after it is a typo, not a choice.
|
|
129
|
+
*/
|
|
130
|
+
export function parseCliArgs(argv, env) {
|
|
131
|
+
const args = Array.isArray(argv) ? argv : [];
|
|
132
|
+
const out = { presetName: null, listPresets: false, errors: [] };
|
|
133
|
+
for (let i = 0; i < args.length; i++) {
|
|
134
|
+
const a = args[i];
|
|
135
|
+
if (a === '--list-presets') { out.listPresets = true; continue; }
|
|
136
|
+
if (a === '--preset') {
|
|
137
|
+
const v = args[i + 1];
|
|
138
|
+
if (v === undefined || v.startsWith('--')) { out.errors.push('--preset requires a value'); continue; }
|
|
139
|
+
out.presetName = v; i++; continue;
|
|
140
|
+
}
|
|
141
|
+
if (a.startsWith('--preset=')) {
|
|
142
|
+
const v = a.slice('--preset='.length);
|
|
143
|
+
if (!v) { out.errors.push('--preset requires a value'); continue; }
|
|
144
|
+
out.presetName = v; continue;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (out.presetName === null && env && typeof env[PRESET_ENV] === 'string' && env[PRESET_ENV].trim() !== '') {
|
|
148
|
+
out.presetName = env[PRESET_ENV].trim();
|
|
149
|
+
}
|
|
150
|
+
return out;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** One line per preset, for --list-presets and for the README generator. */
|
|
154
|
+
export function describePresets() {
|
|
155
|
+
return PRESET_NAMES.map(n => ({
|
|
156
|
+
name: n,
|
|
157
|
+
serverName: PRESETS[n].serverName,
|
|
158
|
+
title: PRESETS[n].title,
|
|
159
|
+
toolCount: PRESETS[n].tools.length,
|
|
160
|
+
tools: [...PRESETS[n].tools],
|
|
161
|
+
}));
|
|
162
|
+
}
|
package/src/tools.js
CHANGED
|
@@ -59,11 +59,37 @@ export function toolNameFor(slug) {
|
|
|
59
59
|
return slug;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Build the tool index. With no options this is the full catalog fronted by
|
|
64
|
+
* FEATURED — byte-identical to every release before presets existed.
|
|
65
|
+
*
|
|
66
|
+
* With a preset, the WHOLE index is restricted: `actors` (what search,
|
|
67
|
+
* describe and run can reach) is filtered to the preset's tools, and
|
|
68
|
+
* `featured` becomes the preset's own list. A preset tool that is not in the
|
|
69
|
+
* catalog is a hard error, not a warning — a scoped server advertising a tool
|
|
70
|
+
* that does not exist is precisely the defect a stderr line would hide.
|
|
71
|
+
*/
|
|
72
|
+
export function indexCatalog(catalog, options = {}) {
|
|
73
|
+
const all = catalog.actors || [];
|
|
74
|
+
const preset = options.preset || null;
|
|
75
|
+
const presetName = options.presetName || null;
|
|
76
|
+
if (preset) {
|
|
77
|
+
const missing = preset.tools.filter(s => !all.some(a => a.slug === s));
|
|
78
|
+
if (missing.length) {
|
|
79
|
+
throw new Error(`preset "${presetName}" names tools that are not in the bundled catalog: ${missing.join(', ')}. `
|
|
80
|
+
+ 'Regenerate the catalog or fix the preset before starting a server that would advertise them.');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const allSlugs = new Set(all.map(a => a.slug));
|
|
84
|
+
const featured = preset ? [...preset.tools] : [...FEATURED];
|
|
85
|
+
const keep = preset ? new Set(preset.tools) : null;
|
|
86
|
+
const actors = keep ? all.filter(a => keep.has(a.slug)) : all;
|
|
64
87
|
const bySlug = new Map(actors.map(a => [a.slug, a]));
|
|
65
|
-
const missingFeatured =
|
|
66
|
-
|
|
88
|
+
const missingFeatured = featured.filter(s => !bySlug.has(s));
|
|
89
|
+
const scopeNote = preset
|
|
90
|
+
? ` This server is scoped to the "${presetName}" preset (${actors.length} of ${all.length} catalog tools); start gov-data-mcp without --preset for the full catalog.`
|
|
91
|
+
: '';
|
|
92
|
+
return { actors, bySlug, missingFeatured, featured, presetName, scopeNote, catalogTotal: all.length, allSlugs };
|
|
67
93
|
}
|
|
68
94
|
|
|
69
95
|
function truncate(s, n) {
|
|
@@ -151,10 +177,26 @@ export const ROUTING = {
|
|
|
151
177
|
+ 'It is NOT a property contamination screen — for soil and groundwater records at a site use epa-contaminated-site-screener.',
|
|
152
178
|
};
|
|
153
179
|
|
|
180
|
+
/**
|
|
181
|
+
* A routing note is only shown when every tool it points at is reachable on
|
|
182
|
+
* THIS server. Under a preset, a note that sends the agent to a tool outside
|
|
183
|
+
* the preset would be a dead end dressed as advice, so the note is dropped
|
|
184
|
+
* rather than edited — a half-note that names a missing tool is worse than none.
|
|
185
|
+
*/
|
|
186
|
+
export function routingNoteFor(index, slug) {
|
|
187
|
+
const note = ROUTING[slug];
|
|
188
|
+
if (!note) return '';
|
|
189
|
+
// Only tokens that are catalog slugs count as references; hyphenated prose is not a tool.
|
|
190
|
+
const isSlug = (r) => index.allSlugs ? index.allSlugs.has(r) : index.bySlug.has(r);
|
|
191
|
+
const referenced = (note.match(/[a-z0-9]+(?:-[a-z0-9]+){2,}/g) || []).filter(r => r !== slug && isSlug(r));
|
|
192
|
+
return referenced.every(r => index.bySlug.has(r)) ? ` ${note}` : '';
|
|
193
|
+
}
|
|
194
|
+
|
|
154
195
|
export function featuredToolDefinitions(index) {
|
|
155
|
-
|
|
196
|
+
const featured = index.featured || FEATURED;
|
|
197
|
+
return featured.filter(s => index.bySlug.has(s)).map(slug => {
|
|
156
198
|
const a = index.bySlug.get(slug);
|
|
157
|
-
const routing =
|
|
199
|
+
const routing = routingNoteFor(index, slug);
|
|
158
200
|
return {
|
|
159
201
|
name: toolNameFor(slug),
|
|
160
202
|
description: `${a.title}. ${truncate(a.description, 400)}${routing} Reads live from the official government source. ${costNote(a.pricing)} Store page: ${a.storeUrl}`,
|
|
@@ -169,7 +211,7 @@ export function metaToolDefinitions(index) {
|
|
|
169
211
|
return [
|
|
170
212
|
{
|
|
171
213
|
name: META_TOOLS.SEARCH,
|
|
172
|
-
description: `Search the full catalog of ${n} US government data tools by keyword, agency, or topic (e.g. "wetlands", "FDIC", "flood", "drone airspace", "business licenses"). Returns matching tool names with descriptions. Use this first when the task is not covered by one of the dedicated tools above. FREE: reads a catalog bundled with this server — no network call, no run, nothing charged.`,
|
|
214
|
+
description: `Search the full catalog of ${n} US government data tools by keyword, agency, or topic (e.g. "wetlands", "FDIC", "flood", "drone airspace", "business licenses"). Returns matching tool names with descriptions. Use this first when the task is not covered by one of the dedicated tools above.${index.scopeNote || ''} FREE: reads a catalog bundled with this server — no network call, no run, nothing charged.`,
|
|
173
215
|
annotations: { title: 'Search the government data catalog', ...ANNOTATIONS.CATALOG_LOCAL },
|
|
174
216
|
inputSchema: {
|
|
175
217
|
type: 'object',
|
|
@@ -246,7 +288,7 @@ export function describeTool(index, name) {
|
|
|
246
288
|
const near = searchCatalog(index, String(name || '').replace(/[-_]/g, ' '), 5).map(r => r.tool);
|
|
247
289
|
return {
|
|
248
290
|
ok: false,
|
|
249
|
-
error: `No tool named "${name}" in this catalog.${near.length ? ` Closest matches: ${near.join(', ')}.` : ''} Use ${META_TOOLS.SEARCH} to find one. This is a lookup miss, not a statement about the underlying data
|
|
291
|
+
error: `No tool named "${name}" in this catalog.${near.length ? ` Closest matches: ${near.join(', ')}.` : ''} Use ${META_TOOLS.SEARCH} to find one. This is a lookup miss, not a statement about the underlying data.${index.scopeNote || ''}`,
|
|
250
292
|
};
|
|
251
293
|
}
|
|
252
294
|
return {
|
|
@@ -271,7 +313,7 @@ export function resolveCall(index, toolName, args) {
|
|
|
271
313
|
if (!slug) return { ok: false, error: `${META_TOOLS.RUN} requires a "tool" argument naming which catalog tool to run.` };
|
|
272
314
|
if (!index.bySlug.has(slug)) {
|
|
273
315
|
const near = searchCatalog(index, String(slug).replace(/[-_]/g, ' '), 5).map(r => r.tool);
|
|
274
|
-
return { ok: false, error: `No tool named "${slug}" in this catalog.${near.length ? ` Closest matches: ${near.join(', ')}.` : ''}` };
|
|
316
|
+
return { ok: false, error: `No tool named "${slug}" in this catalog.${near.length ? ` Closest matches: ${near.join(', ')}.` : ''}${index.scopeNote || ''}` };
|
|
275
317
|
}
|
|
276
318
|
return { ok: true, slug, input: (args && args.input) || {}, maxItems: args && args.maxItems };
|
|
277
319
|
}
|