---
name: premiumpin-parcel-query
description: Query parcel slots and request bounded CSV exports.
version: 0.1.16
author: Brett (PremiumPin), Hermes Agent
platforms: [macos, linux]
metadata:
  hermes:
    tags: [parcels, closed-catalog, mcp]
    related_skills: []
---

# PremiumPin parcel query

Customer skill for the packaged PremiumPin STDIO MCP server. Uses the existing
closed-catalog client; does not build SQL, read parcel files, create credentials,
grant access, or bypass server-side entitlement/privacy controls.

## When to Use

- Search parcel records by supported slots, look up a parcel key, match a
  bounded batch, request a CSV export, save accepted search criteria, or draft
  property-only criteria from a small exact-key CSV through the MCP tool.
- Do not use for arbitrary SQL, probate, phones, emails, invented fields,
  tenant/credit/employment screening, or telemarketing.

## Prerequisites

Install the accompanying wheel and hash-locked dependencies as described in
`README.md`. Register the `premiumpin` STDIO server using the placeholder-only
`mcp-config.example.json`. The customer supplies their authorized `PP_API_KEY`
only to the host's runtime process environment. Never request, inspect, print,
store, or mint a key. Do not edit agent profiles automatically.

The default API is `https://api.premiumpin.com`. Preserve the actual serving
snapshot reported by the API; the package is not a grant of service access.
The website handles marketing, account access, and agent/API instructions at
`https://premiumpin.com/api/#agents`; search and export use MCP or the API.
Questions and export operations are unlimited. Each paid account has its own
1,000,000 delivered-row allowance per UTC month across channels; each export
is capped at 5,000 rows. Omit `select` for all available canonical fields,
up to 91, with honest blanks for fields not held on a parcel.
If no authorized key is available, explain the missing prerequisite; do not
try other credentials or invent an open/free/paid entitlement.

## How to Run

Use the registered MCP tools, not the retired checkout-only CLI:
`coverage_check`, `field_catalog`, `count_properties`, `parcel_lookup`, `property_search`, `batch_match`,
`export_properties`, `saved_search`, `profile_properties`, `parcel_list`, and
`prepare_mailing_list`. Tool arguments
never contain a key or API URL.

For host setup only, the STDIO command is
`terminal(command="<venv-python> -I -B -m premiumpin_customer")`;
a protocol-speaking MCP host must supply stdin. This is not an HTTP server
or an interactive terminal application. Installing/loading this skill alone
will not register the MCP process for the host.

## Procedure

1. Confirm the actual host completed MCP initialize and lists all eleven tools.
   Call `coverage_check` before data work. Stop on a missing/unexpected snapshot
   or service error. Health metadata does not establish county capability,
   customer entitlement, query count or scope exhaustion.
   Use `field_catalog(fips)` before a field-sensitive search; it reports canonical
   names, operators, county availability, and the current account's entitlement.
2. Route an explicit single `(fips, parcel_id)` key to
   `parcel_lookup(fips, parcel_id)`. Route 1–100 explicit key pairs to
   `batch_match(items=[{"fips":"04021","parcel_id":"123-45-678"}, ...])`;
   preserve input order and report each returned found/unmatched result.
   A non-404 lookup failure, county-not-held 404, or snapshot change aborts the batch; report that
   error rather than claiming a per-key result. These tools accept exact
   keys, not uploaded CSVs, addresses, saved lists or
   customer profiles. For a criteria request, send the complete wording as
   `question` to `property_search` or `export_properties`. The shared
   interpreter preserves range endpoints, ZIP sets, owner/address literals
   and bounded geography. Do not compress repeated bounds into a one-value
   slot map or discard unknown words.
   Route count questions to `count_properties`; its exact aggregate returns no
   parcel rows and does not use the delivered-row allowance.
3. If the tool returns `clarify` or `unsupported`, no row request was made.
   Show its question/reason. Forward its returned `state` as `previous_plan`
   with the user's next answer. Unresolved changes block search/export until
   resolved or explicitly cancelled; never fall back to the older plan. Show
   every `dropped_constraints` entry rather than silently omitting a request.
