About king-county-permit-status
A read-only permit lookup for King County, WA addresses, parcel numbers, or permit numbers, for people checking building permit status and history. It combines county and city data sources and points to the relevant portal when a jurisdiction lacks live coverage.
Key features
- 01Search by address, parcel, or permit number
- 02Summarize permit status, types, and date ranges
- 03Filter by date and permit type
- 04Show searched jurisdictions and sources
- 05Link to portals where live data is unavailable
Use cases
- 01Review permit history for a property address
- 02Check permits and open status for a parcel
- 03Use a municipal portal when live data is unavailable
MCP support
The hosted service exposes a read-only MCP tool, `king_county_permit_status`, over Streamable HTTP. MCP clients can connect to `https://permits-api.secondlandings.ai/mcp`.
Configuration
Remote servers need no local install. Pick your client, then copy the config or install in one click.
https://permits-api.secondlandings.ai/mcpclaude mcp add --transport http chaoz23-king-county-permit-status https://permits-api.secondlandings.ai/mcp{"mcpServers":{"chaoz23-king-county-permit-status":{"type":"http","url":"https://permits-api.secondlandings.ai/mcp"}}}Open in Cursor{"servers":{"chaoz23-king-county-permit-status":{"type":"http","url":"https://permits-api.secondlandings.ai/mcp"}}}Open in VS Code{"mcpServers":{"chaoz23-king-county-permit-status":{"type":"http","url":"https://permits-api.secondlandings.ai/mcp"}}}{"mcpServers":{"chaoz23-king-county-permit-status":{"serverUrl":"https://permits-api.secondlandings.ai/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
1| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Max permits to return (newest first). summary always covers the whole matched set, so start small and raise only if you need the rows. |
| query | string | No | One of: street address ('1817 Morris Ave S, Renton WA 98055'), 10-digit parcel number (plain '7222000353' or formatted '722200-0353'), or permit number ('B25000947', 'ADDC21-0275', '23-127651-LP', '6145915-CN'). Input type is auto-detected. |
| since | string | No | Only permits applied/issued on or after this date (YYYY-MM-DD). |
| types | array | No | Case-insensitive substrings matched against each permit's type, e.g. ['electrical', 'mechanical']. |
| license | string | No | WA L&I contractor license number — same search by license. Use instead of query. |
| contractor | string | No | Contractor company name (substring) — returns what they have pulled across the MyBuildingPermit cities. Use instead of query. |
Details
From the project READMEKing County Permit Status
Look up building permit history and status across King County, WA jurisdictions — county-level permits (septic, critical areas, grading) and city-level permits (building, mechanical, electrical) can all apply to the same address. Coverage is live where a jurisdiction offers an open permit feed, and falls back to the correct municipal portal link everywhere else.
Coverage today: 🟢 20/39 cities live (status + history) · 🟠 19/39 indexed (issued-permit history from the King County Assessor; current status needs the city portal, which next_step names) · plus unincorporated King County. See the coverage scorecard below for the per-city breakdown.
python3 lookup.py "27927 E Main St" # by address
python3 lookup.py "7222000353" # by parcel number
python3 lookup.py "B25000947" # by permit number
python3 lookup.py "23-127651-LP" # Bellevue permit number
python3 lookup.py "6145915-CN" # Seattle SDCI permit number
python3 lookup.py --pipe "27927 E Main St" # agent pipeline mode
python3 lookup.py --limit 10 --since 2020-01-01 --type electrical "27927 E Main St" # shape: newest 10 electrical since 2020
python3 lookup.py --all "27927 E Main St" # every permit (default is the 50 newest + a summary of all)
python3 lookup.py --schema # print tool definition
Hosted API + MCP (no install)
The same lookup is served read-only, no auth, from permits-api.secondlandings.ai
(server.py, zero dependencies; see deploy/README.md):
| MCP (Streamable HTTP) | POST https://permits-api.secondlandings.ai/mcp — tool king_county_permit_status, arg query |
| REST | GET https://permits-api.secondlandings.ai/api/lookup?q=1817+Morris+Ave+S,+Renton+WA — optional limit, since=YYYY-MM-DD, types=electrical,mechanical |
| Vendor map | /vendor-map (and /vendor-map.json) — which permitting system each of the 39 cities runs, how it is queried or why it can't be, electrical authority, per-type routing; generated from the adapter config (scripts/gen_vendor_map.py, also in docs/vendor-map.md) |
| OpenAPI 3.1 (typed) | /openapi.json · agent orientation /llms.txt · CLI definition /tool.json · /healthz |
Results are live; the server caches each query for 15 minutes and rate-limits
per client (30/min) to protect the municipal portals. Known hosted-only gap: Tyler's
hosted Civic Access (Redmond) returns 403 to datacenter IPs, so from the hosted endpoint a
Redmond lookup carries the Assessor index plus a next_step with reason: source_blocked
instead of live Redmond records; run lookup.py locally for those. Every other source
answers from the droplet. Run it yourself with
python3 server.py or docker compose up — server.json is the MCP Registry manifest.
Parcel-number searches query every supported MyBuildingPermit and live city portal because a bare parcel number does not identify its city jurisdiction.
Address searches are routed by geometry, not the mailing city: the address
is geocoded with King County's four-county locator and the point is tested
against the city-limits polygons. A "Kent, WA" address that sits in
unincorporated King County is searched as county, not Kent; an address with no
city in it is routed correctly instead of fanning out to every jurisdiction; and
Pierce-side addresses of Milton/Pacific/Auburn get a pierce: parcel id. The
mailing city is only used when geocoding fails (jurisdiction.basis says which).
What you get
{
"action": "found",
"permit_count": 2,
"searched": ["Renton (EnerGov)"],
"permits": [
{
"permit_number": "E26000458",
"type": "Residential Electrical Permit",
"status": "Issued",
"description": "Electrical Work (Garage & Garage Exterior): ...",
"address": "1817 Morris Ave S Renton WA 98055",
"jurisdiction": "Renton",
"applied_date": "2026-01-28",
"issued_date": "2026-01-28",
"finaled_date": null,
"expires_date": "2027-07-27",
"portal": "https://permitting.rentonwa.gov",
"record_url": null,
"is_open": true
}
],
"trust_level": "live",
"fetched_at": "2026-10-08T19:02:11+00:00",
"parcel_id": "king:7222000353",
"cite_as": "King County Permit Status (github.com/chaoz23/king-county-permit-status), queried 2026-10-08 via Renton (EnerGov)"
}
| Field | Description |
|---|---|
action | found (permits returned), none (no matches), refine (connection issue) |
permit_count | Unique permits found before any filter (= summary.total) |
summary | Answer from this first. Computed over every permit matching since/types, not just the returned rows: total, matched, returned, truncated, open, closed, status_unknown, by_type, by_status, by_year, years [oldest, newest], latest |
permits | Up to limit records (default 50), newest first — a 356-permit commercial parcel is ~56k tokens unshaped; the summary carries the whole picture |
filters | The limit / since / types that produced this response |
searched | Which jurisdictions were searched |
separate_portal | If the city has an unsupported portal: city name + URL + prose note |
next_step | Structured twin of separate_portal for agents: kind: manual_portal_search, reason (no_feed / electrical_only / parcel_resolution_failed / source_incomplete / source_blocked — the city's live system refused this client with 403), portal_url (the portal's actual search page when known — PermitTrax, LAMA, OpenGov, Kent), vendor, search_by (inputs that page accepts; empty when login-gated), query, query_type, covers_electrical, hint |
errors | Source errors when a search is incomplete; may accompany permits from successful sources |
trust_level | live (every applicable source answered), partial (a source errored or hit its result cap — see errors), fallback (nothing searchable). A city that needs a manual portal visit (next_step) is a scope fact, not distrust, and no longer lowers this |
fetched_at | UTC timestamp of the query — records are live, never cached |
parcel_id | County-namespaced parcel, e.g. king:7222000353 or pierce:5985002900, when the query was or resolved to a parcel |
jurisdiction | Where the query was routed and why: city, basis (city-limits = the geocoded point falls inside that city's polygon — authoritative; geocoder-city; address-text = the mailing city in the query, used only when geocoding fails), county, unincorporated (true → county permits only, even if the mailing city says "Kent") |
routing_by_type | Where each kind of permit lives for the resolved place — building, mechanical_plumbing, electrical, land_use, engineering_row, fire, grading, septic → {system, portal, live, note}. live: true means this tool searched that system; otherwise portal is where to look (e.g. septic is always King County Public Health; electrical is L&I unless the city self-runs it) |
address_resolution | How well the geocoder matched an address: matched_address, score, match_type (point = exact address point; interpolated = number placed along the street; street), partial_match, street_number_snapped, parcel_basis (address-point, parcel-polygon, or nearby-parcel when the PIN came from the parcel layer under/near an interpolated point — then candidate_parcels lists the alternatives) |
cite_as | One-line attribution string for generated text |
Per permit: permit_number, type, status, is_open (heuristic, census-tested weekly; null when the source exposes no status) with is_open_basis (finaled_date = certain, status-vocabulary = regex over the vendor's status word, null = unknown), description, address, jurisdiction, applied_date, issued_date, finaled_date, expires_date, portal, record_url (the specific record's URL when the source exposes one).
Multi-jurisdiction coverage
| Source | Cities / scope |
|---|---|
| MyBuildingPermit.com | Auburn, Bellevue, Bothell, Burien, Edmonds, Federal Way, Issaquah, Kenmore, King County (unincorporated), Kirkland, Mercer Island, Mill Creek, Newcastle, Sammamish, Snoqualmie |
| Bellevue Open Data (live ArcGIS API) | Daily Bellevue permit snapshot (1998+) for address, parcel, and permit-number searches |
| Seattle Open Data (live Socrata APIs) | Building, electrical, trade, and land-use permits for Seattle address and permit-number searches; parcel-number queries reach it through the Assessor's site address (the datasets have no parcel column) |
| Renton EnerGov (live API) | All Renton permit types including electrical |
| Redmond EnerGov Civic Access (live API) | All Redmond permit types including electrical, for address, parcel, and permit-number searches |
| Accela Citizen Access (live) | Woodinville, and King County's own agency for unincorporated addresses (older history, enforcement and electrical records that MyBuildingPermit lacks), for address, parcel, and permit-number searches |
| SmartGov (live) | Normandy Park and Carnation, for address, parcel, and permit-number searches |
| King County Assessor parcel index | Issued-permit history (number, type, description, issue date, value, issuing city) for every King County parcel — the only source for the 19 cities without a public portal. It is what cities report for valuation: building/remodel/addition permits (some electrical), dense since ~2023 and thin before, back to the late 1990s; never trade sub-permits or inspections, and no status. Address queries use the geocoded parcel, parcel queries use it directly |
| LAMA (live) | SeaTac, for address and permit-number searches (incl. SeaTac's self-run electrical; parcel search not offered by the portal; capped at 200 newest per query) |
| Shoreline eTRAKiT (live) | Building, mechanical/plumbing, and land-use permits for Shoreline address, parcel, and permit-number searches (status/description not exposed by the portal's search) |
| WA State L&I | Electrical permits for cities not handling their own (2020+) |
Coverage scorecard
Auto-generated from routing_data.json (python3 scripts/gen_scorecard.py --write). One row per King County city.
Legend — ✅ live (status + history) · 🗂️ index (valuation-reported building history · the number after ✅/🗂️ in Building is the record count at the city's QC address (see qc_addresses.json) — how much is really behind the row from the King County Assessor's parcel index — no status, no sub-permits, dense since ~2023) · ➖ L&I electrical only (2020+) · ⚠️ gap (city self-runs electrical, not yet integrated)
Health = last weekly live probe of the city's source (scripts/source_health.py, 2026-10-26): ✅ answered with records · ⚪ answered, zero rows for a known-good query · ⛔ blocked (403) · ❌ down · ❔ unchecked · — no live source
| City | Status | Source | Health | Building | Electrical | Mech/Plumb | Land Use |
|---|---|---|---|---|---|---|---|
| Algona | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 2 | ➖ L&I | 🗂️ index | 🗂️ index |
| Auburn | 🟢 Live | MyBuildingPermit | ✅ | ✅ 133 | ➖ L&I | ✅ | ✅ |
| Beaux Arts Village | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 5 | ➖ L&I | 🗂️ index | 🗂️ index |
| Bellevue | 🟢 Live | Bellevue (Open Data) | ✅ | ✅ 360 | ✅ | ✅ | ✅ |
| Black Diamond | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 2 | ➖ L&I | 🗂️ index | 🗂️ index |
| Bothell | 🟢 Live | MyBuildingPermit | ✅ | ✅ 117 | ➖ L&I | ✅ | ✅ |
| Burien | 🟢 Live | MyBuildingPermit | ✅ | ✅ 27 | ✅ | ✅ | ✅ |
| Carnation | 🟢 Live | Carnation (SmartGov) | ✅ | ✅ 2 | ➖ L&I | ✅ | ✅ |
| Clyde Hill | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 3 | ➖ L&I | 🗂️ index | 🗂️ index |
| Covington | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 24 | ➖ L&I | 🗂️ index | 🗂️ index |
| Des Moines | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 17 | ⚠️ gap | 🗂️ index | 🗂️ index |
| Duvall | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 1 | ➖ L&I | 🗂️ index | 🗂️ index |
| Enumclaw | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 3 | ➖ L&I | 🗂️ index | 🗂️ index |
| Federal Way | 🟢 Live | MyBuildingPermit | ✅ | ✅ 120 | ✅ | ✅ | ✅ |
| Hunts Point | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 2 | ➖ L&I | 🗂️ index | 🗂️ index |
| Issaquah | 🟢 Live | MyBuildingPermit | ✅ | ✅ 57 | ➖ L&I | ✅ | ✅ |
| Kenmore | 🟢 Live | MyBuildingPermit | ✅ | ✅ 77 | ➖ L&I | ✅ | ✅ |
| Kent | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 7 | ➖ L&I | 🗂️ index | 🗂️ index |
| Kirkland | 🟢 Live | MyBuildingPermit | ✅ | ✅ 2 | ✅ | ✅ | ✅ |
| Lake Forest Park | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 1 | ➖ L&I | 🗂️ index | 🗂️ index |
| Maple Valley | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 8 | ➖ L&I | 🗂️ index | 🗂️ index |
| Medina | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 5 | ➖ L&I | 🗂️ index | 🗂️ index |
| Mercer Island | 🟢 Live | MyBuildingPermit | ✅ | ✅ 12 | ✅ | ✅ | ✅ |
| Milton | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 0 | ⚠️ gap | 🗂️ index | 🗂️ index |
| Newcastle | 🟢 Live | MyBuildingPermit | ✅ | ✅ 85 | ➖ L&I | ✅ | ✅ |
| Normandy Park | 🟢 Live | Normandy Park (SmartGov) | ✅ | ✅ 22 | ✅ | ✅ | ✅ |
| North Bend | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 2 | ➖ L&I | 🗂️ index | 🗂️ index |
| Pacific | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 8 | ➖ L&I | 🗂️ index | 🗂️ index |
| Redmond | 🟢 Live | Redmond (EnerGov Civic Access) | ✅ | ✅ 32 | ✅ | ✅ | ✅ |
| Renton | 🟢 Live | Renton (EnerGov) | ✅ | ✅ 24 | ✅ | ✅ | ✅ |
| Sammamish | 🟢 Live | MyBuildingPermit | ✅ | ✅ 11 | ✅ | ✅ | ✅ |
| SeaTac | 🟢 Live | SeaTac (LAMA) | ✅ | ✅ 178 | ✅ | ✅ | ✅ |
| Seattle | 🟢 Live | Seattle (SDCI Open Data) | ✅ | ✅ 131 | ✅ | ✅ | ✅ |
| Shoreline | 🟢 Live | Shoreline (eTRAKiT) | ✅ | ✅ 53 | ➖ L&I | ✅ | ✅ |
| Skykomish | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 3 | ➖ L&I | 🗂️ index | 🗂️ index |
| Snoqualmie | 🟢 Live | MyBuildingPermit | ✅ | ✅ 57 | ➖ L&I | ✅ | ✅ |
| Tukwila | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 6 | ⚠️ gap | 🗂️ index | 🗂️ index |
| Woodinville | 🟢 Live | Woodinville (Accela) | ✅ | ✅ 9 | ➖ L&I | ✅ | ✅ |
| Yarrow Point | 🟠 Indexed | KC Assessor index | ✅ | 🗂️ index 1 | ➖ L&I | 🗂️ index | 🗂️ index |
| King County (unincorp.) | 🟢 Live | MyBuildingPermit (King County) + KC Accela | ✅ | ✅ | ➖ L&I | ✅ | ✅ |
Coverage: 20/39 live · 19/39 indexed (issued history via the Assessor; status needs the city portal). Plus King County (unincorporated) for county-level permits (septic, critical areas, grading).
⚠️ Electrical gaps: Des Moines, Milton, Tukwila. These cities self-run their electrical program (so L&I is skipped) and are not on MyBuildingPermit, leaving their electrical permits in no feed we search. MBP cities that self-run electrical (Burien, Federal Way, Kirkland, Mercer Island, Sammamish) are not gaps — verified 2026-07-15 that MBP carries their electrical history. Closing the remaining gaps is tracked in the coverage epic.
ℹ️ Split-county cities: Milton (mostly Pierce), Pacific and Auburn straddle the King/Pierce line. Each city issues its own permits for the whole city, so a live row applies to both sides; but the 🗂️ Assessor index is King County's, so for an indexed split city (Milton) only King-side parcels have index rows — Pierce-side addresses get the portal pointer only. Pierce County's portal is not searched. Parcel ids are county-namespaced (
king:…/pierce:…) for this reason.
All 39 incorporated King County cities are recognized. Cities outside the searchable sources are flagged with their municipal portal URL rather than being treated as unincorporated King County.
For comma-separated addresses, the locality component takes precedence over
city names that also appear in streets (for example, Kent Kangley Rd, Covington). If a Renton address cannot be resolved to a parcel for its live
EnerGov search, the result retains Renton's portal as an actionable fallback.
Seattle address and exact permit-number searches query all four official SDCI
Open Data datasets; parcel-only Seattle lookup is not yet supported.
Kent's official permit-status page currently requires users to sign in to the
city portal, so Kent results include that page as a manual fallback.
Exit codes
| Code | Action | Meaning |
|---|---|---|
| 0 | found | permits[] is populated |
| 1 | none / refine | No permits or connection issue |
| 2 | reject | Bad input |
For agents
tool.json at the repo root contains the full tool definition in Anthropic/OpenAI tool-call format. An agent can load it directly or fetch the live version:
python3 lookup.py --schema
{
"name": "king_county_permit_status",
"description": "Look up building permit history and status for any King County, WA property...",
"input_schema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Street address, 10-digit parcel number, or permit number..."
}
},
"required": ["query"]
},
"output_schema": { ... },
"invocation": {
"command": "python3 lookup.py --pipe \"{query}\"",
"exit_codes": {
"0": "action=found — permits[] is populated",
"1": "action=none or refine — no permits or connection issue",
"2": "action=reject — bad input"
}
}
}
Pipeline pattern:
# Get all permits at an address, extract open ones
python3 lookup.py --pipe "1817 Morris Ave S, Renton WA" \
| python3 -c "
import sys, json
d = json.load(sys.stdin)
open_statuses = {'Issued', 'In Review', 'On Hold', 'Pending'}
open_permits = [p for p in d.get('permits', []) if p['status'] in open_statuses]
print(json.dumps(open_permits, indent=2))
"
Related tools in this series:
king-county-address-to-parcel-number— resolve an address to its parcel numberwa-contractor-license— verify WA contractor license status and violationsking-county-property-tax-appeal— build a filing-ready tax appeal packet
Requirements
- Python 3.10+ (stdlib only, no dependencies)
- Network access to the municipal and county hosts in the source table above (MyBuildingPermit, Tyler/Accela/SmartGov/eTRAKiT/LAMA portals, Seattle and Bellevue open data,
gismaps.kingcounty.gov,blue.kingcounty.com,secure.lni.wa.gov)
Development
Run the network-free regression suite with:
python3 -m unittest discover -s tests -v
Contractor search
python3 lookup.py --contractor "Brambila" # what a contractor has pulled
python3 lookup.py --license BRAMBSL123AA # same, by L&I license number
Searches MyBuildingPermit's People index across all of its jurisdictions (Auburn, Bellevue,
Bothell, Burien, Edmonds, Federal Way, Issaquah, Kenmore, King County, Kirkland, Mercer
Island, Mill Creek, Newcastle, Sammamish, Snoqualmie), concurrently, splitting busy
contractors by applied-date window; same schema and summary. coverage_note says which
cities are not searched by contractor (Seattle, Renton, Redmond, Shoreline, SeaTac,
Woodinville, Normandy Park, Carnation — their portals' contractor searches aren't
implemented). Pair with wa-contractor-license
for the license/bond/insurance check. Also on the hosted API: ?contractor= / ?license=,
and the MCP tool's contractor / license arguments.
Quality checks
Four layers, each answering a different question:
| Check | Question | Runs |
|---|---|---|
python3 -m unittest discover -s tests | Does the code still do what it did? (mocked, offline) | CI on every push + Mondays |
python3 scripts/qc_scorecard.py | Does every scorecard row behave as claimed, live? One real address per city (qc_addresses.json); expectations are derived from the same classification that renders the scorecard — live rows must return records from the city's own source, indexed rows must return Assessor history plus a next_step, and the electrical column must match what was searched | Mondays (non-blocking), or by hand |
python3 scripts/qc_smoke.py | Do real, fake and edge inputs route sensibly end to end? | Mondays (non-blocking) |
python3 scripts/source_health.py | Is each adapter still answering a known-good query, and what status vocabulary is it returning? | Mondays → source_health.json → scorecard Health column |
License
MIT — see LICENSE. Permit data comes from the public municipal and county sources named above; cite results with the cite_as field.
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.