# Check an agent action over MCP (TypeScript)

This example calls HANRIA's free tools at `https://check.hanria.ai/v1/mcp` with the official TypeScript MCP SDK. It lists the server's tools, checks the mandate once with `validate_mandate`, checks one action with `check_action`, prints the decision, and verifies the signed receipt in-process with Web Crypto.

A mandate is the operator's rule set. An action is what the agent wants to do. The decision is `permit`, `deny`, or `escalate`, with the clause that decided it. An `error` outcome means the input did not validate; treat it as deny. Decisions are advisory: the calling agent or its operator decides what to do with them.

## Run it

Node 22 or later.

```sh
mkdir hanria-mcp-typescript && cd hanria-mcp-typescript
curl -fsSO https://hanria.ai/examples/mcp-typescript/check_action_example.mjs
curl -fsSO https://hanria.ai/examples/mcp-typescript/package.json
curl -fsSO https://hanria.ai/examples/mcp-typescript/package-lock.json
npm ci
node check_action_example.mjs
```

Pass `--keys FILE` to verify with a saved copy of `https://check.hanria.ai/.well-known/hanria-receipt-keys.json` instead of fetching the keys.

Expected output shape:

```text
{
  "schema_version": "0.1-draft",
  "outcome": "permit",
  "reason": "clause 'permit-file' applies",
  "mandate_ref": "minimal-permit",
  "clause": "permit-file",
  "action_digest": "...",
  "receipt": {
    "type": "hanria-receipt-v1",
    "kid": "...",
    "outcome": "permit",
    "action_digest": "...",
    "mandate_digest": "...",
    "issued_at": "...",
    "not_after": "...",
    "signature": "..."
  }
}
VERIFIED: the hosted check answered permit
```

The receipt binds the answer to the exact mandate and action and is verified without asking HANRIA. The example also requires the signed receipt's outcome, action digest, clause, and mandate reference (including their presence or absence) to match the decision envelope; it prints and exits from the signed receipt's outcome, never the unsigned envelope's outcome. It proves what the hosted check answered, not that the action was performed or that the mandate belongs to the operator. The process exits 0 for a verified `permit`, `deny`, or `escalate`; it exits 1 for an error, a mismatch, an unverifiable receipt, or a failed connection.

## Use your own mandate

Replace `MANDATE` and `ACTION` in `check_action_example.mjs`. Their JSON schemas are in the tool's `inputSchema`, returned by `tools/list`, and described in https://hanria.ai/llms.txt.

## Data handling

Requests are evaluated in memory and not stored; only daily counts are kept. See https://check.hanria.ai/privacy. Do not send secrets, personal data, or confidential policies. The unchanged example counts as an example call, not as real use; see https://check.hanria.ai/methodology.

`package.json` and `package-lock.json` pin `@modelcontextprotocol/sdk` to exactly `1.31.0`.