4. Explicit structured `slots` remain supported for existing integrations.
   Search ranges and ZIP membership through the question path. ZIP requests
   need bounded county/state context; do not infer a ZIP-to-county mapping.
   Explicit single-family/SFR in Harris County, Texas uses its A1 appraisal
   category. In Pinal County, Arizona, it uses 42 exact assessor-use codes,
   including model-home and nonconforming-zoning modifiers and the `871`
   family for sites over five acres. Neither category independently verifies
   a physical or habitable building. Preserve the returned classification
   explanation and full conversation state. Broad residential and unmapped
   county classes remain unavailable. Roof age, equity,
   motivation and saved campaigns are not established capabilities. Unsupported is not zero matching rows.
   `saved_search` keeps only account-owned accepted criteria; it does not save
   campaigns, recipient lists, exclusions, parcel rows, or CSV profiles.
5. Use named `select` only when the user requests specific output fields.
   Example: `{"question":"market value between 150k and 300k in Harris County Texas","limit":25}`.
   For a correction, send the next question with the prior returned state.
   For CSV, call `export_properties` with that state and `question:"export these"`.
   For a requested next question-based API/MCP result page, require a nonempty prior
   `next_cursor` and pass it unchanged
   as `cursor` to `property_search` with the same accepted state as
   `previous_plan`, the same `limit` and `select`, and `question:"show these"`.
   Structured searches return no language state: repeat the original scope,
   `slots`, `select` and `limit` with the nonempty returned cursor. Never pass
   a missing cursor as a continuation; it would restart the first page.
   A bare `question:"next page"` is not a supported continuation phrase.
   Do not start over, alter the criteria, or chain additional paid pages
   without the customer's request. These are input examples, not evidence
   of actual rows or access.
6. For an explicit save, pass the complete ready response's `state` as
   `saved_search(operation="create", name=..., search_state=...,
   idempotency_key=...)`. Use one stable idempotency key for retries of the
   same create request. `list` and `get` return metadata or current accepted
   state without a parcel snapshot claim; `update` and `delete` require the
   saved ID and current `expected_revision`. A revision conflict needs a fresh
   get and customer decision. To run loaded criteria, wait for an explicit
   request and pass the loaded state as `previous_plan` to
   `property_search(question="show these")` or
   `export_properties(question="export these")`. Loading never executes or
   grants entitlement. Set the data tool's `limit` no higher than the loaded
   state's accepted plan limit; also obey the tool's own cap. Do not auto-page
   or auto-export.
7. For a buyer-supplied exact-key CSV, call `profile_properties(csv_text=...)`
   only after explaining that it makes actual `batch_match` parcel lookup
   calls and consumes applicable allowance. The UTF-8 CSV must contain exactly
   `fips,parcel_id` columns, at most 100 data rows and 64 KiB. Preserve exact
   five-digit FIPS and parcel IDs. Report each invalid or unmatched row and
   duplicate input row; duplicates do not bias the summary. Explain field
   denominators and missing values. Numeric ranges are editable drafts from
   observed property fields only, not a lookalike model or verified buyer
   criteria. Review and adjust them with the buyer before any explicit
   `property_search` request. Profiling never automatically searches similar
   properties or saves a profile. This is an MCP tool, not a website CSV upload.
8. Call the requested data tool only with customer authorization. Search
   pages are capped at 1,000 rows, exports at 5,000 requested rows, FIPS
   lists at 50 counties, batches at 100 keys, and responses at 512 KiB. A
   server-side allowance can impose a lower cap. Do not auto-retry billable
   requests on an ambiguous failure or stitch partial deliveries into an
   unsupported completeness claim.
9. Preserve returned snapshot, limitations and scope/receipt metadata.
   For an export, `delivery_complete` is not the same as `complete`.
   Claim whole-scope completion only if the tool's `complete` is true with
   its validated receipt/execution proof and available scope. Otherwise label
   the actual status: partial, truncated, incomplete, error or not-started.
   Write a CSV only when requested, disclose any incompleteness, and never
   fabricate rows, values, counts, null replacements or coverage.

