_ registry / mcp streamable-http · checked 1h ago

permitintel

https://permitintel.ai

Registry code: 7b8f30de0462dda9

api record

PermitIntel publishes building-permit records collected from the cities and counties that issue them, plus Florida DBPR license verification and derived roof intelligence. Every tool needs a PermitIntel API key sent as `Authorization: Bearer pmit_...` or `x-api-key`; tools/list works without one. Calls are metered in RECORDS (one record per object returned) against the key's monthly allowance — each tool description says what it costs, and the response headers carry X-Records-Request and X-Records-Remaining. Report every count as a FLOOR: "at least N permits on record", never as a total filed…

endpoint
https://permitintel.ai/api/mcp
protocol
streamable-http ·2025-06-18
authentication
none observed
public key
none — nobody has proven they own this listing · is it yours? claim it
karma
0 · newcomer
_ is it live, free and safe measured by this hub
Is permitintel live?
Yes — it answered the hub's last check (checked 1h ago). It answered 100% of checks over the last 30 days.
Is permitintel free to use?
Not anonymously — it asks for a key or a login before it will serve. Whether that key costs anything is the operator's plan to say: the hub measured the door, not the pricing.
What tools does permitintel have?
6 tools: roof_lookup, lookup_contractor, search_permits, verify_license, rollups, supply_accounts.
Is permitintel safe to connect?
The hub found no text in its card or tool descriptions aimed at the agent reading them. It measures what the server answers, not its code — grant it only the access its tools need.
reachable
live
uptime, 30 days
100%

90 days 100%· all time 100%

latency
424ms

last good check

priced tools
0

of 6 tools

_ answered our checks, 90 days 1 checks · signed record
  • unknown → live
_ usage and payments 30 days

Calls placed through this hub's router, from its own receipts. Every caller and every payer counts the same; the chain total is counted from three payers.

accounts
0

through this hub

calls served
0

successful

paid through this hub
0 USDC

what callers paid

_ what it can do 6 tools
5 auth-required 1 never probed 5 of 6 classified

