About fcc-broadband-mcp-server
fcc-broadband-mcp-server supports broadband coverage and digital-divide research with FCC data for US geographies. It combines Form 477, Broadband Data Collection, and the FCC Geo API for geocoding, coverage queries, and area comparisons, alongside a research prompt and resources.
Key features
- 01Convert coordinates to census blocks
- 02Find providers and speeds by block
- 03Summarize and compare area coverage
- 04Rank areas by unserved population
- 05Search providers and coverage profiles
- 06List filing periods and download files
Use cases
- 01Assess broadband availability at a location
- 02Compare coverage across states or counties
- 03Find areas with larger unserved populations
- 04Prepare data for BEAD and equity research
MCP support
The MCP server exposes 10 tools, 2 resources, and a digital-divide analysis prompt to clients. Form 477 queries require no credentials; the BDC download-list tool requires configured credentials.
Configuration
Remote servers need no local install. Pick your client, then copy the config or install in one click.
https://fcc-broadband.caseyjhand.com/mcpclaude mcp add --transport http cyanheads-fcc-broadband https://fcc-broadband.caseyjhand.com/mcp{"mcpServers":{"cyanheads-fcc-broadband":{"type":"http","url":"https://fcc-broadband.caseyjhand.com/mcp"}}}Open in Cursor{"servers":{"cyanheads-fcc-broadband":{"type":"http","url":"https://fcc-broadband.caseyjhand.com/mcp"}}}Open in VS Code{"mcpServers":{"cyanheads-fcc-broadband":{"type":"http","url":"https://fcc-broadband.caseyjhand.com/mcp"}}}{"mcpServers":{"cyanheads-fcc-broadband":{"serverUrl":"https://fcc-broadband.caseyjhand.com/mcp"}}}Run commands in a terminal; paste JSON into the client’s MCP config and restart. Servers that need sign-in will prompt on first connect.
Tools
9| Parameter | Type | Required | Description |
|---|---|---|---|
| latitude | number | Yes | Latitude of the location in decimal degrees (e.g., 47.6062 for Seattle, WA). Must be within the continental US, Alaska, Hawaii, or US territories. |
| longitude | number | Yes | Longitude of the location in decimal degrees (e.g., -122.3321 for Seattle, WA). Negative for western hemisphere. |
Details
From the project README@cyanheads/fcc-broadband-mcp-server
Access FCC broadband availability, coverage analysis, and digital divide data for US geographies and census blocks via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://fcc-broadband.caseyjhand.com/mcp
Overview
FCC broadband data from Form 477 (June 2015 – June 2021) and the Broadband Data Collection (June 2022 onward). Geocode coordinates to census blocks, look up the ISPs and advertised speeds at a block, and summarize, compare, or rank geographies by unserved population for BEAD and equity research.
Tools
| Tool | Description |
|---|---|
fcc_geocode_block | Convert a lat/lon coordinate to a 2010-vintage census block FIPS code, with county and state identifiers |
fcc_search_availability | List the providers and advertised speeds at a census block, filtered by technology and speed |
fcc_search_geographies | Find place and CBSA GEOIDs by name for coverage queries |
fcc_get_coverage_summary | Population by provider count for one geography, split by urban/rural and tribal/non-tribal |
fcc_compare_areas | Rank coverage across several geographies of the same type, worst first |
fcc_find_underserved | Rank the most underserved areas in a state or nationwide by unserved population |
fcc_search_providers | Search holding companies by name, state, and technology; returns hoconum identifiers |
fcc_get_provider | National coverage profile for one holding company: technologies and population per speed tier |
fcc_list_filing_periods | List data vintages: Form 477 filing periods and BDC as-of dates |
fcc_list_downloads | List BDC bulk data files for one as-of date |
Resources
| Resource | Description |
|---|---|
fcc-broadband://geography/{type}/{id}/summary | Coverage summary for one geography at 25 Mbps |
fcc-broadband://providers/list/{offset} | One page of the Form 477 holding-company directory, 25 entries per page |
Resource data is also reachable through tools: fcc_get_coverage_summary for geographies, fcc_search_providers for holding companies.
Prompts
| Prompt | Description |
|---|---|
broadband_equity_analysis | Structure a digital divide analysis that chains FCC coverage with Census and BLS data |
Capability reference
fcc_geocode_block tool
latitudeandlongitudein decimal degrees, resolved against 2010 census boundaries through the FCC Geo API- Returns
blockFips(15 digits, ready forfcc_search_availability),censusVintage,countyFips,countyName,stateFips,stateCode, andstateName; coordinates over water or outside US coverage fail asblock_not_found. Structured FCC backend faults fail asgeo_backend_unavailablewith guidance to retry the same coordinates later
fcc_search_availability tool
block_fips(15 digits, 2010 vintage) is required;tech_filter(Form 477 technology codes),min_speed_down(Mbps), andconsumer(trueconsumer,falsebusiness) narrow the rows- One row per offering with
hoconum,techCode/techLabel,maxDownloadMbps,maxUploadMbps,consumer, andbusiness, plustotalProviderscounting distinct holding companies; an unfiltered block with no providers fails asblock_not_found, while a filtered query that matches nothing returns an empty list with anotice
fcc_search_geographies tool
- Required nonblank
namematches a case-insensitive literal substring; optionalgeography_typeisplaceorcbsa,limitdefaults to 20 (max 100), andoffsetstarts at 0 - Returns distinct
{ geography_type, geography_id, name }matches in stable name/type/GEOID order, pluscount,offset, andnextOffsetonly when more matches remain. Empty and past-end pages carry guidance; no total count is computed - Uses the live FCC lookup with
year='2021'even when the mirror is enabled. Include a location qualifier innameto narrow matches; CBSA codes do not establish state membership. Pass the selected type and GEOID tofcc_get_coverage_summary
fcc_get_coverage_summary tool
geography_typeis one ofnation,state,county,cd,place,cbsa,tribal;geography_idis required for every type butnation;urban_rural_filter(all/R/U) andtribal_filter(all/T/N) narrow the population- Returns
populationby provider count (noCoverage,oneProvider,twoProviders,threeOrMore,total),coveragePct,unservedPct,competitivePct, and a per-segmentbreakdown; fails asgeography_not_found,invalid_geography_combo, orinvalid_geography_id_shape - National coverage is named
United Stateslocally and retainsgeography.id: "0"; it needs no geography-name lookup
fcc_compare_areas tool
- 2 to 50
geography_idsof onegeography_type(every type butnation), orcompare_all_states: truefor the 50 states plus DC;sort_byisunserved_pct(default),unserved_pop,coverage_pct, orcompetitive_pct - Every sort ranks worst first, so
rank1 is the area most in need; rows carryid,namewhen resolved, the provider-count populations, and all three percentages. Fails asmissing_geography_ids,invalid_all_states_combo,invalid_geography_id_shape, orno_data_found
fcc_find_underserved tool
state(USPS state or territory code) scopes the search, otherwise it runs nationwide;geography_typeiscounty(default),cd,place, orcbsa;urban_rural_filterdefaults toR,min_unserved_popto 1, andlimitto 20 (max 100)- Areas ranked by
noCoverage, each withrank,id,name,oneProvider,total,unservedPct, andcoveragePct;totalFoundcounts matches before the limit. An unrecognizedstatefails asunknown_state, and filters that match nothing return an empty ranking with anotice
fcc_search_providers tool
name_search(case-insensitive partial name),state, andtech_filterare all optional and must hold on the same filing;limitdefaults to 50 (max 200)- Deduplicated holding companies with
hoconum,holdingCompanyName, and nationalstatesServed/techCodesthat the filters never narrow. No match returns an empty list with anotice; a live search over its 30-second budget fails aslive_search_timeout - Against the live API,
scanTruncated: truemarks the list as a sample andtotalCountis omitted; a full-corpus mirror (FCC_MIRROR_ENABLED=true) returns every match
fcc_get_provider tool
hoconum(digits only) fromfcc_search_providersor the providers directory resource- Returns
techCodes/techLabelsandspeedTierPopulation, which counts each person once and omits empty tiers; business-only carriers come back with both lists empty. Fails asprovider_not_found, orlive_provider_timeoutpast the 30-second budget
fcc_list_filing_periods tool
- Always returns the Form 477 periods;
include_bdc: trueadds BDC as-of dates when credentials are configured periodsnewest first, each withasOfDateandsource(form477orbdc), plusform477Count,bdcCount, andhasBdcCredentials; missing credentials leavebdcCountat 0 rather than raising an error
fcc_list_downloads tool
as_of_date(YYYY-MM-DD) is required; filter bydata_type(availabilitydefault, orchallenge),category(Summary,State,Provider),technology_type(Fixed Broadband,Mobile Broadband,Mobile Voice),state, andprovider_name;limitdefaults to 50 (max 200), paged withoffset- Returns file metadata and a
downloadUrlper file, not file contents;totalFilescounts every match andnextOffsetis omitted on the last page. Fails asinvalid_as_of_datefor an unsupported date - Available to MCP clients only when both BDC credentials are configured at startup. Otherwise the HTTP landing page retains its disabled card and setup guidance
fcc-broadband://geography/{type}/{id}/summary resource
typetakes the sevenfcc_get_coverage_summarygeography types;idis a FIPS GEOID checked for digit count,0fornation- Fixed at 25 Mbps and
acfosw; returnspopulation, the three percentages, andsegmentsasapplication/json. Usefcc_get_coverage_summaryfor other thresholds or filters
fcc-broadband://providers/list/{offset} resource
offsetpages the directory 25 entries at a time inhoconumorder; start at0and follownextOffset- Entries carry
hoconumand, when resolved,holdingCompanyName; each page reportstotalandcount. To find one company by name, usefcc_search_providers
broadband_equity_analysis prompt
- Arguments:
region(free text) andfocus(underserved,rural,tribal, orall), both required - Returns one user message laying out a five-step analysis: baseline coverage, focus area, demographic cross-reference, provider landscape, and BEAD context
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
FCC-specific:
- Three FCC sources, all US government public-domain data: Form 477 on FCC Open Data (Socrata), the BDC Public Data API, and the FCC Geo API
- Every Form 477 tool and resource works without credentials and reads the June 2021 filing, the last one; BDC data is exposed only as bulk-file manifests.
fcc_list_downloadsis advertised to MCP clients only when bothFCC_BDC_USERNAMEandFCC_BDC_HASH_VALUEare configured - The area tools share one vocabulary:
tech_filterletters (acfoswfor every technology, the default;aDSL,ccable,ffiber,oother,ssatellite,wfixed wireless) andspeed_downtiers (0.2,4,10,25,100,250,1000Mbps; default25, and100is the BEAD threshold) - Coverage analysis reads the pre-aggregated Area Table (
xvwq-qtaj), not the block-level deployment table, so state- and county-scale queries stay fast - Optional local Form 477 mirror (
FCC_MIRROR_ENABLED=true) serves queries from SQLite, falling back to the live API for anything not ingested
Agent-friendly output:
- Filter echo: search, summary, and ranking tools return
appliedFilters, and every Form 477 result carriesdataVintage - Partial results say so:
scanTruncatedandscanRowCapflag a result drawn from a capped upstream scan (fcc_search_providers,fcc_find_underserved), and an empty match returns anoticeinstead of an error - Typed failures: reasons such as
block_not_found,invalid_geography_id_shape, andcredentials_required, each with a recovery hint
Getting started
Public Hosted Instance
A public instance is available at https://fcc-broadband.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"fcc-broadband-mcp-server": {
"type": "streamable-http",
"url": "https://fcc-broadband.caseyjhand.com/mcp"
}
}
}
Self-Hosted / Local
Add the following to your MCP client configuration file.
{
"mcpServers": {
"fcc-broadband-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/fcc-broadband-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"fcc-broadband-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/fcc-broadband-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+).
- Optional: FCC BDC credentials for
fcc_list_downloadsand BDC filing periods. Generate a token at broadbandmap.fcc.gov under "Manage API Access". - Optional: a Socrata app token (
FCC_OPENDATA_APP_TOKEN) for higher Form 477 rate limits.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/fcc-broadband-mcp-server.git
- Navigate into the directory:
cd fcc-broadband-mcp-server
- Install dependencies:
bun install
- Configure environment:
cp .env.example .env
# edit .env and set FCC_BDC_USERNAME, FCC_BDC_HASH_VALUE, and FCC_OPENDATA_APP_TOKEN as needed
Configuration
| Variable | Description | Default |
|---|---|---|
FCC_BDC_USERNAME | FCC account email for the BDC API. Needed by fcc_list_downloads and for BDC dates in fcc_list_filing_periods. | none |
FCC_BDC_HASH_VALUE | API token hash from broadbandmap.fcc.gov "Manage API Access". Pairs with FCC_BDC_USERNAME. | none |
FCC_OPENDATA_APP_TOKEN | Socrata app token; raises FCC Open Data rate limits. | none |
FCC_MIRROR_ENABLED | Serve Form 477 queries from the local SQLite mirror where its coverage allows. | false |
FCC_MIRROR_PATH | Directory holding the mirror SQLite files. | data/fcc-mirror |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | HTTP server port. | 3010 |
MCP_SESSION_MODE | HTTP session mode: stateless, stateful, or auto. | stateless |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.). | info |
LOGS_DIR | Directory for log files (Node.js only). | <project-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1. | in-memory |
OTEL_ENABLED | Enable OpenTelemetry. | false |
See .env.example for the full list of optional overrides.
BDC credentials can come from the process environment or .env; process values take precedence. Empty, whitespace-only, and unsubstituted placeholder values count as absent. Restart after configuring both credentials to enable fcc_list_downloads; Form 477 filing periods remain available without them.
Running the server
Local development
-
Build and run:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:http -
Run checks and tests:
bun run devcheck # Lint, format, typecheck, security bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker build -t fcc-broadband-mcp-server .
docker run --rm -p 3010:3010 fcc-broadband-mcp-server
The Dockerfile defaults to HTTP transport and stateless session mode, logging to /var/log/fcc-broadband-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them. The image also ships the mirror scripts and a writable data/ directory.
Local Form 477 mirror
Form 477 is frozen at the June 2021 filing, so it can be ingested once into a local SQLite index. The mirror is off by default, and the full corpus is about 9 GB of source data and takes hours to ingest, so the bootstrap can be scoped to the states you query:
bun run mirror:init -- --states 11,53 # specific states by 2-digit FIPS (11 = DC, 53 = WA)
bun run mirror:init -- --full # the whole corpus
bun run mirror:verify # coverage, row counts, SQLite integrity
Then set FCC_MIRROR_ENABLED=true. In Docker, run the same scripts with docker exec <container> bun run mirror:init -- --states 11,53. Run them from a source checkout or the image: the scripts import through the @/ path alias, which an npm install does not map.
- Block and geography lookups serve from the mirror once the queried state is fully ingested; anything else falls back to the live API.
fcc_search_geographiesalways uses the live lookup: the mirror does not retain its year column.fcc_search_providers,fcc_get_provider, and geographies with no state in their GEOID (cbsa,tribal,nation) serve from the mirror only after a--fullingest.- Mirror name search matches word prefixes (
comcfinds "Comcast") where the live API matches any substring (mcast), so a mid-word fragment can return fewer results. - The ingest is idempotent and resumes an interrupted run from its saved cursor. Set
FCC_OPENDATA_APP_TOKENfirst for a full ingest. Bun uses the built-inbun:sqlite; Node.js needs the optionalbetter-sqlite3peer dependency.
Project structure
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools, resources, and prompts and inits services. |
src/config | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools | Tool definitions (*.tool.ts). Ten tools across FCC Open Data, the BDC API, and the Geo API. |
src/mcp-server/resources | Resource definitions (*.resource.ts). Geography summary and provider directory. |
src/mcp-server/prompts | Prompt definitions (*.prompt.ts). Broadband equity analysis prompt. |
src/services/open-data | FCC Open Data (Socrata) service for Form 477 deployment, area, and provider tables; mirror/ holds the local SQLite mirror. |
src/services/bdc-api | BDC Public Data API service — authenticated filing periods and download manifests. |
src/services/geo-api | FCC Geo API service — lat/lon to census block FIPS. |
scripts/ | Build, devcheck, and packaging scripts, plus fcc-mirror-init.ts / fcc-mirror-verify.ts. |
tests/ | Unit and integration tests mirroring src/. |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storage - Register new tools and resources via the barrels in
src/mcp-server/*/definitions/index.ts - Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
- Socrata returns every field as a string, so parse counts and speeds (
has_0–has_3more,maxaddown,maxadup) explicitly
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
License
Apache-2.0 — see LICENSE for details.
Comments
New to MCP?
From what the protocol is to installing your first server, these answers cover most first questions.
An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.