# MCP — Model Context Protocol

Hangar exposes a platform-level MCP server at
**`POST /api/mcp`**. Any MCP-compatible client (Claude Desktop, Cursor,
your own SDK-based agent) can authenticate with a PAT and invoke tools
that operate on the user's wallet, agent instance, personas, and skills.

## Discovery

- **Server URL:** `https://hangar.so/api/mcp`
- **Discovery doc:** `https://hangar.so/.well-known/mcp`
- **Server card:** `https://hangar.so/.well-known/mcp/server-card.json`
- **Transport:** Streamable HTTP, spec rev `2025-11-25`.

The server is **stateless**. Each request constructs a fresh
`McpServer` scoped to the verified user. Tool schemas don't accept a
`userId` argument — it's derived from the PAT.

## Authentication

Bearer token in the `Authorization` header:

```
Authorization: Bearer oss_<token>
```

If the token is invalid we 401 with `WWW-Authenticate: Bearer`. We
do not fall through to the browser session.

## Tools

| Tool | Scope | What it does |
|---|---|---|
| `wallet.balance` | `mcp:wallet.read` | Current balance, lifetime credit/spend |
| `wallet.transactions` | `mcp:wallet.read` | Recent debits/credits |
| `wallet.checkoutTopUp` | `mcp:wallet.write` | Returns checkout URL |
| `instance.status` | `mcp:instance.read` | Agent runtime status |
| `instance.pause` | `mcp:instance.write` | Stop agent (resumable) |
| `instance.resume` | `mcp:instance.write` | Restart paused agent |
| `instance.refreshEnv` | `mcp:instance.write` | Re-inject env vars |
| `instance.setModel` | `mcp:instance.write` | Change default LLM model |
| `personas.list` | `mcp:personas.read` | Public + active personas |
| `personas.activate` | `mcp:personas.write` | Activate a persona |
| `personas.deactivate` | `mcp:personas.write` | Deactivate a persona |
| `skills.list` | `mcp:skills.read` | Available + pinned skills |
| `skills.show` | `mcp:skills.read` | Full skill details + recent versions |

Wallet credit is **read-only** on MCP. Top-ups go through the billing
provider for receipts/refunds; `wallet.checkoutTopUp` returns a hosted
URL the user opens in their browser.

## Examples

### Claude Desktop

Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "hangar": {
      "url": "https://hangar.so/api/mcp",
      "headers": {
        "Authorization": "Bearer oss_<your-token>"
      }
    }
  }
}
```

Restart Claude. The 13 tools appear automatically.

### Cursor

Cursor reads MCP servers from `~/.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "hangar": {
      "url": "https://hangar.so/api/mcp",
      "headers": {
        "Authorization": "Bearer oss_<your-token>"
      }
    }
  }
}
```

### Health check

```bash
curl -X POST https://hangar.so/api/mcp \
  -H "Authorization: Bearer oss_<your-token>" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```

Returns the full tool list. `401` means the token is wrong or revoked.

### Programmatic call from a Cursor / Claude Code skill

```ts
const result = await mcp('hangar').callTool('wallet.balance', {})
console.log(result.content[0].text)
// JSON: { balanceUsd: 12.34, ... }
```

## Limits

- **Per-instance MCP** (your hosted agent itself exposing MCP) is on
  the roadmap, not yet shipped.
- **Wallet credit** is read-only on MCP. Use the dashboard or the
  `wallet.checkoutTopUp` tool to start a top-up.
- **Skill install/uninstall** is intentionally not exposed — pinning a
  skill version is a rollout-safety surface that stays in the dashboard.
MCP — Model Context Protocol — Hangar