# Plumbline - Contractor License Checks

> Free contractor-license checks from official state records; a no-match never proves unlicensed.

- name: ai.agentlookups/plumbline
- version: 1.0.1
- connection class: R0 (autonomous)
- trust: 80/100 flags: no-repository
- quality: 77/100 (good)
- owner: not claimed
- descriptor: https://api.protogrid.dev/v1/servers/ai.agentlookups%2Fplumbline
- tools: https://api.protogrid.dev/v1/servers/ai.agentlookups%2Fplumbline/tools

**An agent can connect right now, no human step.** Remote endpoint, no authentication, reachable on the last probe.

## Connection (mcpServers)

```json
{
  "mcpServers": {
    "plumbline": {
      "type": "http",
      "url": "https://contractors.agentlookups.ai/mcp"
    }
  }
}
```


## Trust

- hygiene: 80
- liveness: 100
- freshness: 85
- provenance: 55
- drivers: +dns-namespace +website +reachable +uptime-100% ~updated-55d-ago -no-repository
- Derived from observable signals (official registry feed and our own credential-free probes); no code audit performed.

## Quality 77/100 (good)

### protocol: 75 (weight 25)

- warn `protocol.modern`: newest supported version is 2025-06-18; 2026-07-28 not supported, older versions are deprecated until 2027-07-28
- n/a `protocol.stateless`: only applies to 2026-07-28 servers
- pass `protocol.transport`: streamable HTTP
- n/a `protocol.list_ttl`: only applies to 2026-07-28 servers

### authorization: n/a (weight 15)

- n/a `auth.prm`, `auth.as_metadata`, `auth.cimd`: no remote uses OAuth
- n/a `auth.secret_in_url`: no templated URL

### tool hygiene: 93 (weight 30)

- pass `tools.descriptions`: every tool has a description
- warn `tools.description_length`: 1 tools have descriptions over 1,024 characters, which crowds the context
- pass `tools.schemas`: every tool has an object input schema
- pass `tools.annotations`: 1 of 1 tools declare readOnlyHint or destructiveHint
- pass `tools.directory_hints`: every tool declares readOnlyHint, destructiveHint, idempotentHint and openWorldHint
- pass `tools.token_cost`: about 950 tokens to load every tool
- pass `tools.api_dump`: tools are not a one-to-one API dump

### stability: 50 (weight 15)

- pass `stability.changes`: 3 tool changes in 30 days
- fail `stability.rug_pull`: 1 tools kept their name but changed most of their description in 30 days; review before trusting them

### dependencies: n/a (weight 15)

- n/a `deps.known_vulns`, `deps.mcp_sdk_version`, `deps.resolvable`: no npm or PyPI package

- tools: 1, about 950 tokens to load them all
- tool set hash: df19a58cabd7c303a7cec72f7224c4e2
- tools last changed: 2026-10-08T08:58:11.890Z
- badge: [![protogrid quality](https://protogrid.dev/badge/ai.agentlookups/plumbline.svg)](https://protogrid.dev/servers/ai.agentlookups/plumbline)
- Checks run on what our credential-free, read-only probes observe; tools are never called and no code audit is performed.

### Tool changes

- 2026-10-08 `check_contractor` changed (description, inputSchema)
  - before: Looks up a contractor's public credential in indexed state and local licensing records. Licenses, registrations and bond records mean different things. Each record carries a credential object (kind, label, note): kind is license, registration, business_license or bond when the source makes that clear; otherwise it is the generic "credential", and the note says what to verify with the issuing agency. The set of covered jurisdictions changes as sources are added, so this description does not list it. Inputs: a record number (license) or business name, with optional jurisdiction and exact listed city, or an entity_id from an earlier result, which selects that one record. Results: match (the credential record with its status and provenance); candidates (several records fit; each page holds up to 20 rows, total_candidates is the full count, offset pages through the rest, and entity_id selects one; a field with the same value on every row of a page is given once, in same_for_all_rows, and each row's entity block omits what the row already states); no_match_in_index (the index holds no record for that input, which does not mean the contractor is unlicensed; for a search across all jurisdictions, the message states how many covered jurisdictions were searched); or jurisdiction_not_covered (the requested jurisdiction is outside the index, with an official pointer URL where one is on file; the response message states exactly what the link is, or that none is on file, and for some jurisdictions the link is a consumer-protection or licensing-board page, not a license lookup).
  - after: Looks up a contractor's public credential in indexed state and local licensing records. Licenses, registrations and bond records mean different things. Each record carries a credential object (kind, label, note): kind is license, registration, business_license or bond when the source makes that clear; otherwise it is the generic "credential", and the note says what to verify with the issuing agency. The set of covered jurisdictions changes as sources are added, so this description does not list it. Inputs: a record number (license) or business name, with optional jurisdiction and exact listed city, or an entity_id from an earlier result, which selects that one record. Results: match (the credential record with its status and provenance); candidates (several records fit; each page holds up to 20 rows, total_candidates is the full count, offset pages through the rest, and entity_id selects one; a field with the same value on every row of a page is given once, in same_for_all_rows, and each row's entity block omits what the row already states); no_match_in_index (the index holds no record for that input, which does not mean the contractor is unlicensed; for a search across all jurisdictions, the message states how many covered jurisdictions were searched); or jurisdiction_not_covered (the requested jurisdiction is outside the index, with an official pointer URL where one is on file; the response message states exactly what the link is, or that none is on file, and for some jurisdictions the link is a consumer-protection or licensing-board page, not a license lookup). Each record carries as_of_date: the publisher's own last-updated date where we have read one, else the day of our fetch. The freshness field on a match, and freshness_notes on candidates and on a no-match with a jurisdiction, state when a source's copy is behind its normal update schedule, slow to refresh by design, or still on its first full pass, with a plain note, the dates, and the issuing body's own lookup.
