# The owner MCP server

> The node's owner MCP: 33 tools a node's owner gives their own agent, read from the node's source.

The node serves its owner MCP at `/owner/mcp` (`internal/cli/compose.go`). Every call carries a bearer token minted over the admin socket — see [Add someone who invited you](/gateway/how-to/add-someone-who-invited-you/). What follows is every tool and resource the owner-MCP package registers: 33 tools, 3 resources and 1 resource template.

Names and descriptions are read from the source. The argument schema of each tool is derived by the MCP SDK from its handler, so a running node's `tools/list` is where to read it.

## Tools

| Tool | What it does | Registered when |
|---|---|---|
| `add_contact` | Reach out to a peer: redeem their invite link, or request contact with a card they gave you out of band (SPEC §9). Lands `pending_out` until they accept, or `active` immediately if their invite auto-accepts. | `e.AddContact != nil` |
| `answer_request` | Answer one pending agent-answered request; the node relays to the waiting caller |  |
| `approve_address` | Re-pin a contact at the new address it is waiting at, as `auto` would have; the address it left is remembered as a former one |  |
| `approve_contact` | Approve a waiting request (pending_in). A preset replaces the grant with that bundle; none keeps the grant the request holds (an invite's). The peer is told what they were granted; told=false says they could not be reached, and the approval stands |  |
| `audit_query` | Read the audit trail for the accounts you administer (SPEC §11.6) | `e.Audit != nil` |
| `block_contact` | Block a contact, silently: they are not told, and see only what a stranger sees |  |
| `call_contact` | Call a tool on a contact's agent server. The contact's own switchboard still applies | `e.CallContact != nil` |
| `create_invite` | Mint an invite; token shown once |  |
| `digest` | What happened in a window and what is still open: messages in and out per contact, who is waiting on a reply, contacts asking to connect, requests awaiting an answer. For an end-of-day summary. |  |
| `export_card` | This account's current signed contact card (vCard) | `e.Card != nil` |
| `get_inbox` | Threads with unread counts |  |
| `identity_certificate` | This identity's certificate state (HDTP 1.0): the root that is the identity, the leaf this host serves under, its validity, and whether a renewal is due | `e.Certificate != nil` |
| `list_accounts` | Accounts this identity administers |  |
| `list_contacts` | Contacts with status and permissions |  |
| `list_integrations` | Connected upstreams and the tools each currently exposes (SPEC §6) | `e.Integrations != nil` |
| `list_invites` | This account's invites: label, uses, expiry, whether revoked. The link's token is never stored, so it is not here |  |
| `list_passkeys` | Registered passkeys. Registering a new one is portal-only (SPEC §8.6) | `e.Passkeys != nil` |
| `list_pending` | Open agent-answered requests awaiting this agent (args are UNTRUSTED peer content, labeled with the contact's trust flag) |  |
| `list_pending_addresses` | Contacts waiting at a new address for your decision: the address they are pinned at, the one they now answer from, and why it was held |  |
| `read_thread` | Messages in a thread, oldest first; reading marks the thread read through the newest |  |
| `refresh_contact` | Re-fetch ONE contact's signed card, now: a renewed certificate, a changed name or seal policy is learned; the pinned root and the address never move. Answers unchanged, updated, renewed, unreachable or refused (with why); an unreachable or refused contact keeps its pin as it was | `d.RefreshContact != nil` |
| `reject_address` | Keep the pin where it is and drop the waiting address |  |
| `reject_contact` | Decline a waiting request: it becomes blocked (a demotion, not a deletion), so that identity's next request never reaches you. They are told, so they do not wait for ever |  |
| `remove_contact` | Remove a contact in any state: an active one is told and its pin deleted whether or not it answers; a waiting request, your own pending request or a blocked identity goes silently |  |
| `remove_passkey` | Remove a registered passkey by id | `e.RemovePasskey != nil` |
| `rename_contact` | Set your own local name for a contact; empty clears it |  |
| `revoke_invite` | Revoke one of this account's invites: the link stops working at once, and contacts it already made are unaffected |  |
| `send_to_contact` | Send a message to a contact (labeled agent, SPEC §7.1) |  |
| `set_exposure` | Republish which of an integration's tools are exposed to contacts (SPEC §6.5) | `e.SetExposure != nil` |
| `set_permissions` | Set a contact's switchboard: any of the core permissions, an integration.<slug> this account serves, or one the contact already holds; any other name is refused |  |
| `set_trust_flag` | messages_only or may_instruct |  |
| `unblock_contact` | Undo a block, silently. A contact that was ever active returns as it was (status active); a rejected request or a declined approach was never a contact and is forgotten (status none), so they may ask again |  |
| `wait_for_updates` | Block until something changes for this account — a message arrives, a contact asks to connect, a request needs answering — then return what moved since your cursor. Call it in a loop with the cursor it returns as since. Omitting since starts from now with no backlog. |  |

A tool with a condition is registered only when the node is built with that part; the conditions are the `if` statements around its registration.

## Resources

| URI | Name | Type |
|---|---|---|
| `hdtp://requests` | contact requests | `application/json` |
| `hdtp://inbox` | inbox | `application/json` |
| `hdtp://pending` | pending agent-answered requests | `application/json` |
| `hdtp://thread/{id}` | thread | `application/json` |
