MCP Server

GAIP Witness Agent

io.github.tjcgraham-rgb/gaip-witness
MCP & Agent Infrastructure Security Public & reachable MCP 2026-07-28

What this MCP does

W witnesses service delivery, verifies citations and receipts, and monitors public agents or MCP servers for changes.

gaip_check_sar_receipt
Check an x402 SAR receipt
Use this when handed an x402 SAR-shaped receipt (draft proposal shape; may change). Pass `sar_receipt`, optionally the issuer's `public_key`. Returns missing fields, whether receipt_id matches the core and whether the signature checks out against that key. Free, read-only, no account; inputs must be public and non-personal.
Read only Idempotent
Input schema
{'type': 'object', 'examples': [{'public_key': 'Y8BpzlWPH3EPRQziEPRBeLS1lJBF4xEo9WaxTNbzNp0', 'sar_receipt': {'ts': '2026-10-01T09:00:00Z', 'sig': 'ogilW-bjlCbYkwwUAIrg_zm_Wuoc6EiRgeErs0RL7llP7FWyX43-LgozZFyCjCXgsViK-A4_aroOo16Q4uvTCg', 'sig_alg': 'Ed25519', 'verdict': 'PASS', 'confidence': 1.0, 'receipt_id': 'sha256:17146cdeb5aba1c269130348cdc7d3d96ae55f6e048b81d3baa59d4e3f3b188b', 'reason_code': 'SPEC_MATCH', 'task_id_hash': 'sha256:c8b36982316351a28e040a6520df2092c2c87a4ea611c123d04993074b2b6f1d', 'verifier_kid': 'ef654fc8b615b51c', 'receipt_version': '0.1'}}], 'required': ['sar_receipt'], 'properties': {'public_key': {'oneOf': [{'type': 'string', 'maxLength': 512}, {'type': 'object'}], 'description': "Optional: the issuer's Ed25519 public key, raw 32 bytes base64url or a JWK {kty: OKP, crv: Ed25519, x}. Omit to use GAIP's published keys."}, 'sar_receipt': {'type': 'object', 'description': 'The SAR receipt object (or a whole gaip_receipt_export x402 result).'}}, 'additionalProperties': False}
gaip_citation_witness
Verify citations and quotes
Use this when asked to verify citations or quotes ("do these sources really say this?"). Pass `citations` (1-20 {url, quote}). GAIP fetches each page once (robots.txt respected); returns QUOTE_FOUND / QUOTE_NOT_FOUND_IN_FETCHED_VERSION / SOURCE_UNREACHABLE..., an excerpt and a receipt. Free, read-only, no account; inputs must be public and non-personal.
Read only Open world
Input schema
{'type': 'object', 'examples': [{'citations': [{'url': 'https://www.gaipagents.com/', 'quote': 'GAIP', 'claimed_title': 'GAIP'}]}], 'required': ['citations'], 'properties': {'citations': {'type': 'array', 'items': {'type': 'object', 'required': ['url'], 'properties': {'url': {'type': 'string', 'format': 'uri', 'maxLength': 2048}, 'quote': {'type': 'string', 'maxLength': 2000}, 'claimed_date': {'type': 'string', 'maxLength': 64}, 'claimed_title': {'type': 'string', 'maxLength': 500}}, 'additionalProperties': False}, 'maxItems': 20, 'minItems': 1, 'description': '1-20 citations, each {url, quote?, claimed_title?, claimed_date?}.'}, 'data_classification': {'enum': ['PUBLIC', 'NON_PERSONAL_PUBLIC'], 'type': 'string', 'default': 'PUBLIC', 'description': 'PUBLIC (default) or NON_PERSONAL_PUBLIC. Never send personal data.'}}, 'additionalProperties': True}
gaip_receipt_export
Export a GAIP receipt
Use this when you need a GAIP receipt in another format. Pass `receipt_id` and `format`: x402 (attestation style), erc8004 (validation-response shape) or vc (W3C-VC-like JSON-LD). Ed25519-signed when the runtime key is available; hash chain and Merkle proof; no on-chain write. Free, read-only, no account; inputs must be public and non-personal.
Read only Idempotent
Input schema
{'type': 'object', 'examples': [{'format': 'x402', 'receipt_id': '<receipt_id returned by any GAIP tool>'}], 'required': ['receipt_id', 'format'], 'properties': {'format': {'enum': ['x402', 'erc8004', 'vc'], 'type': 'string', 'description': 'x402, erc8004 or vc.'}, 'receipt_id': {'type': 'string', 'maxLength': 128, 'minLength': 1, 'description': 'A receipt_id returned by an earlier GAIP call.'}}, 'additionalProperties': False}
gaip_watch_events
Read watch change events
Use this when asked what changed on a watched agent or service. Pass your `continuity_handle` and optionally a `watch_id`. Returns recent change events: verdict before and after, a change summary, the receipt and webhook delivery status. Free, read-only, no account; inputs must be public and non-personal.
Read only Idempotent
Input schema
{'type': 'object', 'examples': [{'limit': 10, 'watch_id': '<watch_id from gaip_watch_register>', 'continuity_handle': {'token': '<continuity_handle.token returned by any GAIP tool>', 'continuity_id': '<continuity_handle.continuity_id returned by any GAIP tool>'}}], 'required': ['continuity_handle'], 'properties': {'limit': {'type': 'integer', 'maximum': 50, 'minimum': 1, 'description': 'Optional: maximum events to return.'}, 'watch_id': {'type': 'string', 'description': 'The watch_id returned by gaip_watch_register.'}, 'continuity_handle': {'type': 'object', 'required': ['continuity_id', 'token'], 'properties': {'token': {'type': 'string'}, 'continuity_id': {'type': 'string'}}, 'description': 'The continuity_handle from an earlier GAIP result; proves you own these watches.'}}, 'additionalProperties': False}
gaip_watch_list
List my watches
Use this when asked which agents or services you are watching. Pass your `continuity_handle`. Returns each watch's kind, target, last verdict, last and next check and webhook endpoint (never the secret). Free, read-only, no account; inputs must be public and non-personal.
Read only Idempotent
Input schema
{'type': 'object', 'examples': [{'continuity_handle': {'token': '<continuity_handle.token returned by any GAIP tool>', 'continuity_id': '<continuity_handle.continuity_id returned by any GAIP tool>'}}], 'required': ['continuity_handle'], 'properties': {'continuity_handle': {'type': 'object', 'required': ['continuity_id', 'token'], 'properties': {'token': {'type': 'string'}, 'continuity_id': {'type': 'string'}}, 'description': 'The continuity_handle from an earlier GAIP result; proves you own these watches.'}}, 'additionalProperties': False}
gaip_watch_register
Watch an agent or MCP server for changes
Use this when asked to keep an eye on an agent or MCP server ("tell me if it changes or goes down"). Pass the `continuity_handle` from any GAIP result, `kind` and `target_url`. GAIP re-checks every 24 hours (3 free watches), receipts each change and can call your webhook. Free, no account; records a GAIP receipt only. Inputs must be public and non-personal.
Open world
Input schema
{'type': 'object', 'examples': [{'kind': 'SUPPLIER_CARD', 'target_url': 'https://weather.example.com/.well-known/agent-card.json', 'webhook_url': 'https://hooks.example.com/gaip-watch', 'interval_hours': 24, 'continuity_handle': {'token': '<continuity_handle.token returned by any GAIP tool>', 'continuity_id': '<continuity_handle.continuity_id returned by any GAIP tool>'}}], 'required': ['continuity_handle', 'kind'], 'properties': {'sla': {'type': 'object', 'description': 'DELIVERY_SLA only: service-level terms checked on every observation, any of min_uptime_pct, max_latency_ms, required_fields (JSON key paths), freshness_field + max_age_seconds; optional uptime_window_hours, min_observations. Results go only to you.'}, 'kind': {'enum': ['AGENT_READINESS', 'DELIVERY_TERMS', 'SUPPLIER_CARD', 'DELIVERY_SLA'], 'type': 'string', 'description': 'AGENT_READINESS (agent URL), SUPPLIER_CARD (published card), DELIVERY_TERMS (terms_id) or DELIVERY_SLA (terms_id plus sla terms).'}, 'terms_id': {'type': 'string', 'description': 'DELIVERY_TERMS or DELIVERY_SLA: terms_id from witness_register_terms.'}, 'target_url': {'type': 'string', 'format': 'uri', 'maxLength': 2048, 'description': 'Public https URL (AGENT_READINESS, SUPPLIER_CARD). No query string.'}, 'webhook_url': {'type': 'string', 'format': 'uri', 'maxLength': 2048, 'description': 'Optional: your own public https endpoint for signed change events.'}, 'interval_hours': {'type': 'integer', 'default': 24, 'maximum': 168, 'minimum': 1, 'description': 'Hours between checks: 24 minimum on the free tier; 1 for DELIVERY_SLA.'}, 'continuity_handle': {'type': 'object', 'required': ['continuity_id', 'token'], 'properties': {'token': {'type': 'string'}, 'continuity_id': {'type': 'string'}}, 'description': 'The continuity_handle from an earlier GAIP result; proves you own these watches.'}, 'data_classification': {'enum': ['PUBLIC', 'NON_PERSONAL_PUBLIC'], 'type': 'string', 'default': 'PUBLIC', 'description': 'PUBLIC (default) or NON_PERSONAL_PUBLIC. Never send personal data.'}}, 'additionalProperties': False}
gaip_watch_remove
Remove a watch
Use this when asked to stop watching an agent or service. Pass your `continuity_handle` and the `watch_id`. Its stored events are deleted; retained receipts stay verifiable. Free, no account; records a GAIP receipt only. Inputs must be public and non-personal.
Destructive Idempotent
Input schema
{'type': 'object', 'examples': [{'watch_id': '<watch_id from gaip_watch_register>', 'continuity_handle': {'token': '<continuity_handle.token returned by any GAIP tool>', 'continuity_id': '<continuity_handle.continuity_id returned by any GAIP tool>'}}], 'required': ['continuity_handle', 'watch_id'], 'properties': {'watch_id': {'type': 'string', 'description': 'The watch_id returned by gaip_watch_register.'}, 'continuity_handle': {'type': 'object', 'required': ['continuity_id', 'token'], 'properties': {'token': {'type': 'string'}, 'continuity_id': {'type': 'string'}}, 'description': 'The continuity_handle from an earlier GAIP result; proves you own these watches.'}}, 'additionalProperties': False}
verify_gaip_receipt
Verify a GAIP receipt
Use this when you hold a GAIP receipt_id and want to confirm it ("is this receipt genuine?"). Returns the retained record, hash chain and Merkle inclusion proof. Integrity only: it does not make the underlying claim true. Free, read-only, no account; inputs must be public and non-personal.
Read only Idempotent
Input schema
{'type': 'object', 'examples': [{'receipt_id': '<receipt_id returned by any GAIP tool>'}], 'required': ['receipt_id'], 'properties': {'synthetic': {'type': 'boolean', 'description': 'Optional: true marks a test call.'}, 'episode_id': {'type': 'string', 'description': 'Optional: your own id to group related calls.'}, 'receipt_id': {'type': 'string', 'maxLength': 128, 'minLength': 1, 'description': 'A receipt_id returned by an earlier GAIP call.'}, 'continuity_handle': {'type': 'object', 'required': ['continuity_id', 'token'], 'properties': {'token': {'type': 'string'}, 'continuity_id': {'type': 'string'}}, 'description': 'Optional: the continuity_handle from an earlier GAIP result; links this call to your earlier ones.', 'additionalProperties': False}, 'data_classification': {'enum': ['PUBLIC', 'NON_PERSONAL_PUBLIC'], 'type': 'string', 'description': 'PUBLIC (default) or NON_PERSONAL_PUBLIC. Never send personal data.'}, 'independent_operator_id': {'type': 'string', 'description': 'Optional: your operator id (recorded as a claim, not verified).'}}, 'additionalProperties': True}
witness_delivery
Did the service deliver?
Use this when asked whether a service delivered what was agreed ("did the supplier deliver?"). Pass the `terms_id` from witness_register_terms and mode PUBLIC_REPLAY (GAIP fetches it) or BUYER_SUBMITTED. Returns PASS / FAIL / UNKNOWN per check, what changed since last time, and a receipt. Free, read-only, no account; inputs must be public and non-personal.
Read only Open world Idempotent
Input schema
{'type': 'object', 'examples': [{'mode': 'PUBLIC_REPLAY', 'terms_id': '<terms_id from witness_register_terms>'}], 'required': ['terms_id', 'mode'], 'properties': {'body': {'type': 'string', 'maxLength': 32768, 'description': 'BUYER_SUBMITTED: the response body you received (max 32 KiB).'}, 'mode': {'enum': ['BUYER_SUBMITTED', 'PUBLIC_REPLAY'], 'type': 'string', 'description': 'PUBLIC_REPLAY: GAIP fetches the public URL itself. BUYER_SUBMITTED: check a response you pass in.'}, 'terms_id': {'type': 'string', 'description': 'The terms_id returned when the terms were registered.'}, 'synthetic': {'type': 'boolean', 'description': 'Optional: true marks a test call.'}, 'episode_id': {'type': 'string', 'description': 'Optional: your own id to group related calls.'}, 'body_sha256': {'type': 'string', 'description': 'BUYER_SUBMITTED: SHA-256 of the body, instead of the body.'}, 'http_status': {'type': 'integer', 'description': 'BUYER_SUBMITTED: the HTTP status you received.'}, 'content_type': {'type': 'string', 'description': 'BUYER_SUBMITTED: the Content-Type you received.'}, 'continuity_handle': {'type': 'object', 'required': ['continuity_id', 'token'], 'properties': {'token': {'type': 'string'}, 'continuity_id': {'type': 'string'}}, 'description': 'Optional: the continuity_handle from an earlier GAIP result; links this call to your earlier ones.', 'additionalProperties': False}, 'data_classification': {'enum': ['PUBLIC', 'NON_PERSONAL_PUBLIC'], 'type': 'string', 'default': 'PUBLIC', 'description': 'PUBLIC (default) or NON_PERSONAL_PUBLIC. Never send personal data.'}, 'independent_operator_id': {'type': 'string', 'description': 'Optional: your operator id (recorded as a claim, not verified).'}}, 'additionalProperties': True}
witness_dispute_bundle
Export a delivery evidence bundle
Use this when a witnessed delivery failed and you must hand the facts to the other party or a resolver. Pass `terms_id` or a delivery `receipt_id`. Returns one hash-stamped bundle: terms, every check, receipts, timeline, summary. No judgement of who is right. Free, read-only, no account; inputs must be public and non-personal.
Read only Idempotent
Input schema
{'type': 'object', 'examples': [{'receipt_id': '<receipt_id from witness_delivery>'}], 'properties': {'terms_id': {'type': 'string', 'description': 'Or the terms_id (wt_...) of the agreement.'}, 'receipt_id': {'type': 'string', 'description': 'A delivery receipt_id from witness_delivery.'}, 'receipt_format': {'enum': ['gaip', 'x402_sar'], 'type': 'string', 'default': 'gaip', 'description': 'gaip (default) or x402_sar: also give each delivery in the x402 SAR draft shape.'}, 'continuity_handle': {'type': 'object', 'description': 'Optional: the continuity_handle that registered a DELIVERY_SLA watch on these terms; adds your SLA breaches.'}}}
witness_register_terms
Register what a service should deliver
Use this when about to depend on a public HTTPS service and you want neutral evidence of what it delivers. Pass `service_url`; `checks` default to HTTP 200 and a non-empty body (also JSON keys, latency, size, regex). Returns a `terms_id`; then call witness_delivery. Free, no account; records a GAIP receipt only. Inputs must be public and non-personal.
Input schema
{'type': 'object', 'examples': [{'checks': [{'id': 'http_status_in', 'allowed': [200]}, {'id': 'json_parses'}], 'seller_ref': 'example-weather-agent', 'service_url': 'https://weather.example.com/forecast.json'}], 'required': ['service_url'], 'properties': {'checks': {'type': 'array', 'maxItems': 8, 'minItems': 1, 'description': '1-8 checks, each {"id": "http_status_in", "allowed": [200]}, {"id": "content_type_is", "value": "application/json"}, {"id": "non_empty"}, {"id": "json_parses"}, {"id": "json_required_keys", "keys": ["a.b"]}, {"id": "json_path_equals", "path": "a.b", "value": 1}, {"id": "max_latency_ms", "limit": 2000}, {"id": "max_bytes", "limit": 20000}, {"id": "text_contains", "value": "ok"} or {"id": "regex", "pattern": "ok|up"}.'}, 'seller_ref': {'type': 'string', 'description': 'Optional: name of the supplier. Defaults to the host of service_url.'}, 'service_url': {'type': 'string', 'description': 'Public https URL of the service.'}, 'data_classification': {'enum': ['PUBLIC', 'NON_PERSONAL_PUBLIC'], 'type': 'string', 'default': 'PUBLIC', 'description': 'PUBLIC (default) or NON_PERSONAL_PUBLIC. Never send personal data.'}}}
Added
gaip_check_sar_receipt
Oct. 2, 2026, 2:41 a.m.
Changed
gaip_watch_register
Oct. 2, 2026, 2:41 a.m.
Changed
witness_dispute_bundle
Oct. 2, 2026, 2:41 a.m.
Changed
gaip_receipt_export
Oct. 2, 2026, 2:41 a.m.
Changed
witness_delivery
Oct. 2, 2026, 2:41 a.m.
Changed
witness_register_terms
Oct. 2, 2026, 2:41 a.m.
Added
gaip_citation_witness
Sept. 30, 2026, 2:40 a.m.
Added
gaip_watch_events
Sept. 30, 2026, 2:40 a.m.
Added
gaip_watch_remove
Sept. 30, 2026, 2:40 a.m.
Added
gaip_watch_list
Sept. 30, 2026, 2:40 a.m.
Added
gaip_watch_register
Sept. 30, 2026, 2:40 a.m.
Added
witness_dispute_bundle
Sept. 30, 2026, 2:40 a.m.
Added
verify_gaip_receipt
Sept. 30, 2026, 2:40 a.m.
Added
gaip_receipt_export
Sept. 30, 2026, 2:40 a.m.
Changed
witness_delivery
Sept. 30, 2026, 2:40 a.m.
Changed
witness_register_terms
Sept. 30, 2026, 2:40 a.m.
Added
witness_delivery
Sept. 28, 2026, 2:40 a.m.
Added
witness_register_terms
Sept. 28, 2026, 2:40 a.m.