Skip to main content
Glama

king-county-permit-status

King County permit status

king_county_permit_status
Read-onlyIdempotent

Look up building permit history and status for any King County, WA property. Accepts a street address, 10-digit parcel number, or permit number. Live sources: MyBuildingPermit (14 cities + unincorporated King County), Seattle and Bellevue open data, Renton EnerGov, Redmond Civic Access, Shoreline eTRAKiT, Woodinville + King County Accela, Normandy Park and Carnation SmartGov, SeaTac LAMA, WA State L&I (electrical), plus the King County Assessor's issued-permit index for every parcel (covers the 19 cities without a public portal; history only, no status). Jurisdiction is derived from the city-limits polygon, not the mailing city. Returns all matching permits sorted newest-first. Use for due diligence, permit tracking, or verifying contractor pull history.

Input Schema

NameRequiredDescriptionDefault
limitNoMax permits to return (newest first). summary always covers the whole matched set, so start small and raise only if you need the rows.
queryNoOne 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.
sinceNoOnly permits applied/issued on or after this date (YYYY-MM-DD).
typesNoCase-insensitive substrings matched against each permit's type, e.g. ['electrical', 'mechanical'].
licenseNoWA L&I contractor license number — same search by license. Use instead of query.
contractorNoContractor company name (substring) — returns what they have pulled across the MyBuildingPermit cities. Use instead of query.

Output Schema

