> ## Documentation Index
> Fetch the complete documentation index at: https://acachete.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Tools

> How available tools are generated from the live on-chain allow-list and each contract's own spec -- never a hardcoded list.

## Generated, not hardcoded

Point `stellar-agentgate` at any `passkey-kit` wallet and `agent-policy` instance, and it exposes **exactly** the methods that wallet's policy currently allows -- no more, no less. This comes from two on-chain reads at server start, implemented in `src/spec-to-tools.ts`:

<Steps>
  <Step title="Read the policy's allow-list">
    A read-only simulate of `agent-policy.get_config(wallet)` returns the configured `Vec<AllowedCall>` -- each entry naming a `{contract, fn_name, amount_arg_index}`.
  </Step>

  <Step title="Fetch each target contract's own spec">
    `server.getContractWasmByContractId()` + `contract.Spec.fromWasm()` gives the REAL parameter names and types for each allowed method -- sourced from the contract's own compiled spec, never guessed.
  </Step>

  <Step title="Build one MCP tool per allowed method">
    A JSON Schema is generated from the real parameter types, and the tool's description states its spend cap (or confirms it's uncapped) in plain language.
  </Step>
</Steps>

If the wallet owner changes the allow-list on-chain -- adds a method, tightens a cap -- the next MCP server start reflects that immediately. There is no separate configuration file to keep in sync.

## Address auto-fill

Every `AllowedCall` this project's demo contract exposes takes the wallet's own address as its primary parameter (`deposit(from, amount)`, `withdraw(to, amount)`) -- the overwhelmingly common shape for a policy-gated call. Rather than requiring an agent to know and pass a 56-character `C...`/`G...` address just to say "deposit 100," any `Address`-typed parameter the caller omits defaults to the wallet's own address:

```typescript src/mcp-server.ts theme={null}
// Address-typed params an agent omits default to the wallet's own address --
// the overwhelmingly common case for a policy-gated call (the wallet acting
// on its own behalf), sparing the agent from having to know a 56-char C...
// address just to say "deposit 100".
function fillAddressDefaults(tool, args, walletId) { /* ... */ }
```

An agent can still pass an explicit address to override this -- the default only fills gaps, it never overwrites a value the caller provided.

## Spend-cap hints on the amount argument itself

Beyond the tool-level description (`(spend-capped by argument index N)` or
`(uncapped)`), the JSON Schema property for that specific argument also
carries the note -- so an agent inspecting just that one field, not the
whole tool description, still knows it's the number that counts against the
wallet's rolling-window allowance:

```json theme={null}
"amount": {
  "type": "string",
  "description": "integer, as a decimal string (too large for a JSON number). Spend-capped: counts against this wallet's rolling-window allowance (see wallet_info for the current cap)."
}
```

Built by `describeAmountArg` in `src/spec-to-tools.ts`, keyed off the same
`amount_arg_index` `policy__` itself reads on-chain -- the hint and the
enforcement can never drift out of sync with each other.

## Rejections are ordinary tool errors

When the policy rejects a call -- cap exceeded, method not allowed -- the MCP server does not crash or retry. It returns a normal MCP tool result with `isError: true` and the on-chain error surfaced in plain text:

```json theme={null}
{
  "content": [{ "type": "text", "text": "Rejected: simulation failed: HostError: Error(Auth, InvalidAction)" }],
  "isError": true
}
```

An agent (or the human watching it) sees a clean, expected failure -- not an unhandled exception.

## Try it directly

The `policy-explain` subcommand runs the same discovery logic and prints it in plain text, useful for a human auditing what an agent can currently do before trusting it:

```bash theme={null}
stellar agentgate policy-explain
```

```text theme={null}
wallet:  C...
policy:  C...
agent:   G...

an agent holding this signer may currently do:
  - deposit(...) on C...  [uncapped]
  - withdraw(...) on C...  [spend-capped, arg #1]
```
