# federal.contractors agent setup

Instructions for a coding agent or AI assistant adding federal.contractors
exclusion checks to a project. There are two paths. Connect over MCP so an
assistant runs checks in conversation, or call the REST API so the project's
own code runs checks. Both use the same bearer API key and the same record
credits.

federal.contractors runs federal exclusion checks against the SAM.gov
Exclusions public extract and seals every check as a permanent, publicly
linkable verification record. New records use format version 2 and cover the
record id, checked input, identity basis, customer confirmation when present,
candidate-set completeness, method versions, results, limitations, and exact
source provenance. The seal is SHA-256 over the stored RFC 8785 canonical
UTF-8 payload bytes. The record URL is the deliverable. A free SAM.gov search
is always sufficient for the compliance duty (2 CFR 180.300); this service
documents the check.

Recomputing the SHA-256 seal checks whether the canonical payload matches the
printed checksum. The checksum alone does not authenticate
federal.contractors as issuer or establish independent time. New production
records add an RFC 9943 SCITT PS256 issuer signature over the exact format 2
bytes and a DigiCert RFC 3161 timestamp over the RFC 9921 signature imprint.
The Timestamp Authority receives only the SHA-256 imprint of the CBOR-encoded
signature field and protocol metadata. The timestamp proves that issuer
signature existed no later than DigiCert's time. Neither mechanism proves
check execution time, source truth, matching correctness, identity, or a legal
outcome. No independent Transparency Service receipt is attached.

The record page exposes the bare `.scitt` statement and offline bundle. The
bundle retains the timestamp request and response, RFC 9921 timestamped
statement, Timestamp Authority trust anchor, and revocation lists. When
verifying a saved bundle, fetch `/scitt/issuer.json` separately from the bundle
over authenticated HTTPS and retain it. Do not treat the key history inside
the bundle as its own trust anchor; that would allow replacement of the
evidence, statement, public key, and manifest together. The timestamp trust
anchor is pinned by the verifier profile.

## Before you start

1. The user needs an API key (`fc_...`) from https://federal.contractors/keys.
   Keys are shown once at creation and only a hash is stored. If the user has
   no key, stop and ask them to create one.
2. Never commit the key. Read it from an environment variable (suggested name:
   `FEDERAL_CONTRACTORS_API_KEY`) and add it to the project's env example file
   as an empty placeholder.