NameRequiredDescriptionDefault
actionYesfound — permits[] is populated; none — no permits found; refine — connection issue, retry; reject — bad input
errorsNoSource errors when a search is incomplete; may accompany permits from sources that succeeded.
cite_asNoOne-line attribution string for generated text
filtersNoThe limit/since/types that produced this response
messageYes
permitsNoUp to `limit` permit records, newest first (applied_date, else issued_date).
summaryNoComputed over every permit matching since/types (not just the returned rows): total, matched, returned, truncated, open, closed, status_unknown, open_basis_counts {finaled_date, status-vocabulary} (how many open/closed verdicts rest on a fact vs the status-word heuristic), by_type, by_status, by_year, years [oldest, newest], latest {permit_number,type,status,date,jurisdiction}. Answer from this; drill into permits only when you need rows.
searchedNoJurisdictions searched (e.g. ['King County', 'Renton (EnerGov)']).
next_stepNoStructured twin of separate_portal: the exact follow-up an agent can take. kind=manual_portal_search; reason in no_feed|electrical_only|parcel_resolution_failed|source_incomplete; portal_url (the portal's search page when known); vendor; search_by (inputs that page accepts, empty when login-gated); query/query_type to re-use; covers_electrical; hint.
parcel_idNoCounty-namespaced parcel id, e.g. 'king:7222000353' or 'pierce:5985002900', when the query was or resolved to a parcel
fetched_atNoUTC ISO-8601 timestamp of this query; records are live, not cached
trust_levelNolive — every applicable source answered; partial — a source errored or hit its result cap (see errors); fallback — nothing searchable, use next_step. A city needing manual follow-up (next_step) does not by itself lower trust.
jurisdictionNoWhich authority the query was routed to and why. basis: city-limits (geocoded point inside the city's polygon — authoritative), geocoder-city (locator's city, outside King County's polygon layer), address-text (the mailing city in the query), parcel-site-address (a parcel query, resolved through the Assessor's site address), null (none). unincorporated=true means county permits only.
permit_countNoUnique permits found before any since/types filter (= summary.total)
coverage_noteNoContractor searches only: which cities were (and were not) searched
routing_by_typeNoPer permit type (building, mechanical_plumbing, electrical, land_use, engineering_row, fire, grading, septic) for the resolved jurisdiction: {system, portal, live, note}. live=true means that system is searched by this tool; otherwise the portal is where to look. Present for address queries and parcel queries that resolved a city.
separate_portalNoPresent when manual follow-up at a city portal is needed, including when a live city search is incomplete. Includes city, portal URL, note.
address_resolutionNoHow well the geocoder matched an address query. match_type: point (exact address point), interpolated (number placed along the street; no parcel), street (street only). partial_match is true for anything but point; street_number_snapped when the matched house number differs from the one given.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed13 schema fields changed
    • addedInput schema / description
      Added value: +"Give `query` (address / parcel / permit number) OR `contractor` / `license` for a contractor pull-history search; never both."
    • addedInput schema / properties / contractor
      Added value: +{
      +  "description": "Contractor company name (substring) — returns what they have pulled across the MyBuildingPermit cities. Use instead of query.",
      +  "type": "string"
      +}
    • addedInput schema / properties / license
      Added value: +{
      +  "description": "WA L&I contractor license number — same search by license. Use instead of query.",
      +  "type": "string"
      +}
    • changedInput schema / required
      Previous value: -[
      -  "query"
      -]New value: +[]
    • addedOutput schema / properties / coverage_note
      Added value: +{
      +  "description": "Contractor searches only: which cities were (and were not) searched",
      +  "type": "string"
      +}
    • changedOutput schema / properties / jurisdiction / description
      Previous value: -"Which authority the query was routed to and why. basis: city-limits (geocoded point inside the city's polygon — authoritative), geocoder-city (locator's city, outside King County's polygon layer), address-text (the mailing city in the query), null (none). unincorporated=true means county permits only."New value: +"Which authority the query was routed to and why. basis: city-limits (geocoded point inside the city's polygon — authoritative), geocoder-city (locator's city, outside King County's polygon layer), address-text (the mailing city in the query), parcel-site-address (a parcel query, resolved through the Assessor's site address), null (none). unincorporated=true means county permits only."
    • changedOutput schema / properties / jurisdiction / properties / basis / enum
      Previous value: -[
      -  "city-limits",
      -  "geocoder-city",
      -  "address-text",
      -  null
      -]New value: +[
      +  "city-limits",
      +  "geocoder-city",
      +  "address-text",
      +  "parcel-site-address",
      +  null
      +]
    • changedOutput schema / properties / next_step / properties / query_type / enum
      Previous value: -[
      -  "address",
      -  "parcel",
      -  "permit"
      -]New value: +[
      +  "address",
      +  "parcel",
      +  "permit",
      +  "contractor"
      +]
    • changedOutput schema / properties / next_step / properties / reason / enum
      Previous value: -[
      -  "no_feed",
      -  "electrical_only",
      -  "parcel_resolution_failed",
      -  "source_incomplete",
      -  "source_blocked"
      -]New value: +[
      +  "no_feed",
      +  "electrical_only",
      +  "parcel_resolution_failed",
      +  "source_incomplete",
      +  "source_blocked",
      +  "source_capped"
      +]
    • changedOutput schema / properties / permits / items / properties / is_open / description
      Previous value: -"Normalized across vendor status vocabularies: false when finaled/closed/expired/withdrawn/etc., null when the source exposes no status"New value: +"Heuristic, census-tested weekly: false when finaled/closed/expired/withdrawn/etc. (or a finaled_date exists), true for issued/pending/review words, null when the source exposes no status. Check is_open_basis before relying on it."
    • addedOutput schema / properties / permits / items / properties / is_open_basis
      Added value: +{
      +  "description": "finaled_date = certain (the record carries a final date); status-vocabulary = regex over the vendor's status word (heuristic); null = no status available",
      +  "enum": [
      +    "finaled_date",
      +    "status-vocabulary",
      +    null
      +  ],
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / routing_by_type
      Added value: +{
      +  "description": "Per permit type (building, mechanical_plumbing, electrical, land_use, engineering_row, fire, grading, septic) for the resolved jurisdiction: {system, portal, live, note}. live=true means that system is searched by this tool; otherwise the portal is where to look. Present for address queries and parcel queries that resolved a city.",
      +  "type": "object"
      +}
    • changedOutput schema / properties / summary / description
      Previous value: -"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 {permit_number,type,status,date,jurisdiction}. Answer from this; drill into permits only when you need rows."New value: +"Computed over every permit matching since/types (not just the returned rows): total, matched, returned, truncated, open, closed, status_unknown, open_basis_counts {finaled_date, status-vocabulary} (how many open/closed verdicts rest on a fact vs the status-word heuristic), by_type, by_status, by_year, years [oldest, newest], latest {permit_number,type,status,date,jurisdiction}. Answer from this; drill into permits only when you need rows."
  2. Changed1 schema field changed
    • changedOutput schema / properties / next_step / properties / reason / enum
      Previous value: -[
      -  "no_feed",
      -  "electrical_only",
      -  "parcel_resolution_failed",
      -  "source_incomplete"
      -]New value: +[
      +  "no_feed",
      +  "electrical_only",
      +  "parcel_resolution_failed",
      +  "source_incomplete",
      +  "source_blocked"
      +]
  3. Changed10 schema fields changed
    • addedInput schema / properties / limit
      Added value: +{
      +  "default": 50,
      +  "description": "Max permits to return (newest first). summary always covers the whole matched set, so start small and raise only if you need the rows.",
      +  "minimum": 0,
      +  "type": "integer"
      +}
    • addedInput schema / properties / since
      Added value: +{
      +  "description": "Only permits applied/issued on or after this date (YYYY-MM-DD).",
      +  "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +  "type": "string"
      +}
    • addedInput schema / properties / types
      Added value: +{
      +  "description": "Case-insensitive substrings matched against each permit's type, e.g. ['electrical', 'mechanical'].",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / address_resolution / properties / candidate_parcels
      Added value: +{
      +  "description": "Present when several parcels sit within 40 ft of an interpolated point; the first was used",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / address_resolution / properties / parcel_basis
      Added value: +{
      +  "description": "How the parcel was found: the locator's address point; the parcel polygon under an interpolated point; or the nearest parcel within 40 ft (check candidate_parcels)",
      +  "enum": [
      +    "address-point",
      +    "parcel-polygon",
      +    "nearby-parcel",
      +    null
      +  ],
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / filters
      Added value: +{
      +  "description": "The limit/since/types that produced this response",
      +  "type": "object"
      +}
    • addedOutput schema / properties / permit_count / description
      Added value: +"Unique permits found before any since/types filter (= summary.total)"
    • changedOutput schema / properties / permits / description
      Previous value: -"Permit records sorted newest applied_date first."New value: +"Up to `limit` permit records, newest first (applied_date, else issued_date)."
    • addedOutput schema / properties / summary
      Added value: +{
      +  "description": "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 {permit_number,type,status,date,jurisdiction}. Answer from this; drill into permits only when you need rows.",
      +  "type": "object"
      +}
    • changedOutput schema / properties / trust_level / description
      Previous value: -"live — every applicable source answered; partial — some source errored or a city portal needs manual follow-up; fallback — nothing searchable, use separate_portal"New value: +"live — every applicable source answered; partial — a source errored or hit its result cap (see errors); fallback — nothing searchable, use next_step. A city needing manual follow-up (next_step) does not by itself lower trust."
  4. First observed

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish read-only, idempotent, non-destructive, open-world behavior, and the description adds substantial context on top: the live source list, the fact that jurisdiction is derived from the city-limits polygon rather than mailing city, and the important coverage caveat that the Assessor index for 19 portal-less cities is 'history only, no status'. These are material behavioral facts an agent cannot infer from annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose, accepted inputs, and sources are front-loaded, and the final sentence cleanly states when to use it. The enumeration of a dozen named source systems is long, but each entry maps to real coverage an agent needs to reason about, so most of the length earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value detail is unnecessary, and the description instead supplies the things that actually matter for correct use: input modes, sorting order, jurisdiction resolution logic, and explicit coverage gaps. Nothing an agent needs before calling is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and every parameter already carries examples and format guidance, so the baseline is 3. The description reinforces the accepted input types and the polygon-based jurisdiction resolution, but most of that is duplicative of the schema's own parameter descriptions, adding no format or constraint detail beyond it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb ('look up') plus resource ('building permit history and status') plus explicit geographic scope ('any King County, WA property'). The three accepted identifier forms and the sorted result set make the tool's contract unambiguous, far beyond a restatement of the name.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Names concrete use cases — 'due diligence, permit tracking, or verifying contractor pull history' — and pairs them with the matching input mode (query vs. contractor/license). It does not state when to avoid the tool or what to do when a jurisdiction has no portal beyond the implicit note that Assessor history lacks status, so it stops short of full alternative routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.