- 2026-09-28 `check_contractor` changed (title, description, inputSchema) **meaning changed**
  - before: Check a contractor's public credential against indexed state and local records. Licenses, registrations and bond records have different meanings; use the returned credential description. The covered set grows over time; GET /v1/coverage on this host for the exact current list, and never assume from this description whether a jurisdiction is covered. Provide a record number or business name, optionally jurisdiction and exact listed city; select a candidate with entity_id. Returns match (the credential record with status and provenance), candidates (disambiguate and call again; page with offset), no_match_in_index (NOT a determination of unlicensure), or jurisdiction_not_covered (with an official pointer URL for that jurisdiction; the response message states exactly what the link is, which for some jurisdictions is a consumer-protection or licensing-board page rather than a license lookup, so relay the message's wording and never present the link as a license lookup unless the message says it is one).
  - after: Looks up a contractor's public credential in indexed state and local licensing records. Licenses, registrations and bond records mean different things. Each record carries a credential object (kind, label, note): kind is license, registration, business_license or bond when the source makes that clear; otherwise it is the generic "credential", and the note says what to verify with the issuing agency. The set of covered jurisdictions changes as sources are added, so this description does not list it. Inputs: a record number (license) or business name, with optional jurisdiction and exact listed city, or an entity_id from an earlier result, which selects that one record. Results: match (the credential record with its status and provenance); candidates (several records fit; each page holds up to 20 rows, total_candidates is the full count, offset pages through the rest, and entity_id selects one; a field with the same value on every row of a page is given once, in same_for_all_rows, and each row's entity block omits what the row already states); no_match_in_index (the index holds no record for that input, which does not mean the contractor is unlicensed; for a search across all jurisdictions, the message states how many covered jurisdictions were searched); or jurisdiction_not_covered (the requested jurisdiction is outside the index, with an official pointer URL where one is on file; the response message states exactly what the link is, or that none is on file, and for some jurisdictions the link is a consumer-protection or licensing-board page, not a license lookup).
- 2026-09-27 `check_contractor` changed (description, inputSchema, annotations)
  - before: Check a contractor's license against official state and local licensing records covering dozens of US jurisdictions. The covered set grows over time; GET /v1/coverage on this host for the exact current list, and never assume from this description whether a jurisdiction is covered. Provide a license number or a business name, plus the jurisdiction. Returns match (the license record with status and provenance), candidates (disambiguate and call again; page with offset), no_match_in_index (NOT a determination of unlicensure), or jurisdiction_not_covered (with an official pointer URL for that jurisdiction; the response message states exactly what the link is, which for some jurisdictions is a consumer-protection or licensing-board page rather than a license lookup, so relay the message's wording and never present the link as a license lookup unless the message says it is one).
  - after: Check a contractor's public credential against indexed state and local records. Licenses, registrations and bond records have different meanings; use the returned credential description. The covered set grows over time; GET /v1/coverage on this host for the exact current list, and never assume from this description whether a jurisdiction is covered. Provide a record number or business name, optionally jurisdiction and exact listed city; select a candidate with entity_id. Returns match (the credential record with status and provenance), candidates (disambiguate and call again; page with offset), no_match_in_index (NOT a determination of unlicensure), or jurisdiction_not_covered (with an official pointer URL for that jurisdiction; the response message states exactly what the link is, which for some jurisdictions is a consumer-protection or licensing-board page rather than a license lookup, so relay the message's wording and never present the link as a license lookup unless the message says it is one).

Full history: https://api.protogrid.dev/v1/servers/ai.agentlookups%2Fplumbline/changes

## Remotes

- https://contractors.agentlookups.ai/mcp (streamable-http, auth none, reachable true, uptime30d 1)

## Packages

_none_

## Tools (1)

- `check_contractor`: Looks up a contractor's public credential in indexed state and local licensing records. Licenses, registrations and bond records mean different things. Each record carries a credential object (kind, label, note): kind is license, registration, business_license or bond when the source makes that clear; otherwise it is the generic "credential", and the note says what to verify with the issuing agency. The set of covered jurisdictions changes as sources are added, so this description does not list it. Inputs: a record number (license) or business name, with optional jurisdiction and exact listed city, or an entity_id from an earlier result, which selects that one record. Results: match (the credential record with its status and provenance); candidates (several records fit; each page holds up to 20 rows, total_candidates is the full count, offset pages through the rest, and entity_id selects one; a field with the same value on every row of a page is given once, in same_for_all_rows, and each row's entity block omits what the row already states); no_match_in_index (the index holds no record for that input, which does not mean the contractor is unlicensed; for a search across all jurisdictions, the message states how many covered jurisdictions were searched); or jurisdiction_not_covered (the requested jurisdiction is outside the index, with an official pointer URL where one is on file; the response message states exactly what the link is, or that none is on file, and for some jurisdictions the link is a consumer-protection or licensing-board page, not a license lookup). Each record carries as_of_date: the publisher's own last-updated date where we have read one, else the day of our fetch. The freshness field on a match, and freshness_notes on candidates and on a no-match with a jurisdiction, state when a source's copy is behind its normal update schedule, slow to refresh by design, or still on its first full pass, with a plain note, the dates, and the issuing body's own lookup.
