About fcc-spectrum-mcp-server
fcc-spectrum-mcp-server lets spectrum researchers, licensees, and analysts search US FCC radio-license records from a local index. It supports license and site lookups, frequency searches, and reference-code decoding; full-power broadcast and satellite earth stations are excluded.
Key features
- 01Search licenses and spectrum leases
- 02Read license sites and technical records
- 03Find nearby licensed transmitters
- 04Search assignments by frequency band
- 05Decode ULS reference codes
Use cases
- 01Check license details for a callsign
- 02Locate licensed sites near coordinates
- 03Identify licenses covering a frequency
- 04Interpret FCC service and status codes
MCP support
Exposes five tools and two resources to MCP clients over STDIO or Streamable HTTP. Queries use a local SQLite index; network access is needed to build and refresh that index.
Configuration
Remote servers need no local install. Pick your client, then copy the config or install in one click.
https://fcc-spectrum.caseyjhand.com/mcpclaude mcp add --transport http cyanheads-fcc-spectrum https://fcc-spectrum.caseyjhand.com/mcp{"mcpServers":{"cyanheads-fcc-spectrum":{"type":"http","url":"https://fcc-spectrum.caseyjhand.com/mcp"}}}Open in Cursor{"servers":{"cyanheads-fcc-spectrum":{"type":"http","url":"https://fcc-spectrum.caseyjhand.com/mcp"}}}Open in VS Code{"mcpServers":{"cyanheads-fcc-spectrum":{"type":"http","url":"https://fcc-spectrum.caseyjhand.com/mcp"}}}{"mcpServers":{"cyanheads-fcc-spectrum":{"serverUrl":"https://fcc-spectrum.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
5| Parameter | Type | Required | Description |
|---|---|---|---|
| frn | string | No | FCC Registration Number, up to 10 digits; spaces and hyphens are removed and it is left-padded with zeros. |
| limit | integer | No | Positive integer records per page; values above 100 are clamped to 100 with a notice. |
| state | enum | No | Licensee mailing state: a two-letter USPS code (incl. DC, PR, VI, GU, AS, MP) or a full state name. This is the licensee's address, not the site location.AL | AK | AZ | AR | CA | CO | CT | DE | DC | FL | GA | HI | ID | IL | IN | IA | KS | KY | LA | ME | MD | MA | MI | MN | MS | MO | MT | NE | NV | NH | NJ | NM | NY | NC | ND | OH | OK | OR | PA | RI | SC | SD | TN | TX | UT | VT | VA | WA | WV | WI | WY | AS | GU | MP | PR | VI |
| cursor | string | No | nextCursor from the previous page of the same search; omit for the first page. |
| status | enum | No | License status: A active, L pending legal, X term pending, E expired, C canceled, T terminated, P parent station canceled, or "any" for every status. Defaults to A.A | C | E | L | P | T | X | any |
| callsign | string | No | Exact callsign or lease ID, e.g. "KNKA123" or "L000012345". Case, spaces, and one trailing portable suffix ("/4") are normalized. ULS reuses callsigns, so several records can match. |
| licensee | string | No | Licensee name words, with at least one letter or digit; every word must match the start of a word in the name, in any order (e.g. "verizon wireless"). A word joined by - or & ("T-Mobile", "AT&T") matches its pieces side by side. |
| market_code | string | No | Market code of a geographic-area license, matched exactly, e.g. "PEA016", "CMA020", "D06037", or "NW" (nationwide); results carry it as marketCode. Case, spaces, and hyphens are ignored, and the digits are left-padded with zeros ("pea16" reads as PEA016). |
| radio_service | string | No | Two-character radio service code, e.g. "CD" (paging) or "BR" (BRS); see fcc_spectrum_list_reference topic "radio_services". |
Details
From the project README@cyanheads/fcc-spectrum-mcp-server
Search FCC radio licenses, find nearby licensed sites, and see who is licensed on a frequency via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://fcc-spectrum.caseyjhand.com/mcp
Overview
US radio spectrum licensing from the FCC's Universal Licensing System, searchable offline. Look up a callsign, licensee, or market; read a license's sites, antennas, frequencies, and microwave paths; find transmitters near a point; and see who's authorized on any frequency or band. Covers land mobile, microwave, cellular, paging, amateur, and more; full-power broadcast stations and satellite earth stations aren't included. No API key required.
Tools
| Tool | Description |
|---|---|
fcc_spectrum_search_licenses | Search licenses and spectrum leases by callsign, licensee name, FRN, market code, radio service, status, or licensee state. |
fcc_spectrum_get_license | Read one license or lease in full by callsign or USI: licensee, status and dates, locations, antennas, frequencies with emissions, microwave paths, market blocks, and lease links. |
fcc_spectrum_find_transmitters | Find FCC-licensed sites within a radius of a coordinate, nearest first, with their filed roles and authorized frequencies. |
fcc_spectrum_search_frequencies | Find site assignments and market-area spectrum blocks whose occupied band overlaps a frequency or band. |
fcc_spectrum_list_reference | Decode ULS codes (radio services, station classes, statuses, location and antenna types, applicant types, operator classes) and report index coverage and freshness. |
Resources
| Resource | Description |
|---|---|
fcc-spectrum://license/{callsign} | One license or lease by callsign as JSON — the first page fcc_spectrum_get_license returns. |
skill://fcc-spectrum-guide/SKILL.md | Workflow guidance for ULS investigations: completeness checks, identifiers, shared sites, market geography, leases, and microwave paths. |
License records are also reachable via fcc_spectrum_get_license. The investigation guide is available to clients through resources/list and resources/read.
Capability reference
fcc_spectrum_search_licenses tool
- Filters:
callsign,licensee(every word must match the start of a word in the name),frn,market_code(a geographic-area license's market, matched exactly:PEA016,CMA020,D06037,NW;pea16reads asPEA016),radio_service, andstate(the licensee's mailing state) — at least one required;statusnarrows toA(default),C,E,L,P,T,X, orany - Positive integer
limit(default 25, capped at 100) with cursor paging; each row carries theusito pass tofcc_spectrum_get_license, plusisLease,licenseeRedacted, and location and frequency counts - Typed errors:
no_criteria,unknown_radio_service,service_not_indexed,invalid_cursor,index_not_ready
fcc_spectrum_get_license tool
- Exactly one of
callsignorusi(identifier_requiredotherwise); a callsign shared by several records returns the active one, else the most recent, and lists the others inotherCallsignRecords - Pages large records: whole locations up to 50 sites, 100 antennas, and 100 microwave paths (a location larger than that is listed alone), up to 100 leases, and
max_frequenciesfrequency rows (positive integer, default 100, capped at 1000) per call;nextLocationOffsetandnextLeaseOffsetfeedlocation_offsetandlease_offseton the next call - Microwave paths (FCC PA records) are listed in
pathsunder the antenna that transmits them: path number, type, passive flag, and receiving callsign as filed, and areceiveend with its location and antenna numbers, coordinates when the license files exactly one valid site under the receive number,siteCountwhen it files none or several, andantennaFiled: falsewhen no antenna record matches.pathTotalcounts the record's paths across all locations (absent on an index built before paths were indexed, untilmirror:initrebuilds it), and when more locations follow, the notice reports the paths listed against it location_numberstarts the locations at a site'slocationNumberfromfcc_spectrum_find_transmittersorfcc_spectrum_search_frequencies; combined with a nonzerolocation_offsetit fails (location_start_conflict)- A miss returns
found: falsewithguidanceand up to 5 callsign-prefixcandidates, not an error;technicalRetained: falsemarks a record whose status keeps no sites or frequencies
fcc_spectrum_find_transmitters tool
latitude/longitudeas decimal degrees or DMS strings,radius_km0.1–100 (default 5); optionalfrequency_low/frequency_highinunit(kHz,MHzdefault,GHz),radio_service,location_type(one ULS location type code, case-insensitive:Fkeeps fixed sites only,Mmobile andTtemporary-fixed areas), andstatus(Adefault,L,X, oranyfor all three)- Sites nearest first, positive integer
limit(default 25, capped at 100) with cursor paging; each site lists up tomax_frequencies_per_sitefrequencies (positive integer, default 10, capped at 50), withfrequencyCountcarrying the full count - Each site carries
locationTypeCode,locationTypeLabel,radiusKm,locationClassCode, andlocationClassLabelwhen filed; a mobile or temporary-fixed area is returned at its filed center, anddistanceKmmeasures to that center.location_class(case-insensitiveC,L,P,R, orT) keeps one FCC class; results describe authorization, not actual on-air activity - Typed errors:
invalid_frequency_range,unknown_radio_service,service_not_indexed,invalid_cursor,index_not_ready
fcc_spectrum_search_frequencies tool
frequency_lowrequired,frequency_highoptional, inunit; a site assignment matches when its occupied band (widened by its emission bandwidth) overlaps the query, a market block when its filed edges do;kindissite,market, orboth(default)- Narrow by
state,radio_service,licensee,frn,market_code, andstatus(Adefault,L,X,any); positive integerlimit(default 50, capped at 200) with cursor paging, frequency ascending; each row'skindsays whether it is a site assignment or a market block market_codeandfrnfilter site rows and market rows alike; anfrnsearch returns individual licensees redacted. Single-site rows carrylocationTypeCode,locationTypeLabel,radiusKm,locationClassCode, andlocationClassLabelwhen filed; shared-number rows and market blocks omit them- Typed errors:
invalid_frequency_range,unknown_radio_service,service_not_indexed,invalid_cursor,index_not_ready
fcc_spectrum_list_reference tool
topic:radio_services,station_classes,license_statuses,location_types,antenna_types,applicant_types,operator_classes, orcoverage;filternarrows radio services and station classes to entries containing every token in their code and label, with case/accent folding and punctuation separating tokens- A searchable
filtermust contain an ASCII letter or digit (invalid_filterotherwise); blank means unset. Other topics ignore the filter and say so - Decode a station class with
{"topic":"station_classes","filter":"FXO"}(FXOis Operational Fixed,FB2Mobile Relay,MOMobile). Labels come from a bundled 266-code table of the FCC'suls_code_definitions_20240718.txt(archived copy); an unmapped code returns no entries. These are licensed categories, not actual on-air activity coveragereportsindex.status(none,building,ready), per-group record, site, and frequency counts with snapshot times, and whether redaction is on; it works before the index is built.index.antennaCoverageIncomplete: truemarks an older index that dropped unnumbered antennas, andindex.pathCoverageIncomplete: trueone built before microwave paths were indexed;bun run mirror:initrebuilds either
fcc-spectrum://license/{callsign} resource
- The first page of
fcc_spectrum_get_license(up to 100 frequency rows, with its microwave paths) asapplication/json, withdataAsOf, totals, and anoticenaming the tool call that reads the rest; cached 1 hour - Typed errors:
index_not_ready,license_not_found
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 ULS-specific:
- Keyless and local at request time — every query reads the SQLite index; network access is needed only to build and refresh it
- Occupied-band frequency matching — each assignment's band is widened by the bandwidth parsed from its emission designators, so a query near a wide channel's edge still finds it
- Spectrum leases are first-class records —
isLeasemarks them, the licensee shown is the lessee, and lease links are listed in both directions - Site state is derived from coordinates when the filing leaves it blank (common for microwave and BRS/EBS), and flagged
stateFromCoordinates - Individual licensees are redacted by default, and contact details are never ingested — see Individual-licensee redaction
Agent-friendly output:
- Freshness and filter echo — every data response carries
dataAsOf, and search tools echoappliedFilters - Truncation disclosure —
truncated,shown,cap, andtotalCountplus anoticenaming the next call, so a partial page is never read as the whole; output budgets above a ceiling clamp to it with a notice naming requested and effective values - Absent stays absent — fields ULS leaves blank are omitted, coordinates that fail validation are kept as DMS text (
coordinatesDms), and all-zero placeholder coordinates are dropped - Discriminated output —
found,kind,isLease,licenseeRedacted, andtechnicalRetainedlet callers branch on data, not string parsing
Getting started
Connect to the hosted instance, no install:
claude mcp add --transport http fcc-spectrum-mcp-server https://fcc-spectrum.caseyjhand.com/mcp
The hosted index is rebuilt weekly and refreshed daily, with individual licensees redacted.
Or run it locally against an index built with First-run setup:
claude mcp add fcc-spectrum-mcp-server -e FCC_SPECTRUM_MIRROR_DIR=/path/to/fcc-uls -- bunx @cyanheads/fcc-spectrum-mcp-server
For other clients, add this to the MCP config file:
{
"mcpServers": {
"fcc-spectrum-mcp-server": {
"command": "bunx",
"args": ["@cyanheads/fcc-spectrum-mcp-server"],
"env": { "FCC_SPECTRUM_MIRROR_DIR": "/path/to/fcc-uls" }
}
}
}
FCC_SPECTRUM_MIRROR_DIR must name the directory mirror:init built. Use an absolute path: MCP clients choose the process's working directory. Until the first build completes, data tools fail with index_not_ready; fcc_spectrum_list_reference with topic coverage reports the build state.
For Docker or a source build, see Running the server.
First-run setup
The index is built from the FCC's public ULS bulk files at data.fcc.gov — weekly full snapshots per service group, plus daily incrementals. On the default groups a build downloads about 1.1 GB of zips, one at a time; a measured build produced 3,270,502 license records and an index of about 1.8 GB in about 3 minutes.
Build it once from a source checkout after bun run build (see Running the server), from an installed package, or with the Docker image:
# Download the weekly snapshots and build the index (resumable; skips when nothing is newer)
FCC_SPECTRUM_MIRROR_DIR=/path/to/fcc-uls bun run mirror:init
# Check it: SQLite integrity plus per-file line counts against the FCC's counts files
FCC_SPECTRUM_MIRROR_DIR=/path/to/fcc-uls bun run mirror:verify
# Apply the daily incrementals published since the last build
FCC_SPECTRUM_MIRROR_DIR=/path/to/fcc-uls bun run mirror:refresh
Each mirror:* script runs a compiled entry under dist/cli/ on Bun. From an npm install, run the scripts from the package directory, or call an entry directly: FCC_SPECTRUM_MIRROR_DIR=/path/to/fcc-uls bun node_modules/@cyanheads/fcc-spectrum-mcp-server/dist/cli/mirror-init.js (likewise mirror-verify.js and mirror-refresh.js).
With Docker, run the same commands against the volume: docker run --rm -v fcc-uls:/usr/src/app/.mirror ghcr.io/cyanheads/fcc-spectrum-mcp-server:latest bun run mirror:init.
Keeping it current:
- HTTP transport. The server schedules the weekly rebuild on Sundays at 16:00 and the daily refresh at 17:00, in the process's local time (the Docker image runs in UTC; the FCC publishes snapshots Sunday morning US Eastern). Refresh checks the available daily publication dates for gaps and overwritten files. When they cannot cover the checkpoint, it runs the weekly rebuild and retries refresh; if no newer snapshot is available, the job reports failure until recovery is possible. Neither job runs until
mirror:inithas published a first index. Each job runs in a child process on the server's runtime, so queries and/healthzkeep answering while it writes, and its log lines appear in the server log; on shutdown a running job is stopped and resumes at the next run. - stdio. Nothing is scheduled. Run
mirror:refreshdaily andmirror:initweekly from cron or another scheduler; daily files never remove licenses, so removals arrive with the weekly rebuild. - Disk. A rebuild writes a new generation beside the one being served, so leave room for a second index plus the largest zip (about 420 MB). Older generations are deleted at the start of the next rebuild.
- Concurrency. An ingest lock lets one
mirror:init,mirror:refresh, or scheduled job write at a time; an interruptedmirror:initresumes from its last completed step when rerun.
Configuration
| Variable | Description | Default |
|---|---|---|
FCC_SPECTRUM_MIRROR_DIR | Directory holding the index and its build files. Use an absolute path. | .mirror/fcc-uls |
FCC_SPECTRUM_SERVICES | Comma-separated weekly service groups to index, case-insensitive. Opt-in: gmrs, ship, aircr. An unknown name fails startup and lists the valid set. | LMpriv,LMcomm,LMbcast,micro,cell,market,paging,coast,mdsitfs,amat |
FCC_SPECTRUM_REDACT_INDIVIDUALS | Redact individual licensees and trustee names and exclude individuals from name search. Only false, 0, no, or off disables it. | true |
FCC_SPECTRUM_BASE_URL | ULS bulk file host root, read only when building or refreshing the index. | https://data.fcc.gov/download/pub/uls |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_SESSION_MODE | Session mode: auto (resolves to stateful), stateful, or stateless. | stateless |
MCP_HTTP_PORT | Port for the HTTP server. | 3010 |
MCP_HTTP_ENDPOINT_PATH | HTTP endpoint path where the MCP server is mounted. | /mcp |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (RFC 5424). | info |
LOGS_DIR | Directory for log files (Node.js only). | <project-root>/logs |
OTEL_ENABLED | Enable OpenTelemetry instrumentation (spans, metrics, completion logs). | false |
See .env.example for the full list of optional overrides.
Service groups
The FCC splits its weekly snapshots into service groups. Adding a group takes effect at the next mirror:init; a removed group drops out at the next weekly rebuild.
| Group | Contents | Indexed |
|---|---|---|
LMpriv | Private land mobile (public safety, business, industrial) | default |
LMcomm | Commercial land mobile | default |
LMbcast | Broadcast auxiliary land mobile | default |
micro | Point-to-point microwave | default |
cell | Cellular | default |
market | Market-area wireless (PCS, AWS, 700 MHz, 3.45 and 3.7 GHz, and other auctioned blocks) | default |
paging | Paging | default |
coast | Coast stations | default |
mdsitfs | Broadband Radio Service and Educational Broadband Service (BRS/EBS) | default |
amat | Amateur radio | default |
gmrs | General Mobile Radio Service — licensee records only | opt-in |
ship | Ship stations — licensee records only | opt-in |
aircr | Aircraft stations — licensee records only | opt-in |
Individual-licensee redaction
ULS records name the person behind many licenses, amateur and otherwise: individuals also hold land mobile, paging, and microwave licenses. FCC_SPECTRUM_REDACT_INDIVIDUALS is on by default and fails safe:
- A record is an individual's when its applicant type is
I, or blank in the amateur and GMRS services. A blank type or typeH(Other) in any service also counts when the filing carries a person's name parts, or when the licensee name contains no organization word (Inc,County,Church,Wireless, …), so an organization named without one is redacted too. Its licensee name is thennullwithlicenseeRedacted: true, and its licensee city, its sites' street addresses, and its site names are omitted, since some individuals file their own name as a site name. - Trustee names are withheld on every license, since a trustee is always a person.
- Licensee name search excludes individuals, and the response
noticesays so. A callsign, USI, or FRN lookup still returns the record, redacted. - Site coordinates, city, county, state, and technical data stay: they are the spectrum record.
- Redaction applies when a response is built, so changing the setting needs a restart, not a rebuild.
Licensee mailing street addresses, ZIP codes, PO boxes, attention lines, phone numbers, fax numbers, and email addresses are never ingested, for anyone.
Known limitations
- Dense-band frequency searches return partial pages. Over a crowded band (all of 150–174 MHz, or the whole spectrum), a page can hold fewer rows than
limitand still carrynextCursor, andtotalCountis then a lower bound (totalIsLowerBound: true). Narrow withstate,radio_service,licensee,frn, ormarket_codeto keep the exact count. - Sites, frequencies, and market blocks are kept only for live licenses (
Aactive,Lpending legal,Xterm pending). Expired, cancelled, and terminated records keep their licensee, status, dates, and lease links. - Market blocks match by state, not by county.
statematches a market block when the FCC's market-area definitions place its market in that state (a multi-state market matches each of its states), when its market name carries the state code, or when its license files a site there; nothing maps a county or a coordinate to the markets covering it. Nationwide and Gulf of Mexico markets match no state, and Tribal land (TL) and MVDDS (MVD) markets with no state code in the name are skipped;market_codewithoutstatereaches any of them. - Radius search matches an operating area by its center. ULS files mobile and temporary-fixed locations as a center and a radius of operation.
fcc_spectrum_find_transmittersreturns such an area at its center, withradiusKm, when the center lies withinradius_km; it does not match an area because the search point falls inside it. Locations filed without coordinates, as most mobile, temporary, itinerant, and control-station locations are, are not returned. - Derived states are approximate near borders, within about a kilometer of a state line; territories other than Puerto Rico get no derived state.
- Removals lag up to a week. Daily files never delete licenses; the weekly rebuild does. A refresh gap longer than the daily window forces a full rebuild.
- Priority Access Licenses are not found by frequency. ULS files each 3.5 GHz PAL as a 10 MHz channel width with no frequency; list them with
fcc_spectrum_search_licensesandradio_servicePL. - Frequencies at a shared location number cannot be tied to a site. ULS files frequencies against the location number, so when a license files several sites under one number, no frequency can be placed at a single site.
- Redaction is per record. A person who also holds licenses filed under a non-individual applicant type appears by name on those records, which carry the same FRN.
- Station class labels use a bundled FCC snapshot. Technical responses preserve filed codes;
fcc_spectrum_list_referencewithtopic: "station_classes"andfilterdecodes known codes. A newer or unknown code may have no bundled label. - Coordinates are NAD83 as filed, with no datum shift.
- A few implausible emission bandwidths pass. A designator 20% of its frequency or wider is ignored as a filing error; narrower implausible filings are taken as filed.
Running the server
Prerequisites
- Bun v1.4 or higher (or Node.js v24+).
bun:sqliteis built into Bun; under Node, installbetter-sqlite3beside the server (declared as an optional peer dependency). - Disk for the index at
FCC_SPECTRUM_MIRROR_DIR: about 1.8 GB on the default groups, plus rebuild room as above. - Network access to
data.fcc.govwhen building or refreshing the index. Queries need none.
Installation
For local development, or to build the index from source:
- Clone the repository:
git clone https://github.com/cyanheads/fcc-spectrum-mcp-server.git
- Navigate into the directory:
cd fcc-spectrum-mcp-server
- Install dependencies:
bun install
- Build the server, which also compiles the
mirror:*entries:
bun run build
- Build the index (see First-run setup):
FCC_SPECTRUM_MIRROR_DIR=/path/to/fcc-uls bun run mirror:init
Local development
-
Build and run:
# One-time build bun run rebuild # Build the index (see First-run setup) bun run mirror:init # 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
# Build the index once against the volume:
docker run --rm -v fcc-uls:/usr/src/app/.mirror ghcr.io/cyanheads/fcc-spectrum-mcp-server:latest bun run mirror:init
# Serve over HTTP:
docker run --rm -p 3010:3010 -v fcc-uls:/usr/src/app/.mirror ghcr.io/cyanheads/fcc-spectrum-mcp-server:latest
The image defaults to HTTP transport with stateless sessions, includes the mirror:* CLI, and logs to /var/log/fcc-spectrum-mcp-server. For stdio, use docker run -i --rm -e MCP_TRANSPORT_TYPE=stdio -v fcc-uls:/usr/src/app/.mirror ghcr.io/cyanheads/fcc-spectrum-mcp-server:latest. Build locally with docker build -t fcc-spectrum-mcp-server .. OpenTelemetry peer dependencies are installed by default; build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools, resources, and the skill directory, inits the index service, and starts the ingest schedule under HTTP transport. |
src/config | Server environment variable parsing and validation with Zod. |
src/mcp-server/tools | Tool definitions (*.tool.ts), shared input schemas, and format helpers. |
src/mcp-server/resources | Resource definitions (*.resource.ts). |
src/services/uls | ULS service — bulk client, record parsers, ingester, index generations, read path with redaction, and the ingest schedule with the job process it spawns. |
src/cli | Index lifecycle CLI — mirror:init, mirror:refresh, mirror:verify — compiled to dist/cli/. |
tests/ | Unit and integration tests mirroring src/, with fixture ULS records. |
skills/ | Published investigation guide, served as an MCP resource. |
Development guide
See CLAUDE.md/AGENTS.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; data access goes through the ULS index service - Register new tools and resources via the barrels in
src/mcp-server/*/definitions/index.ts - The index is the source of truth at runtime — build and refresh it out-of-band, and keep blank ULS fields absent
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
License
Apache-2.0 — see LICENSE for details.
License data comes from the FCC Universal Licensing System (ULS), a US government work in the public domain (17 U.S.C. §105). Credit it as "FCC Universal Licensing System (ULS)" with the dataAsOf time each response carries. This project redistributes none of the license data; operators download it from the FCC when building the index. The package does bundle a market-to-state table (src/services/uls/data/market-states.json) derived from FCC area definitions — the FCC's county-to-market file FCCCNTY2K.txt, its Partial Economic Area county list, and 47 CFR 80.385(a)(3) — which records only the states each market reaches. Basic Trading Areas delineated by the Rand McNally 1992 Commercial Atlas & Marketing Guide, 123rd Edition, at pages 38-39; extended and revised by the Federal Communications Commission, 59 FR 46195 (September 7, 1994). Major Trading Areas delineated by the Rand McNally 1992 Commercial Atlas & Marketing Guide, 123rd Edition, at pages 38-39, extended and excepted by the Federal Communications Commission, 59 FR 14115 (March 25, 1994). This server is independent of the FCC and not endorsed by it.
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.