3. Every account receives a one-time allowance of 50 API-created
   verification records without charge. Creating a new sealed record
   reduces the available credit balance by one. Additional credits are
   purchased upfront as a $50 prepaid pack of 100 record credits (see
   https://federal.contractors/pricing). Fetching an existing record is
   included and does not reduce the balance.

## Path 1: MCP server

The hosted MCP endpoint is `POST https://federal.contractors/mcp`. Streamable
HTTP, stateless, JSON responses only. No OAuth, no SSE, no sessions. Any MCP
client that supports streamable HTTP can connect. Send the API key as an
`Authorization: Bearer` header. The config file name and top-level key vary by
client (Cursor, Windsurf, VS Code, and others); the endpoint and header are
the same everywhere. The common `mcpServers` shape:

```json
{
  "mcpServers": {
    "federal-contractors": {
      "type": "http",
      "url": "https://federal.contractors/mcp",
      "headers": { "Authorization": "Bearer fc_your_key" }
    }
  }
}
```

Claude Code registers the same endpoint with one command:

```sh
claude mcp add --transport http federal-contractors \
  https://federal.contractors/mcp \
  --header "Authorization: Bearer fc_your_key"
```

Clients without native HTTP MCP support (Claude Desktop among them) connect
through the mcp-remote stdio bridge (requires Node.js 18+), in
`claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "federal-contractors": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://federal.contractors/mcp",
        "--header",
        "Authorization: Bearer fc_your_key"
      ]
    }
  }
}
```

Three tools:

- `verify_entity` with `{ "query": string }`: runs one exclusion check by UEI
  (12 characters), CAGE code, or legal name (3 to 200 characters), seals and
  signs a verification record, and returns match results, the record URL, the
  SHA-256 seal, SCITT Signed Statement metadata, and remaining credits. Consumes one
  credit.
- `verify_batch` with `{ "queries": string[] }`: 1 to 100 entries, one signed
  record and one credit each. Items after credit exhaustion fail individually
  while the rest succeed.
- `get_record` with `{ "id": string }`: fetches an existing sealed record by
  id (`vr_...`), including Signed Statement metadata and download URLs when present. Free,
  consumes no credits.

## Path 2: REST API

Machine-readable spec: https://federal.contractors/openapi.json. Human
documentation: https://federal.contractors/docs.

Authentication: `Authorization: Bearer fc_your_key` on every request. The API
and MCP endpoint send no CORS headers by design: call them from server-side
code or a desktop client, never from browser JavaScript, which would also
expose the key.

`POST https://federal.contractors/v1/verify` with body
`{ "query": "UEI, CAGE code, or legal name" }`:

```sh
curl -X POST https://federal.contractors/v1/verify \
  -H "Authorization: Bearer fc_your_key" \
  -H "Content-Type: application/json" \
  -d '{"query": "RZK2AJC7QGA3"}'
```

The response contains:

- `record`: `{ id, formatVersion, sha256, url, scitt }`. New records report
  format version 2. `record.scitt` carries the issuer-asserted issuance time,
  SPKI-derived key id, and `timestamp` metadata with the authority, policy OID,
  and independent timestamp time. `record.url` is permanent and public by
  unguessable id.
- `query`, `matchType` (`"uei"`, `"cage"`, or `"name"`), `checkedAt` (UTC
  timestamp), and `identityStatus`.
- `matchingMethod`, `matchingVersion`, and `normalizationVersion`: the exact
  matching contract used.
- `resultStatus`: `matched_uei`, `potential_match`, or
  `no_active_exclusion_record_matched`.
- `total`, `matches`, and `truncated`: the full candidate count, up to 200
  returned candidate rows, and whether that returned list is incomplete. Each
  candidate carries its identity state, match basis, and field-level agreements
  or contradictions.
- `source`: the SAM.gov Exclusions extract snapshot the check ran against,
  including its artifact name, as-of and retrieval times, source-freshness
  classification at check time, record and invalid-row counts, byte count, and
  SHA-256 digest.
- `credits`: `{ included, purchased, used, remaining }`.

`POST https://federal.contractors/v1/verify/batch` with body
`{ "queries": string[] }` (1 to 100 items) runs the same check per item and
seals one record each. Rows carry the query, match type, result status,
candidate total, truncation and version fields, and record reference. Full
evidence remains at each record URL.

`GET https://federal.contractors/v1/records/{id}` fetches an existing sealed
record by id (`vr_...`). Free and keyless; the unguessable id is the
capability. It returns the format version, canonicalization method, sealed
results, source provenance, separate check, issuer, independent timestamp, and
source times, SHA-256 seal, and Signed Statement metadata when present.
Operational account-ownership fields and canonical-byte storage columns are
not exposed. Identity already sealed into a historical packet remains part
of its immutable payload. The permanent page links to bare statement and
offline bundle downloads. Use this route to re-fetch evidence without
spending a credit.

Keyless endpoints for smoke tests: `GET https://federal.contractors/health`
(liveness) and `GET https://federal.contractors/v1/stats` (public registry
stats). Note that every successful `/v1/verify` call consumes a real credit
and seals a real record, so test with one call, not a loop.

## What to store

Persist `record.id`, `record.formatVersion`, `record.url`, `record.sha256`,
`record.scitt`, `checkedAt`, and the source artifact's as-of time, retrieval
time, digest, and completeness facts alongside the counterparty you checked.
Treat the rest of the API response as transient; the full evidence payload and
Signed Statement downloads live at the record URL. Re-checks create new signed records.
Keep the history, do not overwrite earlier records.

## Interpreting results

- `resultStatus: "no_active_exclusion_record_matched"` means no active
  exclusion record matched under the recorded method, as of the extract named
  in `source`. It is not a present-tense status and not a verdict.
- `resultStatus: "matched_uei"` means at least one active exclusion record
  matched the searched UEI exactly. Report it as "matched this UEI".
- `resultStatus: "potential_match"` means a person must review the candidate
  basis and field agreements or contradictions. CAGE and name candidates do not
  become UEI matches.
- `matchType` describes how the input was classified. It is not the outcome.
- `truncated: true` means the returned candidate list is incomplete. Do not
  present it as a complete candidate review.

## Errors and record balance

Every non-2xx response uses one envelope:
`{ "error": { "code": <http status>, "message": "..." } }`.

- `400`: malformed body. Fix the request, do not retry as-is.
- `402`: no record credits remain in the account balance. Do not retry;
  surface it to the user with a link to https://federal.contractors/pricing.
- `429`: request rate limit. The response carries a `Retry-After` header;
  honor it before retrying.

Surface the `credits.remaining` record balance to the user when it runs low.

## Copy rules for any UI you build

If you render results in an interface, follow these rules. They mirror the
regulatory language of 2 CFR 180.300 and keep the product's claims honest.

- The system checks; the person verifies. Write "exclusion check", "checked",
  "re-checked". Never write that the integration "verified" a vendor and
  never write "verified clear".
- Date every status: "No active exclusion record matched, as of the
  2026-08-14 extract". Never present a check result as what is true right
  now.
- Show provenance wherever results display: the check time, source (SAM.gov
  Exclusions), source as-of time, and retrieval time. Keep those times distinct.
- Never promise compliance or audit outcomes. A record is evidence of
  diligence, not a verdict.
- federal.contractors is not affiliated with the U.S. government. Do not use
  government seals or .gov-style styling around the results.
