# Passport MCP — for builders

A read-only Model Context Protocol server your agent reads inside a run — the user's identity, wallet balance and the current conversation's history. No sign-in to build: the session token arrives in the webhook.

## What's a Passport?

Every ONBF user carries an **ONBF Passport** — their identity, wallet and chat history (with memory, connected tools & files coming next), all in one place. It's how an agent can act *on a user's behalf* ("ONBF" reads aloud as *on behalf*) without you ever building sign-in, accounts or connectors yourself.

When a user opens your agent they already arrive *known*: a verified identity, a prepaid wallet to pay you, and — with their consent — the context your agent needs to be useful from the first message. The **Passport MCP** is your read-only window into the parts of that Passport a user has granted you.

> **Are you an end-user?:** This page is the agent-/builder-facing reference. If you want to connect *your own* Passport to an external agent or MCP client, see **[Passport for users](/docs/passport-users)**.

## Overview

The Passport MCP is a standard MCP server at `https://onbf.ai/api/mcp` speaking the **Streamable HTTP** transport (protocol revision `2025-03-26`). You authenticate with a bearer token; the server advertises only the tools your token is entitled to.

| Field | Value |
| --- | --- |
| Endpoint | `https://onbf.ai/api/mcp` |
| Transport | Streamable HTTP (JSON responses) |
| Protocol | `2025-03-26` |
| Auth | `Authorization: Bearer <token>` |
| Methods | `POST` for JSON-RPC · `GET` for unauthenticated discovery |
| Rate limit | 120 requests / 60s per token |

## The session token

As a builder you almost never deal with tokens by hand. Every run ONBF dispatches to your webhook carries a **session token** (`onbf_sess_…`) in its `mcp` block — that's your key to the Passport for the duration of that run.

- **Per-run & time-limited** — it's minted for a single run and bound to one `{user, conversation, project}`. It stays valid only for that run's reply window (`reply.expiresInSeconds`), then expires.
- **Zero setup** — nothing for you or the user to configure; it's delivered to you in the `agent.run.created` payload.
- **Conversation-aware** — unlike a user's personal token, it can read the *current* conversation's history (the `conversation:read` scope) so your agent answers in context.

> **Personal access tokens:** Your end-users can also mint a long-lived personal token to connect their Passport to *any* agent or MCP client themselves. That flow lives on the **[Passport for users](/docs/passport-users)** page — as a builder you don't issue or handle those.

## Scopes

Tools declare the scopes they need; a connection sees a tool only when its token holds every required scope (so it's never advertised, not just denied at call time). The in-run session token holds all three:

| Scope | Session token | User's personal token |
| --- | --- | --- |
| `identity:read` | ✓ | ✓ |
| `balance:read` | ✓ | ✓ |
| `conversation:read` | ✓ | — |

## Tools

| Tool | Returns | Requires |
| --- | --- | --- |
| `get_identity` | Display name, handle, bio, member-since date. | Any token |
| `get_balance` | The user's current prepaid wallet balance. | Any token |
| `get_conversation_history` | The transcript of the current conversation, so the agent can ground its reply. | Session token only |

> **Discovery & health check:** There's no separate `/healthz` — an unauthenticated `GET https://onbf.ai/api/mcp` is your health/discovery endpoint. It returns server identity, the protocol revision and the public tool catalog (session-only tools are not advertised there).

## Reading conversation history inside a run

When ONBF dispatches a run to your webhook, the payload includes an `mcp` block with the session token. Use it to read the current conversation so your reply stays in context — no PAT, no user setup required:

```javascript
// When a run arrives, the payload includes an `mcp` block with a
// per-run session token (time-limited to the run's reply window). Use it to
// also read the CURRENT conversation's history — so your agent answers in
// context. No PAT, no user setup: it's delivered to you in the webhook.
if (event.mcp) {
  const res = await fetch(event.mcp.url, {
    method: "POST",
    headers: {
      "content-type": "application/json",
      "accept": "application/json, text/event-stream",
      "authorization": `Bearer ${event.mcp.token}`,
    },
    body: JSON.stringify({
      jsonrpc: "2.0",
      id: 1,
      method: "tools/call",
      params: { name: "get_conversation_history", arguments: {} },
    }),
  });
  const history = await res.json();
}
```

> **Where the mcp block comes from:** It rides on the `agent.run.created` webhook alongside your reply token — see the inbound payload on the **[Your Webhook](/docs/agent-webhook)** page.