## Saved parcel lists and mailing preparation

Use `parcel_list` only for an explicit customer request to keep supplied exact
`fips` and `parcel_id` keys. Preserve leading zeros. Create uses a stable
`idempotency_key`; updates and deletes require `expected_revision`. A list can
contain up to 5,000 supplied keys; an account can keep 25 active lists. Loading
or saving a list makes no parcel query and does not prove those keys were mailed.
For a large list, create/update may acknowledge only its ID, revision, ordered
input count and key digest. `get` returns bounded ordered key pages with
`offset` and `next_offset`; use the returned revision on subsequent pages and
verify the complete ordered count and digest. A list page is saved user input,
not a parcel result page or export receipt.

For an explicitly requested mailing export, use `prepare_mailing_list`. Explain
that it makes an export call and consumes applicable allowance. An exclusion
list must be fetched at the requested revision before that export. Exclusion
is by exact parcel key, not recipient-level campaign history. Recipient grouping
requires entitled returned owner name, mailing street, city, state and ZIP;
missing details remain unknown and are not guessed. Grouping only collapses
case and whitespace, preserving punctuation and unit information.

Report source coverage and caps alongside derived counts. Never describe a
filtered 5,000-row delivery as the full market or automatically fetch more
rows to replace exclusions. Keep the separate derived manifest and CSV hash;
the source receipt certifies only the original delivery. These tools do not
send mail, manage campaigns or add a website upload screen.
For `export_properties`, prepared private artifacts are the supported path for
larger CSVs. A small result may be delivered inline. A prepared response has an
`artifact.path` and a receipt. Fetch the exact bytes with the same account's
authorization within 24 hours; the path alone is not a credential. Hosted
OAuth uses the authenticated `/mcp/artifacts/{id}` bridge. Preserve the receipt
and verify the downloaded bytes against the artifact SHA-256. Use the same explicit
`idempotency_key` for retries and a new key for a new operation after
expiry. The client does not generate an operation key from the request body.
An export can settle before the derived mailing response reaches this client's
512 KiB limit. In that case the tool returns a typed `response-too-large`
error with bounded `recovery` evidence: verified source CSV and receipt when
they fit, otherwise the exact export request and any known receipt. The
optional `idempotency_key` is forwarded to the export request, but the client
does not claim replay is safe for every account or TEST/LIVE mode. The recovery
envelope says whether source bytes were actually delivered. Never make a
second paid call automatically; a direct API recovery requires the same
account's authentication and a deliberate review of settlement status.

For a missing or ambiguous county, forward the full returned pending state
when the buyer answers. Do not drop the known class, size or year criteria.
An ambiguous county name needs its state; a class unsupported in that county
is not permission to substitute another county's codes.

## Pitfalls

- Absentee means owner/mailing street differs from site street, not necessarily
  an out-of-state owner. Use `owner_absentee`; never write SQL.
- A named field can be syntactically supported but unavailable on a county.
  Preserve the server's `field-not-held` response and do not infer zero matches.
- Vermont remains excluded. Legal exclusions and NJ owner-name suppression
  remain server-side requirements; packaging tests do not certify them.
- A fixed data-version match is not a count proof. The query path preserves
  the server response; it does not manufacture an independent CountProof.
- Public continuation cursors are opaque. Do not decode, edit or invent them;
  expired/unavailable tokens need an explicit customer decision about restarting,
  never an automatic billable retry. Public execution facts omit private ranges,
  raw fetched counts and suppressed identifiers; do not infer them.
- API errors, quotas, authentication failure and receipt-validation failures
  are not invitations to broaden scope, change host, weaken checks or find keys.
- The built-in geographic CSV is a county map, never evidence that parcels
  for that county are currently held. Do not rebuild the backend or website.

## Verification

Verify that the host lists all eleven tools and that real parcel-data tool results
retain snapshot/limitation information. Saved-search metadata does not claim a
parcel snapshot. Never use TESTONLY mocked responses as live
service evidence. If key installation, service access, scope availability or
complete delivery has not been demonstrated, state that specific limitation.