Price is per tool, not per server. An agent whose handshake is open can hold tools that demand a key or a payment, and one figure for the whole agent sends callers into a wall.

  • lookup_contractor auth-required 1h ago

    Look up Florida contractors with their permit activity rolled up: permit count, declared value, activity in the last 12 months, first and last permit dates, top trades, top jurisdictions, plus canonical contact, a workers-compensation-on-record signal and EPA Lead-Safe certification. Call with `license` for one profile, `name` or `specialty` to search, or `sort`/`min_permits`/`min_permits_12mo` to rank by permit activity. Costs 1 record per contractor returned; `limit` defaults to 25 and caps at 100. Activity is a FLOOR built from the permits PermitIntel has ingested, not a complete record of everything the contractor filed. This endpoint returns positive and neutral public record only — it exposes no disciplinary history and no negative flags.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "city": {
          "type": "string",
          "description": "City, e.g. Clermont."
        },
        "name": {
          "type": "string",
          "description": "Business name, matched as a substring."
        },
        "sort": {
          "enum": [
            "permits",
            "permits_12mo",
            "value",
            "value_12mo",
            "last_active"
          ],
          "type": "string",
          "description": "Rank by permit activity instead of name matching."
        },
        "limit": {
          "type": "integer",
          "description": "Rows per page. Default 25, maximum 100."
        },
        "county": {
          "type": "string",
          "description": "Florida county, e.g. Lake."
        },
        "offset": {
          "type": "integer",
          "description": "Offset paging."
        },
        "license": {
          "type": "string",
          "description": "Exact DBPR license number. Returns a single profile."
        },
        "specialty": {
          "type": "string",
          "description": "Matched against the license type name, e.g. roofing, electrical."
        },
        "min_permits": {
          "type": "integer",
          "description": "Only contractors with at least this many permits on record."
        },
        "min_permits_12mo": {
          "type": "integer",
          "description": "Only contractors with at least this many permits in the last 12 months."
        }
      },
      "additionalProperties": false
    }
    arguments 54 lines
  • search_permits auth-required 1h ago

    Search ingested building-permit records. SIX modes, exactly one of which is required: `address` for permits at a street address; `contractor` for a contractor's permit history by name or license number; `zip` for one 5-digit ZIP, newest first; `city` together with `state` for one city, newest first; `jurisdiction` for one jurisdiction code, newest first; or `updated_since` for the change feed — every permit whose RECORD changed at or after a timestamp, oldest change first, paged with the opaque `cursor` from meta.next_cursor. Use the feed, not from/to, to keep a copy in sync: a permit ingested today carrying a 2019 issue date is invisible to a from/to poll. To answer "what permits are in this place", start from `zip` or from `city`+`state` — do NOT invent an address. `zip` is an exact match on the permit's own ZIP and `city` answers from the jurisdiction codes we maintain for that place (the response states both in `query.zip_match` / `query.city_match` and names the codes in `query.jurisdictions`; city_match=jurisdiction_codes_place_alias means the name was folded to reach the stored code, e.g. "Saint Petersburg" -> ST_PETERSBURG or "Miami" -> MIAMI_CITY; an exact match always wins over a fold), so neither is a complete census of a postal area. Both order newest first and therefore exclude permits with no issue date (`query.undated_excluded`). `county` is a filter, not a mode: a prefix range cannot be walked in date order. An empty geo page always carries `zero_row_reason`; read that field before reporting an absence, because "we hold no code for this city" and "nothing matched inside the window" are different facts and only one of them is about the place. Costs 1 record per permit returned; `limit` defaults to 50 and caps at 200, so one call costs at most 200 records. Results are a FLOOR and a SCOPE, never a complete record of all permits at an address or by a contractor — permit offices publish on their own schedules and some publish almost nothing. Report counts as "at least N on record", never as a total filed.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "to": {
          "type": "string",
          "description": "issue_date on or before YYYY-MM-DD. (modes: feed, browse, address, contractor, zip, city)"
        },
        "zip": {
          "type": "string",
          "description": "A 5-digit ZIP. On its own it selects zip mode: that ZIP's permits, newest first, served by the (site_zip, issue_date) index. Inside another mode it narrows the result. Not available in feed mode, which is ordered on a table that does not carry the column. (modes: zip, city, browse, address, contractor)"
        },
        "city": {
          "type": "string",
          "description": "A city. On its own WITH 'state' it selects city mode: that city's permits, newest first. Inside another mode it narrows the result (substring match on the permit's own city column). Not available in feed mode, which is ordered on a table that does not carry the column. (modes: city, zip, browse, address, contractor)"
        },
        "from": {
          "type": "string",
          "description": "issue_date on or after YYYY-MM-DD. (modes: feed, browse, address, contractor, zip, city)"
        },
        "limit": {
          "type": "integer",
          "description": "Rows per page. Default 50, maximum 200. (modes: feed, browse, address, contractor, zip, city)"
        },
        "state": {
          "type": "string",
          "description": "Two-letter state code. Required in city mode; disambiguates a ZIP; the feed's own state filter. Refused in address, contractor and browse mode, which read a view that does not carry the column -- see the note under Polling. (modes: feed, zip, city)"
        },
        "trade": {
          "type": "string",
          "description": "One or more trade slugs, comma-separated. Matched against our permit classifier for roofing, hvac, electrical, pool, solar, windows_doors and fence; matched on keywords over permit_type, work_class and type_of_work for general, plumbing and demolition. Every trade-filtered response reports which matcher ran as trade_source. In browse mode the search is bounded to a 180-day window, reported as a top-level trade_window object on the response (not under meta). Feed mode applies trade with no window, but always matches it on keywords -- see trade_source. (modes: feed, browse, address, contractor, zip, city)"
        },
        "county": {
          "type": "string",
          "description": "County jurisdiction prefix, e.g. FL-MIAMI_DADE. Matches every jurisdiction under it. Narrows another query; it cannot browse on its own, because a prefix range cannot be walked in date order. (modes: feed, address, contractor)"
        },
        "cursor": {
          "type": "string",
          "description": "Opaque cursor from meta.next_cursor. Pass it back to get the next page. Stable across inserts; prefer it to offset. (modes: feed)"
        },
        "offset": {
          "type": "integer",
          "description": "Offset paging, kept for back-compatibility. Use cursor in feed mode. (modes: feed, browse, address, contractor, zip, city)"
        },
        "status": {
          "type": "string",
          "description": "Substring match on the source's permit status. (modes: feed, browse, address, contractor, zip, city)"
        },
        "address": {
          "type": "string",
          "description": "Street address, prefix-matched. Minimum 4 characters. (modes: address)"
        },
        "include": {
          "type": "string",
          "description": "Comma-separated extras. contractor_contact nests the licensed contractor's business name, phone, email and verified website. (modes: feed, browse, address, contractor, zip, city)"
        },
        "new_only": {
          "type": "boolean",
          "description": "With updated_since, restrict to permits first ingested since that timestamp instead of every record that changed. (modes: feed)"
        },
        "min_value": {
          "type": "integer",
          "description": "Minimum declared permit value in USD. (modes: feed, browse, address, contractor, zip, city)"
        },
        "work_type": {
          "type": "string",
          "description": "Raw substring match on the source's own work wording. Use trade for a normalized filter. (modes: feed, browse, address, contractor, zip, city)"
        },
        "contractor": {
          "type": "string",
          "description": "Contractor business name (min 3 chars) or an exact license number. (modes: contractor)"
        },
        "trade_match": {
          "type": "string",
          "description": "classifier (default) or keywords. 'keywords' pins the request to the pre-2026-09-30 substring matcher for every requested trade. Not available in feed mode, which always matches on keywords and reports so in trade_source. (modes: browse, address, contractor, zip, city)"
        },
        "jurisdiction": {
          "type": "string",
          "description": "Exact jurisdiction code, in the form STATE-COUNTY-PLACE: FL-ORANGE-ORLANDO, CA-SAN_FRANCISCO. Case-insensitive. A code we hold nothing under answers 200 with a did_you_mean block naming codes we do hold, so never read an empty page as an empty market. Call /api/v1/jurisdictions rather than guessing. On its own it selects browse mode. (modes: feed, browse, address, contractor)"
        },
        "updated_since": {
          "type": "string",
          "description": "ISO 8601 timestamp. Returns every permit whose record changed at or after it, oldest change first. This is the polling parameter: unlike from/to it sees a permit backfilled today with a 2019 issue date. (modes: feed)"
        },
        "trade_confidence": {
          "type": "string",
          "description": "any (default) or high. Applies only to classifier-matched trades. 'high' keeps trade signals found in the permit's type/class fields and drops those found only in its description — narrower and more precise, and zero rows in jurisdictions whose only signal is the description. Not available in feed mode, which matches every trade on keywords. (modes: browse, address, contractor, zip, city)"
        }
      },
      "additionalProperties": false
    }
    arguments 91 lines
  • verify_license auth-required never probed

    Verify one contractor license against the Florida DBPR record: status, license type, effective and expiration dates, whether it is currently active, days to expiry, and the qualifier. Call it with `license` for an exact number, or with `name` (and optionally `county`) to resolve a business name to its license. Costs 1 record on a hit and 0 records on a miss. License status reflects PermitIntel's most recent DBPR sync, refreshed daily, and is for B2B verification of a licensed business, not consumer underwriting. Florida only.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "name": {
          "type": "string",
          "description": "Business name, matched as a substring. Use instead of license."
        },
        "county": {
          "type": "string",
          "description": "Florida county, to narrow a name lookup. Ignored when license is given."
        },
        "license": {
          "type": "string",
          "description": "An exact DBPR license number, for example CCC1330911 or CGC1520001."
        }
      },
      "additionalProperties": false
    }
    arguments 19 lines
  • rollups auth-required never probed

    Wraps GET /api/v1/rollups. Grouped permit totals for a place instead of a list of permits: set `group` to `county` (with `state`), `zip` (with `county`) or `jurisdiction` (with `state` or `county`), and each row carries permits, permits in the trailing 12 months, declared value for both windows, how many permits resolved to a contractor license, and the most recent issue month. Narrow with `trade` (roofing, hvac, electrical, plumbing, pool, solar, windows_doors, fence, general, or a rollup category such as ev_charger) at county and ZIP grain. `window` is `12mo` or `all` and decides which number ranks the rows. Costs ONE RECORD PER GROUP ROW returned, not one per underlying permit; `limit` defaults to 200 and caps at 1000. County and ZIP rows come from a rollup aggregate of permits carrying an issue month; jurisdiction rows come from the published coverage file, count every permit whatever its dates and carry no declared value, so the two bases do not agree about the same county and every row names its `basis`. Totals are a FLOOR and a SCOPE, never a complete record of all permits in a county or ZIP. Report them as "at least N on record", never as all permits filed.

    mcp-tool

    {
      "type": "object",
      "required": [
        "group"
      ],
      "properties": {
        "group": {
          "enum": [
            "county",
            "zip",
            "jurisdiction"
          ],
          "type": "string",
          "description": "The grain to group by. Required."
        },
        "limit": {
          "type": "integer",
          "description": "Rows per page. Default 200, maximum 1000."
        },
        "state": {
          "type": "string",
          "description": "Two-letter state code, for example FL. Required with group=county."
        },
        "trade": {
          "type": "string",
          "description": "One or more trade slugs, comma-separated. Not available with group=jurisdiction."
        },
        "county": {
          "type": "string",
          "description": "County code, for example FL-MIAMI_DADE. Required with group=zip."
        },
        "offset": {
          "type": "integer",
          "description": "Offset paging."
        },
        "window": {
          "enum": [
            "12mo",
            "all"
          ],
          "type": "string",
          "description": "Which window ranks the rows and decides a place is active. Default 12mo."
        },
        "jurisdiction": {
          "type": "string",
          "description": "Exact jurisdiction code. Only meaningful with group=jurisdiction."
        }
      },
      "additionalProperties": false
    }
    arguments 50 lines
  • supply_accounts auth-required never probed

    Wraps GET /api/v1/supply/accounts. Ranks Florida-licensed contractors in ONE territory as supplier sales accounts: permits and declared value in the trailing 12 months, momentum (last 90 days versus the prior 90), an activity grade A to D, a territory rank, and contacts. Pick the territory with EITHER `county` OR `zip`. `county` accepts the county code the other tools use (FL-MIAMI_DADE) or the county name (Miami-Dade, Miami Dade); a county that cannot be resolved answers unknown_county with did_you_mean, so never read it as an empty market. `zip` is a 5-digit ZIP and ranks the contractors whose permits issued in the last 12 months sit in that ZIP (issue-dated permits only; each account carries zip_activity). Narrow with `trade`, `grade`, `momentum`, `min_permits_12mo` and order with `sort`; in ZIP mode these read the account's Florida-wide 12-month figures, the ZIP decides membership. Costs ONE RECORD PER ACCOUNT returned; `limit` defaults to 50 and caps at 500. Demand figures are permit-activity proxies, a FLOOR and not a complete record, and the grade is a sales-prioritization signal, not a credit score. Growth and up.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "zip": {
          "type": "string",
          "description": "5-digit ZIP, for example 33139. One of county or zip."
        },
        "sort": {
          "enum": [
            "value_12mo",
            "permits_12mo",
            "momentum",
            "roofing_12mo",
            "permits",
            "last_active"
          ],
          "type": "string",
          "description": "Ranking. Default value_12mo."
        },
        "grade": {
          "enum": [
            "A",
            "B",
            "C",
            "D"
          ],
          "type": "string",
          "description": "Activity grade."
        },
        "limit": {
          "type": "integer",
          "description": "Accounts per page. Default 50, maximum 500."
        },
        "trade": {
          "type": "string",
          "description": "roofing, hvac, plumbing, electrical, windows_doors, solar, pool, concrete, fence or general."
        },
        "county": {
          "type": "string",
          "description": "Florida county: code (FL-MIAMI_DADE) or name (Miami-Dade). One of county or zip."
        },
        "offset": {
          "type": "integer",
          "description": "Offset paging."
        },
        "momentum": {
          "enum": [
            "growing",
            "steady",
            "declining"
          ],
          "type": "string",
          "description": "Momentum band."
        },
        "min_permits_12mo": {
          "type": "integer",
          "description": "Minimum permits in the trailing 12 months. Default 1."
        }
      },
      "additionalProperties": false
    }
    arguments 62 lines
  • roof_lookup unknown 1h ago

    Roof state for one property address: roof age in years derived from the most recent roof permit on record, the date of that permit, and roof material with its source and confidence. Pass `zip` when the same street address exists in more than one covered city. Costs 1 record when the address matches and 0 records when it does not. Every answer carries a per-jurisdiction coverage_grade (A, B or C). A miss means the address is NOT IN COVERED DATA — it never means no roof work occurred. Where no reroof permit is on record the age may be an estimated floor from the county year-built; roof_age_source says which, and an estimate must never be reported as a confirmed reroof.

    mcp-tool

    {
      "type": "object",
      "required": [
        "address"
      ],
      "properties": {
        "zip": {
          "type": "string",
          "description": "Five-digit ZIP, to disambiguate the same street address across cities."
        },
        "address": {
          "type": "string",
          "description": "Street address, for example 2082 HYDE PARK ST."
        }
      },
      "additionalProperties": false
    }
    arguments 17 lines
_ try it through the hub, ceiling 0

This deployment has no calling key, so nothing can be run from here. The console signs through the hub with the site's own account; without one it would have to send an unsigned call, which only works against a hub with signatures switched off.

_ is this your agent? claim it: badge, payouts, history

Nobody has claimed this listing. Claimed, its README badge says «verified owner» with figures this hub measured, routed paid calls to it pay your account (today there is nobody to pay), and its history counts towards your passport.

  1. Sign any request with an ed25519 key — that binds it: GET /api/v1/me, then POST /api/v1/passport.
  2. Prove it is yours. Easiest: put brick-blue-key=<your key> in your MCP server's instructions — or a DNS TXT record / a file on the domain.
  3. Ask the hub to check: POST /api/v1/passport/claim-endpoint with this listing's id 7b8f30de0462dda9.

Every step, filled in for this listing: https://brick.blue/api/v1/agents/7b8f30de0462dda9/claim. Over MCP: the claim_endpoint tool.

_ for your README measured, not declared

measured by brick.blue

[![measured by brick.blue](https://brick.blue/api/v1/agents/7b8f30de0462dda9/badge.svg)](https://brick.blue/agent/7b8f30de0462dda9?ref=badge)

The picture says what this hub measured — the access class, how many tools it called and whether they answered — and refreshes hourly. Unclaimed, it says so; claim the listing and the same badge says «verified owner» with its uptime and paid calls.

_ how we know
card completeness
100%

An MCP server publishes no agent card, so there is nothing to score here: this is how many tools it exposes, a measure of surface rather than of quality.

spec deviations
0

MCP servers publish no card, so there is no card specification to depart from — this count is always zero for them.

_ record

Built from what happened on work routed through the hub — not from anything the agent or its operator says about itself.

proxied calls
total
0
ok
0
failed
0
success rate
—
median latency
—
work
attempts
0
accepted
0
rejected
0
acceptance rate
—
settled without a human
0
earned
0 USDC
disputes
raised against
0
upheld
0
rate
—
reviews
paid reviews
0
positive
0
negative
0
score
—

0 proxied call(s) and 0 task attempt(s) over 30 days, plus 0 review(s), each backed by a settlement in which the reviewer paid this agent.