# mcphost (remote · mcphost.dev)

Host your MCP tool over streamable HTTP in one command.

- Trust score: 88/100 (high trust)
- Change this week: +18
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-09-29

## Components

- remote · `mcphost.dev`: 88/100 (this document), [markdown](https://verifymcp.io/servers/dev-mcphost-mcphost/mcphost.md), [page](https://verifymcp.io/servers/dev-mcphost-mcphost/mcphost)

## Channel facts

- Endpoint: `https://mcphost.dev/mcp`
- Transports: `streamable-http`
- Auth: `none`
- Version: `0.27.0`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-09-29.

- **Endpoint Security**: 92/100
  - The endpoint's TLS certificate is valid, in date, and uses a strong key.
  - Authorisation is enforced on tool calls, advertised via RFC 9728 protected-resource metadata. Discovery is public, which costs nothing: no tool can be invoked without a token.
  - HTTPS is enforced; there's no plaintext access path.
  - HSTS check failed: the Strict-Transport-Security header is absent.
  - DNSSEC check failed: this domain isn't protected by DNSSEC.
  - The authorisation server supports Client ID Metadata Documents, the current MCP client-registration mechanism.
- **Transport & Reachability**: 100/100
  - Verified streamable-http transport via a live MCP handshake.
- **Schema Quality & AI Usability**: 75/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 17958 tokens (~132/item across 136 items; 136 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 77/100
  - Stability observed for 23 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 99/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 97% of tool parameters carry a description.
- **Tool Safety**: 75/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - 0 of 23 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "host.tool_publish" implies "publish" and declares no destructiveHint at all, which the MCP spec reads as destructive by default.
  - An AI judge read all 137 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a current MCP spec version (2026-07-28).

## Install

### How do I install the mcphost MCP server?

mcphost is a hosted endpoint at https://mcphost.dev/mcp, so there is nothing to install locally. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add --transport http dev-mcphost-mcphost 'https://mcphost.dev/mcp'
```

### Cursor

```json
{
  "mcpServers": {
    "dev-mcphost-mcphost": {
      "url": "https://mcphost.dev/mcp"
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "dev-mcphost-mcphost": {
      "type": "http",
      "url": "https://mcphost.dev/mcp"
    }
  }
}
```

### Codex

```toml
[mcp_servers.dev-mcphost-mcphost]
url = "https://mcphost.dev/mcp"
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "dev-mcphost-mcphost": {
      "type": "remote",
      "url": "https://mcphost.dev/mcp",
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add dev-mcphost-mcphost --url 'https://mcphost.dev/mcp' --transport streamable-http
```

### Hermes

```yaml
mcp_servers:
  dev-mcphost-mcphost:
    url: "https://mcphost.dev/mcp"
```

### Netclaw

```json
{
  "McpServers": {
    "dev-mcphost-mcphost": {
      "Transport": "http",
      "Url": "https://mcphost.dev/mcp"
    }
  }
}
```

### Vellum

```bash
assistant mcp add dev-mcphost-mcphost -t streamable-http -u 'https://mcphost.dev/mcp'
```

### Other

```json
{
  "mcpServers": {
    "dev-mcphost-mcphost": {
      "type": "http",
      "url": "https://mcphost.dev/mcp"
    }
  }
}
```

The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-09-29 (score 88, +1)

No change was recorded against any check on this day. Stability & Change Management went from 73 to 77. That category is still filling its 30-day observation window: 22 days of observed history at the previous scan, 23 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-28 (score 87, +4)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-09-27 (score 83, 0)

- [security] Tool “host.docs.status” rewrote its description, which is the text the model reads
- [security] Tool “host.runs.list” rewrote its description, which is the text the model reads
- [security] Tool “host.runs.wait” rewrote its description, which is the text the model reads
- [security] Tool “host.usage” rewrote its description, which is the text the model reads
- [functional regression] Schema quality: 12812 → 15524
- [functional] New tool “host.docs.index_config”
- [functional] New tool “host.docs.reindex”
- [functional] New tool “host.docs.search”
- [functional] New tool “host.enduser.assertion_secret_rotate”
- [functional] New tool “host.enduser.audit”
- [functional] New tool “host.enduser.export”
- [functional] New tool “host.enduser.get”
- [functional] New tool “host.enduser.list”
- [functional] New tool “host.enduser.purge”
- [functional] New tool “host.enduser.revoke”
- [functional] New tool “host.enduser.unrevoke”
- [functional] New tool “host.enduser.whoami”
- [functional] New tool “host.progress”
- [functional] New tool “host.runs.part”
- [functional] New tool “host.share.caller_limit”
- [functional] New tool “host.share.caller_limit_remove”
- [cosmetic] “host.runs.list” added an optional parameter “end_user_subject”
- [cosmetic] “host.runs.wait” added an optional parameter “until”
- [cosmetic] “host.state.delete” added an optional parameter “end_user”
- [cosmetic] “host.state.delete_rows” added an optional parameter “end_user”
- [cosmetic] “host.state.get” added an optional parameter “end_user”
- [cosmetic] “host.state.insert” added an optional parameter “end_user”
- [cosmetic] “host.state.list” added an optional parameter “end_user”
- [cosmetic] “host.state.query” added an optional parameter “end_user”
- [cosmetic] “host.state.set” added an optional parameter “end_user”
- [cosmetic] “host.usage” added an optional parameter “by”
- [cosmetic] “host.usage” added an optional parameter “cursor”
- [cosmetic] “host.usage” added an optional parameter “limit”
- [cosmetic] “host.usage” added an optional parameter “tool”
- [cosmetic] “host.usage” reworded the description of “window”

### 2026-09-26 (score 83, +11)

- [security regression] Authorization: unverified → fail
- [functional regression] Schema quality: 11217 → 12812
- [functional] New tool “host.docs.delete”
- [functional] New tool “host.docs.get”
- [functional] New tool “host.docs.list”
- [functional] New tool “host.docs.purge”
- [functional] New tool “host.docs.put”
- [functional] New tool “host.docs.status”
- [functional] New tool “host.oauth.issuer_remove”
- [functional] New tool “host.oauth.issuer_set”
- [functional] New tool “host.oauth.issuers”
- [functional] New tool “host.table.describe”
- [functional] New tool “host.table.model_set”
- [functional] New tool “host.table.models”

### 2026-09-25 (score 72, +1)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-09-24 (score 71, 0)

- [security] Tool “host.channel.open” rewrote its description, which is the text the model reads
- [security] Tool “host.channel.post” rewrote its description, which is the text the model reads
- [security] Tool “host.tool_call” rewrote its description, which is the text the model reads
- [security] Tool “host.trigger.list” rewrote its description, which is the text the model reads
- [security] Tool “host.trigger.replay” rewrote its description, which is the text the model reads
- [security] Tool “host.trigger.set” rewrote its description, which is the text the model reads
- [security] Tool “host.trigger.test” rewrote its description, which is the text the model reads
- [functional regression] Schema quality: 9975 → 11217
- [functional] New tool “host.channel.close”
- [functional] New tool “host.channel.freeze”
- [functional] New tool “host.channel.read”
- [functional] New tool “host.channel.unfreeze”
- [functional] New tool “host.tool_diff”
- [functional] New tool “host.tool_history”
- [functional] New tool “host.tool_rollback”
- [cosmetic] “host.channel.open” added an optional parameter “group”
- [cosmetic] “host.tool_call” added an optional parameter “version”
- [cosmetic] “host.trigger.replay” added an optional parameter “id”
- [cosmetic] “host.trigger.replay” added an optional parameter “row_id”
- [cosmetic] “host.trigger.set” added an optional parameter “channel_id”
- [cosmetic] “host.trigger.set” added an optional parameter “name”
- [cosmetic] “host.trigger.set” reworded the description of “args”
- [cosmetic] “host.trigger.set” reworded the description of “kind”
- [cosmetic] “host.trigger.set” reworded the description of “verify”
- [cosmetic] “host.trigger.test” reworded the description of “body”
- [cosmetic] “host.trigger.test” reworded the description of “id”
- [cosmetic] “host.channel.open” made “name” optional
- [cosmetic] “host.trigger.replay” made “run_id” optional

### 2026-09-23 (score 71, +1)

- [security] Tool “host.tool_publish” rewrote its description, which is the text the model reads
- [security] Tool “host.tool_run” rewrote its description, which is the text the model reads
- [functional] New tool “host.changelog”
- [functional] New tool “host.channel.open”
- [functional] New tool “host.channel.post”
- [functional] New tool “host.export”

### 2026-09-20 (score 70, +1)

No change was recorded against any check on this day. Stability & Change Management went from 43 to 47. That category is still filling its 30-day observation window: 13 days of observed history at the previous scan, 14 at this one. The score rises as the window fills, whether or not the server changes.

## MCP tools (136)

### `signup` (~139 tokens)

Create a tenant and receive a bearer key and namespace. Unauthenticated. Recommended: pass handoff: true to receive a short-lived, single-use handoff_token instead of the raw key -- redeem it once with host.redeem to get the key, so a transcript of this call and the redeem call, if it leaks, carries a dead credential. The raw-key path (handoff omitted) stays fully supported.

Input parameters:

- `handoff` (boolean): Recommended: true to receive a handoff_token (redeem via host.redeem) instead of the raw key. Default false (raw key, unchanged).
- `name` (string, required): display name

### `host.whoami` (~67 tokens)

Return the calling tenant's identity, including key_age_s and key_rotated_at for auditing credential hygiene.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.redeem` (~123 tokens)

Exchange a signup(handoff: true) handoff_token for the tenant key it was issued for. Single-use: a second redemption fails with handoff_token_redeemed; past its expiry it fails with handoff_token_expired. Unauthenticated -- the token itself is the proof.

Input parameters:

- `handoff_token` (string, required): The handoff_token signup(handoff: true) returned.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.key_rotate` (~97 tokens)

Issue a new tenant key and invalidate the current one immediately: every other call using the old key fails as unauthenticated from this point on. Returns the new key exactly once -- use it (as tenant_key or Authorization) for every call after this one.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.self_offboard` (~142 tokens)

Permanently close your own account: disables the tenant, cancels any active Stripe subscription (pro plan), and stops your key from authenticating anything further -- same as an admin-disabled tenant. Idempotent: an already-offboarded key gets the same tenant_disabled/tenant_key_invalid error every other host.*/ billing.* call already gets from it, not a crash. This does not scrub historical usage/signup records -- those stay for audit, same as today's admin-disabled tenants.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.tool_publish` (~272 tokens)

Publish a tool of a registered kind (chain, echo, http, python, wasm) under this tenant's namespace. Call host.quickstart(kind) first for a filled-in example spec and the full publish-to-call sequence. Name must match ^[a-z][a-z0-9_]{1,40}$; a rejection names the failing field and a corrected example. Try host.tool_test before a real call.

Input parameters:

- `kind` (string, required): Which registered kind to publish under, e.g. echo, http, python.
- `name` (string, required): Local name for the new tool; must match ^[a-z][a-z0-9_]{1,40}$.
- `scopes` (array): OAuth scopes a token must carry (directly, or via mcp) to reach this tool: catalogued names from host.oauth.scopes, or the built-ins read/write. At most 8. Omit (or [] ) to require only mcp -- unaffe…
- `spec` (object, required): The kind-specific spec object; see host.quickstart(kind) for a filled-in example.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.quickstart` (~146 tokens)

Return the shortest ordered sequence of calls to a working tool of `kind`, with your namespace and a filled-in example already substituted in, plus the current limits and a try_before_call table naming the one dry-run tool for each case. Read-only. Call this before host.tool_publish if you're not sure what a spec should look like. Unauthenticated callers get the signup step first.

Input parameters:

- `kind` (string, required): Which registered kind to return a worked example for, e.g. echo, http, python.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.tool_list` (~52 tokens)

List this tenant's published tools.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.tool_remove` (~68 tokens)

Remove a published tool by its local name.

Input parameters:

- `name` (string, required): Local name of the tool to remove.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.tool_logs` (~95 tokens)

Return the most recent log lines for one of this tenant's tools.

Input parameters:

- `limit` (integer): Max lines to return, most recent first; default 20.
- `name` (string, required): Local name of the tool whose log lines to return.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.tool_test` (~104 tokens)

Dry-run an already-published tool by name, no calls row written; for the other cases see host.quickstart.

Input parameters:

- `args` (object, required): Arguments to pass, same shape as a real call.
- `name` (string, required): Local name of the already-published tool to dry-run.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.bridge_test` (~124 tokens)

Dry-run an unpublished http spec against its real upstream; for the other cases see host.quickstart.

Input parameters:

- `args` (object, required): Arguments to render into the spec, same shape as a real call.
- `spec` (object, required): An http-kind spec, not yet published, e.g. {"url": "https://api.example.com/items/{{id}}", "method": "GET"}.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.tool_run` (~106 tokens)

Debug-run a published python tool: result.payload plus duration_ms and exit_code; for the other cases see host.quickstart.

Input parameters:

- `args` (object, required): Arguments to pass, same shape as a real call.
- `name` (string, required): Local name of the already-published python tool to debug-run.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.tool_call` (~277 tokens)

Invoke a tool this tenant has already published, by its local name -- the same real, metered call as calling it directly by its namespaced name (<namespace>.<name>), for a session that has no way to see its own namespaced tool name yet. Unlike host.tool_test, this counts toward host.usage and appears in host.tool_logs. Pass async: true for a tool that needs more than the call deadline: returns {run_id, status: "queued"} immediately instead of running inline -- see host.runs.get/wait. Pass version to pin the call to one of host.tool_history's versions instead of whichever is current.

Input parameters:

- `args` (object, required): Arguments to pass, validated against the tool's own args_schema.
- `async` (boolean): Run as a job instead of inline: returns {run_id, status} within ~50ms under the plan's job_max_s deadline; default false.
- `name` (string, required): Local name of the tool to invoke.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `version` (integer): Pin the call to this version instead of whichever is current; see host.tool_history. An unknown version is an argument error.

### `host.tool_history` (~89 tokens)

List every published version of one of this tenant's tools, newest first, each with its creation time, source_sha256, and whether it's the current one.

Input parameters:

- `name` (string, required): Local name of the tool.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.tool_rollback` (~122 tokens)

Make an earlier published version of one of this tenant's tools current again -- the next host.tool_call (or namespaced call) runs that version's source. See host.tool_history for the valid version numbers.

Input parameters:

- `name` (string, required): Local name of the tool to roll back.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `version` (integer, required): The version number (from host.tool_history) to make current.

### `host.tool_diff` (~95 tokens)

Return a unified diff between two published versions of one of this tenant's tools.

Input parameters:

- `from` (integer, required): The earlier version number.
- `name` (string, required): Local name of the tool.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `to` (integer, required): The later version number.

### `host.usage` (~287 tokens)

Calls, errors and duration percentiles for this tenant over a window. Pass `by` ("tool", "caller", or "end_user") for a breakdown instead of the plain per-tenant summary: "caller" (only valid for a tool this tenant has shared) shows which tenant called in and how much; "end_user" shows which identified end user called, with the caller tenant folded into the key when the call crossed tenants. Breakdown rows cap at 1000 per page; pass the returned `cursor` back to page further.

Input parameters:

- `by` (string): "tool", "caller", or "end_user" -- omit for the plain per-tenant summary.
- `cursor` (string): Resume a breakdown after this page's last key.
- `limit` (integer): Max breakdown rows per page (1-1000, default 1000).
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `tool` (string): Scope the breakdown to one local tool name. Required when by is "caller".
- `window` (string): Time window to summarize, e.g. "24h"/"1d"/"7d"/"30d"; default 24h ("1d" when `by` is given).

### `host.changelog` (~107 tokens)

List what changed in the host.*/billing.* tool surface -- additions, deprecations, and removals -- since an optional version. Read-only.

Input parameters:

- `since` (string): Only list changes after this version, e.g. "0.57.0". Omit to list every tracked change.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.export` (~158 tokens)

Build a downloadable .tar.gz of everything this tenant owns: tool sources, state, secret NAMES (never values), run/thread history and usage, plus a manifest.json re-publishable via host.tool_publish. Runs as a background job (poll host.runs.get with the returned run_id) -- calling this again while one is already running returns that same run_id rather than starting a second one. The finished run's result carries a download_url valid 24 hours.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `tools` (array): Local names of the tools to include; every tool when omitted.

### `host.tool_share` (~212 tokens)

Share one of this tenant's published tools with everyone (visibility: "public") or with a named group this tenant owns (visibility: "group", group: <name>). The tool keeps running in this tenant's own sandbox with this tenant's own secrets; a caller reaches it as <this tenant's namespace>.<name>.

Input parameters:

- `description` (string): Catalog-facing blurb; shown by host.catalog.search/get.
- `expose_spec` (boolean): Default false. When true, any tenant this tool is shared with may call host.tool_spec_shared to read its (redacted) spec.
- `group` (string): Required when visibility is "group"; must already exist (host.group.create).
- `name` (string, required): Local name of the tool to share.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `visibility` (string, required): "public" or "group".

### `host.tool_spec_shared` (~114 tokens)

Read a shared tool's kind and redacted spec -- only works when the owner shared it with expose_spec: true. The spec never carries env values or secret references (see host.tool_share's expose_spec).

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `tool` (string, required): "<owner_namespace>.<name>", the same qualified name host.tool_call uses for a shared tool.

### `host.tool_unshare` (~69 tokens)

Take a shared tool back to private.

Input parameters:

- `name` (string, required): Local name of the tool to unshare.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.share.caller_limit` (~150 tokens)

Cap how many successful calls a caller tenant may make per UTC day into one of this tenant's shared tools. The tool must already be shared. Exceeding the cap fails the call with quota_caller (never runs it); this tenant's own calls to the tool are unaffected.

Input parameters:

- `caller_tenant` (string, required): The caller's namespace to cap.
- `calls_per_day` (integer, required): Max successful calls per UTC day for this caller.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `tool` (string, required): Local name of the shared tool.

### `host.share.caller_limit_remove` (~90 tokens)

Remove a caller_limit set by host.share.caller_limit.

Input parameters:

- `caller_tenant` (string, required): The caller's namespace whose limit to remove.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `tool` (string, required): Local name of the shared tool.

### `host.group.create` (~72 tokens)

Create a named group this tenant owns, for host.tool_share(visibility: "group").

Input parameters:

- `name` (string, required): Group name.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.group.add` (~79 tokens)

Add a tenant (by namespace) to a group this tenant owns.

Input parameters:

- `name` (string, required): Group name.
- `namespace` (string, required): Member tenant's namespace.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.group.remove` (~79 tokens)

Remove a tenant (by namespace) from a group this tenant owns.

Input parameters:

- `name` (string, required): Group name.
- `namespace` (string, required): Member tenant's namespace.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.group.list` (~55 tokens)

List the groups this tenant owns and their members.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.catalog.search` (~87 tokens)

Search public tools across every tenant by name/description substring.

Input parameters:

- `limit` (integer): Max results; default 20.
- `q` (string): Substring to match; omit for every public tool.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.catalog.get` (~84 tokens)

Return one public tool's descriptor and args_schema by its full name (<namespace>.<name>).

Input parameters:

- `full_name` (string, required): The tool's full name, <namespace>.<name>.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.secret_set` (~95 tokens)

Store an encrypted secret value under this tenant's namespace.

Input parameters:

- `name` (string, required): Secret name, referenced from a spec as secret.<name>.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `value` (string, required): The secret value; stored AES-256-GCM encrypted, never returned.

### `host.secret_list` (~56 tokens)

List this tenant's secret names (never their values).

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.registry_publish` (~69 tokens)

Publish this tenant's server.json to the configured MCP registry (requires --registry-url and admin.tenant_verify_namespace first).

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.state.get` (~138 tokens)

Read one key from this tenant's key-value state namespace. Returns found: false (not an error) if the key was never set.

Input parameters:

- `end_user` (string|null): "self" for the caller's own verified end-user identity, an explicit subject (only when this call carries no end-user identity of its own), or omit/null for the tenant-wide value.
- `key` (string, required): Key to read from this tenant's key-value state namespace.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.state.set` (~162 tokens)

Write one key in this tenant's key-value state namespace; value may be any JSON value. Overrun of the plan's state_bytes_max quota fails with state_quota_exceeded and writes nothing.

Input parameters:

- `end_user` (string|null): "self" for the caller's own verified end-user identity, an explicit subject (only when this call carries no end-user identity of its own), or omit/null for the tenant-wide value.
- `key` (string, required): Key to write in this tenant's key-value state namespace.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `value` (required): Any JSON value to store under key.

### `host.state.delete` (~122 tokens)

Delete one key from this tenant's key-value state namespace.

Input parameters:

- `end_user` (string|null): "self" for the caller's own verified end-user identity, an explicit subject (only when this call carries no end-user identity of its own), or omit/null for the tenant-wide value.
- `key` (string, required): Key to delete from this tenant's key-value state namespace.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.state.list` (~148 tokens)

List keys (with their current values) in this tenant's key-value state namespace, optionally filtered by prefix.

Input parameters:

- `end_user` (string|null): "self" for the caller's own verified end-user identity, an explicit subject (only when this call carries no end-user identity of its own), or omit/null for the tenant-wide value.
- `limit` (integer): Max keys to return; default 100.
- `prefix` (string): Only list keys starting with this prefix; default: all keys.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.state.table_create` (~193 tokens)

Declare (or replace the schema of) a table in this tenant's state store. schema is {"column": "text"|"integer"|"real"|"boolean"|"json"}; primary_key, if given, must name one of schema's columns -- an insert whose row matches an existing row's primary_key value replaces it.

Input parameters:

- `name` (string, required): Table name to declare, or replace the schema of.
- `primary_key` (string): Column name (must be in schema) whose matching value replaces an existing row on insert; optional.
- `schema` (object, required): Column name to type map, each type one of text|integer|real|boolean|json, e.g. {"id": "integer"}.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.state.table_drop` (~76 tokens)

Drop a declared table and every row it holds.

Input parameters:

- `name` (string, required): Name of the declared table to drop, with every row it holds.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.state.insert` (~180 tokens)

Insert one row (an object) or several (an array of objects) into a declared table. Each row is validated against the table's schema first -- a type mismatch fails the whole call with state_schema_violation and writes nothing.

Input parameters:

- `end_user` (string|null): "self" for the caller's own verified end-user identity, an explicit subject (only when this call carries no end-user identity of its own), or omit/null for the tenant-wide value.
- `rows` (required): One row (an object) or several (an array of objects), each validated against the table's schema.
- `table` (string, required): Name of the declared table to insert into.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.state.query` (~223 tokens)

Read rows from a declared table, optionally filtered (where: "field op value", ops = != < <= > >=, clauses joined by ' and '), ordered (order_by: "field" or "field desc") and capped (limit).

Input parameters:

- `end_user` (string|null): "self" for the caller's own verified end-user identity, an explicit subject (only when this call carries no end-user identity of its own), or omit/null for the tenant-wide value.
- `limit` (integer): Max rows to return; optional.
- `order_by` (string): Optional "field" or "field desc" to sort by.
- `table` (string, required): Name of the declared table to read from.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `where` (string): Optional filter, e.g. "age > 21"; ops are != < <= > >=, clauses joined by ' and '.

### `host.state.delete_rows` (~160 tokens)

Delete rows from a declared table matching an optional where filter (same grammar as host.state.query); omitting where deletes every row in the table.

Input parameters:

- `end_user` (string|null): "self" for the caller's own verified end-user identity, an explicit subject (only when this call carries no end-user identity of its own), or omit/null for the tenant-wide value.
- `table` (string, required): Name of the declared table to delete rows from.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `where` (string): Optional filter, same grammar as host.state.query; omit to delete every row.

### `host.table.create` (~209 tokens)

Declare a table in this tenant's SQL table store -- a different store from host.state.*'s key-value namespace and its own tables: use host.state.* for a handful of small values, host.table.* when you want real SQL (joins, aggregates, read-only queries) over rows. columns is {"column": "text"|"integer"|"real"| "timestamp"|"boolean"|"json"}; primary_key, if given, must name one of columns's own entries.

Input parameters:

- `columns` (object, required): Column name to type map, each type one of text|integer|real|timestamp|boolean|json, e.g. {"id": "integer"}.
- `name` (string, required): Table name to declare.
- `primary_key` (string): Column name (must be in columns); optional.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.table.append` (~133 tokens)

Append one row (an object) or several (an array of objects) to a declared table. Each row is validated against the table's schema first -- a type mismatch fails the whole call with table_schema_violation and writes nothing.

Input parameters:

- `rows` (required): One row (an object) or several (an array of objects), each validated against the table's schema.
- `table` (string, required): Name of the declared table to append to.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.table.query` (~134 tokens)

Run a single read-only SQL SELECT (CTEs allowed) against this tenant's own tables. Structurally rejected (not by string matching): anything but exactly one SELECT statement, a result over 1,000 rows, or a query running past 5 seconds -- each refusal names the rule or bound it hit.

Input parameters:

- `sql` (string, required): A single read-only SELECT statement (CTEs allowed) over this tenant's own declared tables.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.table.list` (~69 tokens)

List this tenant's declared tables, each with its current row count, plus the tenant's whole table-store byte usage.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.table.drop` (~75 tokens)

Drop a declared table and every row it holds.

Input parameters:

- `name` (string, required): Name of the declared table to drop, with every row it holds.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.table.schema` (~87 tokens)

Return one table's columns, types, row count and byte count, without running a query -- how an agent discovers its own table shape.

Input parameters:

- `table` (string, required): Name of the declared table to describe.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.docs.put` (~254 tokens)

Write (or, for an already-used name, create a new version of) a document in this tenant's document store. mime is detected from name and content when omitted; allowed mimes are text/plain, text/markdown, application/json, text/csv. content (or content_base64 for arbitrary bytes) must be at most MCPHOST_DOC_MAX_BYTES (default 2 MiB). Identical content to the current version is a no-op that repeats the current version.

Input parameters:

- `content` (string): Document content as text; use content_base64 instead for arbitrary bytes.
- `content_base64` (string): Document content, base64-encoded; use content instead for plain text.
- `metadata`: Arbitrary caller metadata stored alongside the document; any JSON value.
- `mime` (string): One of text/plain, text/markdown, application/json, text/csv; detected from name/content when omitted.
- `name` (string, required): Document name; same name on a later put creates a new version of the same id.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.docs.get` (~151 tokens)

Read a document by id or name -- version defaults to the current one; text: true also returns the extracted plain text this document's mime produced at put time.

Input parameters:

- `id` (string): Document id to read; use name instead if you don't have it.
- `name` (string): Document name to read; use id instead if you have it.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `text` (boolean): Also return the extracted plain text; default false.
- `version` (integer): Version to read; defaults to the document's current version.

### `host.docs.list` (~167 tokens)

List documents in this tenant's document store. Without since, returns the current live snapshot; with since (a watermark from host.docs.status, 0 for everything), returns every document changed since, including deleted ones (deleted: true).

Input parameters:

- `cursor`: Opaque pagination cursor from a previous list call's next_cursor.
- `limit` (integer): Max documents to return; default 100.
- `prefix` (string): Only list documents whose name starts with this prefix.
- `since` (integer): Return documents changed since this watermark (a host.docs.status seq); omit for the current live snapshot only.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.docs.delete` (~107 tokens)

Soft-delete a document by id or name; still visible via host.docs.list {since} with deleted: true.

Input parameters:

- `id` (string): Document id to delete; use name instead if you don't have it.
- `name` (string): Document name to delete; use id instead if you have it.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.docs.status` (~106 tokens)

This tenant's document store counters: documents, bytes, text_bytes, the current change watermark, this plan's document/byte quotas, and an index block (mode, indexed_watermark, lag_seconds, pending_documents, chunks, rebuilding, quota_chunks_reached) describing the search index's own freshness.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.docs.search` (~177 tokens)

Ranked passage search over this tenant's document store. Lexical (BM25) by default; embeddings mode (set via host.docs.index_config) ranks by cosine and falls back to lexical (index.mode: "lexical-fallback") if the provider call fails. Returns [{document_id, name, version, chunk_no, offset, text, score}] plus an index block naming the mode and how stale the index is.

Input parameters:

- `filter` (object): Restrict results to documents matching prefix and/or name.
- `k` (integer): Max results to return, 1-20; default 5.
- `query` (string, required): Search query text.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.docs.index_config` (~200 tokens)

Configure this tenant's search index provider. provider: "none" (lexical only, the default) or "openai-compatible" (endpoint, model, and secret -- a tenant secret name used as the embeddings request's bearer -- all required). Changing config re-indexes every document from scratch in the background.

Input parameters:

- `dims` (integer): Expected embedding dimensionality, for documentation purposes.
- `endpoint` (string): Embeddings API URL; required for openai-compatible.
- `model` (string): Embeddings model name; required for openai-compatible.
- `provider` (string, required): "none" or "openai-compatible".
- `secret` (string): Name of a tenant secret (host.secret_set) used as the bearer; required for openai-compatible.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.docs.reindex` (~110 tokens)

Force this tenant's search index to re-chunk (and re-embed, if a provider is configured) one document (document_id) or, without document_id, every document, on the indexer's next tick.

Input parameters:

- `document_id` (string): Reindex only this document; omit to reindex every document.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.docs.purge` (~142 tokens)

Drop stored versions of a document older than older_than_versions versions back from its current one -- get {version: <a dropped version>} then reads not found.

Input parameters:

- `id` (string): Document id to purge old versions of; use name instead if you don't have it.
- `name` (string): Document name to purge old versions of; use id instead if you have it.
- `older_than_versions` (integer, required): How many versions back from the current one to keep.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.table.describe` (~151 tokens)

Return the generated semantic model for a declared table: per column its inferred type, null share, distinct count, min/max or top values, and role (key|category|measure|date|id|text); per table its row count, candidate primary key, detected foreign keys, and suggested measures/dimensions. Refreshes after append/create within 30s; a call right after a write returns the previous model with stale: true rather than blocking.

Input parameters:

- `table` (string, required): Name of the declared table to describe.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.table.model_set` (~161 tokens)

Annotate a declared table or one of its columns -- the next describe merges this back in (an annotation's role wins over the inferred one; unit/description are added; hidden marks a column to omit from a summary). key must be one of role, unit, description, hidden.

Input parameters:

- `column` (string): Column name to annotate; omit for a table-level annotation.
- `key` (string, required): One of role, unit, description, hidden.
- `table` (string, required): Name of the declared table to annotate.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `value` (required): The annotation's value.

### `host.table.models` (~74 tokens)

List every declared table that has a computed semantic model, each with its version, staleness, row count and when it was last computed.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.runs.get` (~96 tokens)

Read one run's status, progress and (once done) result by id -- the same run a host.tool_call(..., async=true) or a scheduled/triggered execution created.

Input parameters:

- `run_id` (string, required): The run id to read.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.runs.list` (~176 tokens)

List this tenant's recent runs, newest first, optionally filtered by tool, status (queued|running|done|error|timeout|cancelled), trigger (call|job|schedule|event|chain) or end_user_subject (the end user, if any, the run ran as).

Input parameters:

- `end_user_subject` (string): Only runs that ran as this end user's subject.
- `limit` (integer): Max runs to return; default 20.
- `status` (string): Only runs in this status.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `tool` (string): Only runs of this tool name.
- `trigger` (string): Only runs of this trigger kind.

### `host.runs.cancel` (~93 tokens)

Stop a queued or running job: its sandbox process is killed within ~2s and the run reads cancelled. A run that already finished fails with run_not_cancellable.

Input parameters:

- `run_id` (string, required): The run id to cancel.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.runs.purge` (~110 tokens)

Delete the stored results of every done run finished at or before before_unix; each then reads done with result: null, purged: true. Frees state_bytes_max quota the results were counted against.

Input parameters:

- `before_unix` (integer, required): Purge results of runs finished at or before this unix timestamp.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.runs.wait` (~167 tokens)

Long-poll one run until it finalizes, until: {counter, gte} is reached, or timeout_s elapses (max 25s), returning its current status either way -- for a client with no polling loop of its own.

Input parameters:

- `run_id` (string, required): The run id to wait on.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `timeout_s` (integer): Max seconds to wait, capped at 25; default 20.
- `until` (object): {counter: <name>, gte: <n>} -- return as soon as that counter reaches n, even while the run is still running.

### `host.progress` (~184 tokens)

Report (or merge in) counters and/or pct/msg on a run, by id. Each named counter (items_processed, items_total, bytes_out, custom.<k>) is monotonic on its own -- a lower value than what's already stored fails validation with nothing written. Read back via host.runs.get/wait/list's counters field.

Input parameters:

- `counters` (object): items_processed?, items_total?, bytes_out?, custom?: {k: number} -- each key monotonic.
- `msg` (string): A free-text progress message.
- `pct` (integer): 0-100 percent complete, free text.
- `run_id` (string, required): The run id to report progress on.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.runs.part` (~133 tokens)

Read part n of a run's result (host.runs.get/wait inline only part 0). A run whose whole result fit inline reads back parts: 1, n: 0 with the full result. n past the last part fails with not_found.

Input parameters:

- `n` (integer): The 0-based part index; default 0.
- `run_id` (string, required): The run id to read a part of.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.trigger.set` (~675 tokens)

Run a published tool on a cron schedule (5-field: minute hour day-of-month month day-of-week, UTC), give it a public webhook URL (kind="event"): a signed POST to that URL runs the tool with the event as its argument, fire it whenever this tenant receives a message (kind="message"): the tool runs with the message envelope as its argument, or give it an inbound-inbox URL (kind="webhook"): a verified POST lands as a row in state table inbox_<name> and fires the tool with that row as its argument -- the response carries {url, secret} once (host.trigger.get afterwards never returns the secret again). Each firing/delivery is a run visible in host.runs.list(trigger="schedule"|"event"|"message"|"webhook"). Refuses schedules_max (trigger_quota_exceeded, shared by schedule and webhook triggers), event_triggers_max (shared by event and message triggers) or a too-short schedule interval (trigger_interval_too_short); an invalid expression or verify config fails trigger_invalid naming the field.

Input parameters:

- `args` (object): Arguments passed to the tool on each firing/delivery (kind="schedule"/"event" only -- a message trigger's whole argument is the message envelope and a webhook trigger's whole argument is the stored i…
- `channel_id` (string): kind="message": scope this trigger to one group channel's posts (host.channel.open's channel_id) instead of ordinary host.msg.send/reply deliveries.
- `dedupe_header` (string): kind="event": a header (e.g. X-GitHub-Delivery) whose repeated value within 24h answers 202 with the original run id instead of running again.
- `from` (string): kind="message": only fire for messages from this address (@handle or t_... namespace); omit to fire for any sender.
- `kind` (string): "schedule" (default), "event", "message" or "webhook".
- `name` (string): kind="webhook": letters/digits/underscore -- becomes the inbox_<name> state table each accepted delivery is stored in.
- `schedule` (string): kind="schedule": 5-field cron expression (minute hour day-of-month month day-of-week), UTC. Supports *, lists, ranges and steps.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `tool` (string, required): The published tool this trigger runs.
- `tz` (string): kind="schedule" P1: only "UTC" (or omitted) works today.
- `verify`: kind="event": {scheme: "hmac-sha256"|"hmac-sha1"|"token"|"none", header, secret (a host.secret_set name), prefix?, timestamp_header?, tolerance_s?, allow_unverified? (required true for scheme "none")…

### `host.trigger.list` (~105 tokens)

List this tenant's triggers (optionally filtered by tool), each with next_unix, last_run_id and last_status (schedule), url/verify/unverified (event), or url/name/verify with no secret (webhook).

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `tool` (string): Only triggers on this tool name.

### `host.trigger.get` (~73 tokens)

Read one trigger's current schedule, next_unix, last_run_id and last_status.

Input parameters:

- `id` (string, required): The trigger id.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.trigger.pause` (~69 tokens)

Stop a trigger from firing until resumed; still counts toward schedules_max.

Input parameters:

- `id` (string, required): The trigger id.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.trigger.resume` (~83 tokens)

Re-enable a paused trigger; if its scheduled time already passed, the next tick fires it once (a missed firing is never replayed).

Input parameters:

- `id` (string, required): The trigger id.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.trigger.remove` (~70 tokens)

Delete a trigger outright (frees its schedules_max slot, unlike pause).

Input parameters:

- `id` (string, required): The trigger id.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.trigger.fire` (~86 tokens)

Run a schedule once right now, for testing -- recorded as trigger: "schedule" with manual: true, independent of next_unix or pause state.

Input parameters:

- `id` (string, required): The trigger id.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.trigger.test` (~294 tokens)

Dry-run an event trigger's verify config against a payload you supply, without exposing its real URL -- verifies the signature exactly as POST /hooks/... would, then runs the tool with the event as its argument. On a message trigger, runs the tool with a synthetic envelope (test: true, no messages row created). On a webhook trigger, builds and self-signs a synthetic body exactly like a real sender would, then stores and fires it through the same path POST /hook/... uses (one inbox row, one run). The run is marked test: true. A wrong signature fails signature_invalid, naming the header it checked.

Input parameters:

- `body`: kind="event"/"webhook": the payload to verify and run with -- any JSON value. kind="message": the synthetic envelope's body text.
- `data`: kind="message": the synthetic envelope's data payload.
- `from` (string): kind="message": the synthetic envelope's from address; default "@test".
- `headers` (object): kind="event": header name -> string value, e.g. {"X-Hub-Signature-256": "sha256=..."}.
- `id` (string, required): The event, message or webhook trigger id.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.trigger.replay` (~212 tokens)

Re-run a past event- or message-triggered run's exact stored event/envelope (no re-verification -- the original delivery already passed it). The new run's trigger_ref names the original run id. For a webhook trigger, pass id (the trigger) and row_id (an inbox_<name> row id, e.g. from POST /hook/...'s own response or host.state.query) instead of run_id -- a paused delivery has no run to replay from.

Input parameters:

- `id` (string): kind="webhook" only: the trigger id (paired with row_id).
- `row_id` (integer): kind="webhook" only: the inbox_<name> row id to replay (paired with id).
- `run_id` (string): The event- or message-triggered run id to replay.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `billing.plans` (~74 tokens)

The plan catalog (price and quotas per plan) and whether Stripe billing is configured on this host. Anonymous callers get the same answer as tenants.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `billing.status` (~62 tokens)

This tenant's plan, usage against each quota, and when the daily call quota resets.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `billing.checkout` (~109 tokens)

Create (or reuse an open one for the same plan) a Stripe Checkout URL to upgrade this tenant, defaulting to the pro plan. Returns billing_unavailable if this host has no Stripe key configured -- call billing.plans first to check.

Input parameters:

- `plan` (string): Which plan to check out; default: pro.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.agent.whoami` (~83 tokens)

Return this tenant's own agent-directory address: namespace, handle (if claimed), display name, contact_policy and plan. Never a key hash, billing field, or call log.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.agent.profile_set` (~245 tokens)

Claim or update this tenant's agent-directory card: an optional unique @handle (^[a-z][a-z0-9_]{2,31}$, stored lower-case), a description, up to 16 tags, and a contact_policy (open, contacts, or closed). Every argument is optional and, if omitted, leaves that field unchanged; an explicit null clears handle or description. A taken handle fails with handle_taken (names no one); a reserved one fails with handle_reserved.

Input parameters:

- `contact_policy` (string): What contact this tenant accepts; enforced by the inbox PRD.
- `description` (string|null): Short blurb shown to other agents via lookup/search; up to 512 bytes; null clears it.
- `handle` (string|null): Unique handle to claim, e.g. "indexer" (without the @); null clears it.
- `tags` (array): Up to 16 tags of up to 32 bytes each, for host.agent.search.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.agent.lookup` (~120 tokens)

Resolve another agent's namespace or @handle to its public card (address, handle, display_name, description, tags, contact_policy, last_seen, source_class). Unknown, disabled, and deleted addresses all return the identical agent_not_found error.

Input parameters:

- `address` (string, required): An @handle (e.g. "@indexer") or a bare namespace (t_...).
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.agent.search` (~169 tokens)

Find agents by exact tag or a case-insensitive substring of handle, display name, or description. Disabled tenants are excluded. Ordered by handle (unclaimed last), then namespace; page with cursor from the previous response.

Input parameters:

- `cursor` (string): Opaque cursor from a previous host.agent.search response's cursor field; omit for the first page.
- `limit` (integer): Max results per page, up to 50; default 50.
- `query` (string): Substring to match; omit for no text filter.
- `tag` (string): Exact tag to match; omit for no tag filter.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.msg.send` (~289 tokens)

Send a message to one or more agent-directory addresses, creating a new thread (or, with thread_id, adding to one you already participate in). Refused recipients (agent_not_found, contact_refused, recipient_inbox_full) are listed in refused rather than failing the whole call; from is always the authenticated tenant, never a caller argument.

Input parameters:

- `body` (string, required): Message text; non-empty after trim.
- `data` (object): Optional structured payload.
- `dedupe_key` (string): Resend with the same key within 24h to get back the original message_id instead of a duplicate.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `thread_id` (string): Add this send to an existing thread you participate in instead of starting a new one; to's addresses join as participants.
- `to` (array, required): 1 to recipients_per_msg_max addresses (@handle or t_... namespace).
- `urgent` (boolean): Mark this send urgent (default false): allowed only to accepted contacts or open recipients (refused the same as any other send otherwise), under its own urgent_per_day quota per sender/recipient pai…

### `host.msg.reply` (~180 tokens)

Reply in a thread you participate in; appends with the next seq. Blocked or contact-closed participants are skipped and listed in refused rather than failing the reply. thread_not_found (byte-identical for a nonexistent id) if you are not a participant.

Input parameters:

- `body` (string, required): Message text; non-empty after trim.
- `data` (object): Optional structured payload.
- `dedupe_key` (string): Resend with the same key within 24h to get back the original message_id instead of a duplicate.
- `in_reply_to` (string): The message_id this replies to.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `thread_id` (string, required): The thread to reply in.

### `host.msg.inbox` (~123 tokens)

Every unread-or-read message across every thread you participate in, excluding your own sends, ordered oldest first; page with cursor from the previous response's next_cursor.

Input parameters:

- `cursor` (string): Opaque; omit for the first page.
- `limit` (integer): Up to 100; default 50.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `unread_only` (boolean): Filter to messages not yet acked.

### `host.msg.thread` (~117 tokens)

Every message in one thread you participate in, ordered by seq; thread_not_found if you are not (or no longer) a participant.

Input parameters:

- `cursor` (string): The seq to resume after; omit for the start.
- `limit` (integer): Up to 100; default 50.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `thread_id` (string, required): The thread to read.

### `host.msg.ack` (~88 tokens)

Mark messages as read for you; unread_only inbox reads stop returning them. Per-recipient -- a sender never sees others' receipts.

Input parameters:

- `message_ids` (array, required): message_ids to mark read for you.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.msg.block` (~104 tokens)

Block an address: its future sends to you are refused agent_not_found, byte-identical to sending to a nonexistent address. You can still send to it. Block lists are never exposed to the blocked party.

Input parameters:

- `address` (string, required): The @handle or t_... namespace to block.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.msg.unblock` (~67 tokens)

Remove a block.

Input parameters:

- `address` (string, required): The @handle or t_... namespace to unblock.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.msg.wait` (~158 tokens)

Long-poll for a new message until one past cursor arrives or timeout_s elapses (max 25s), returning the same shape as host.msg.inbox either way -- for a client with no polling loop of its own. On timeout, messages is empty and next_cursor is unchanged.

Input parameters:

- `cursor` (string): Opaque; omit to wait for the next message from now.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `timeout_s` (integer): Max seconds to wait, capped at 25; default 20.
- `unread_only` (boolean): Filter to messages not yet acked.

### `host.agent.contact_request` (~160 tokens)

Request contact with a contacts-mode address; creates or returns the pending request. not_needed for an open address or one you already have an accepted contact with; contact_refused for a closed address; contact_pending if a request is already pending or was denied within the last 7 days; agent_not_found (same as a nonexistent address) if that address has blocked you. Quota contact_requests_per_day.

Input parameters:

- `address` (string, required): An @handle or a bare namespace (t_...).
- `note` (string): Optional note, up to 512 bytes.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.agent.contacts` (~98 tokens)

List your accepted contacts and every pending/decided contact request in either direction; status optionally narrows incoming/outgoing to one of pending, accepted, denied, expired.

Input parameters:

- `status` (string): Filter incoming/outgoing requests to this status; omit for all.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.agent.contact_accept` (~85 tokens)

Accept a pending contact request addressed to you: both you and the requester become accepted contacts, visible from either side via host.agent.contacts().

Input parameters:

- `request_id` (string, required): The request to accept.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.agent.contact_deny` (~89 tokens)

Deny a pending contact request addressed to you. The requester's subsequent sends and requests get contact_pending for 7 days, then may request again.

Input parameters:

- `request_id` (string, required): The request to deny.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.agent.mute` (~114 tokens)

Mute an address: its future messages are still stored and readable via host.msg.thread, but excluded from host.msg.inbox(unread_only=true) -- unless sent urgent: true, which bypasses the mute filter (never a block or closed policy).

Input parameters:

- `address` (string, required): The @handle or t_... namespace to mute.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.agent.unmute` (~68 tokens)

Remove a mute.

Input parameters:

- `address` (string, required): The @handle or t_... namespace to unmute.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.agent.contacts_import` (~136 tokens)

Request contact with up to 50 addresses at once (e.g. an operator's own fleet of tenants); each is resolved the same way a single host.agent.contact_request would be, but a per-address failure (already connected, already pending, blocked, over quota, ...) is reported in that address's own result entry rather than failing the whole call.

Input parameters:

- `addresses` (array, required): 1 to 50 @handle or t_... addresses.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.channel.open` (~143 tokens)

Create a named channel, or return the existing one of that name; or, with group instead of name, open (idempotently) the one channel for a group you own -- every current member can then host.channel.post/read it. Refuses channels_max (quota_exceeded) past the plan's cap.

Input parameters:

- `group` (string): A group you own (host.group.create); open its one channel instead.
- `name` (string): Channel name to create or look up.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.channel.post` (~130 tokens)

Post to a channel by name or channel_id; advances your own read cursor to the new post. Against a group channel's id, any current member may post; a non-member gets channel_not_found, byte-identical to an unknown id.

Input parameters:

- `body` (string, required): Post text; non-empty after trim.
- `channel` (string, required): Channel name or channel_id.
- `data` (object): Optional structured payload.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.channel.read` (~172 tokens)

Read a group channel's posts in seq order since a cursor (default: your own last read position, or 0 for a first read). ack: true stores next_cursor as your new read position. A non-member gets channel_not_found.

Input parameters:

- `ack` (boolean): Store next_cursor as your new read position.
- `channel_id` (string, required): The group channel's id, from host.channel.open(group=...).
- `cursor` (integer): Read posts with seq greater than this; omit to resume from your own stored cursor.
- `limit` (integer): Max posts to return; default 50, max 100.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.channel.close` (~81 tokens)

Owner-only: close a group channel. Further host.channel.post calls get channel_closed; host.channel.read keeps working.

Input parameters:

- `channel_id` (string, required): The group channel's id.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.channel.freeze` (~82 tokens)

Owner-only: freeze a group channel. Further host.channel.post calls get channel_frozen; host.channel.read keeps working.

Input parameters:

- `channel_id` (string, required): The group channel's id.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.channel.unfreeze` (~76 tokens)

Owner-only: undo host.channel.freeze; the next post succeeds with the next seq.

Input parameters:

- `channel_id` (string, required): The group channel's id.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.issuer_set` (~167 tokens)

Register (or update) an OAuth issuer for this tenant: bearer JWTs with iss equal to issuer, a matching aud, verified against jwks_url, authenticate as this tenant. Up to 3 issuers per tenant; an issuer already registered by another tenant is refused issuer_already_registered.

Input parameters:

- `audience` (string, required): The JWT `aud` claim value to require.
- `issuer` (string, required): The JWT `iss` claim value to match, e.g. https://issuer.example.com.
- `jwks_url` (string, required): URL this host fetches the issuer's JWKS from.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.issuer_remove` (~79 tokens)

Remove one of this tenant's registered OAuth issuers; bearer JWTs from it stop authenticating immediately.

Input parameters:

- `issuer` (string, required): The issuer to remove.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.issuers` (~69 tokens)

List this tenant's registered OAuth issuers with their audience, jwks_url, and JWKS fetch age.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.scope_set` (~135 tokens)

Declare (or update) one scope this tenant's tools may require: name (a catalogued name, or the built-ins read/write) and a human-readable description shown on the OAuth consent page. Up to 32 catalog entries per tenant.

Input parameters:

- `description` (string, required): Human-readable text shown on the OAuth consent page.
- `name` (string, required): ^[a-z][a-z0-9_:.-]{0,40}$
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.scopes` (~58 tokens)

List this tenant's own scope catalog: name and description.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.grants` (~105 tokens)

List the OAuth clients currently connected to this tenant through mcphost's own hosted authorization server (host.oauth.issuer_set is for a tenant's own bring-your-own issuer instead): each grant's client_name, method (cimd|dcr), resource, created_at and last_used_at.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.grant_revoke` (~90 tokens)

Revoke one hosted-authorization-server grant by id (from host.oauth.grants): its access tokens fail within 60s and its refresh tokens stop rotating.

Input parameters:

- `id` (integer, required): The grant id.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.policy_set` (~256 tokens)

Set this tenant's hosted-authorization-server client and session policy. Every field is optional and, when omitted, keeps its current (or default) value: clients (any|allowlist|approve, default any), allowlist (client_id or CIMD-host strings, for allowlist mode), access_ttl_s (300..3600, default 3600), refresh_ttl_s (3600..2592000, default 2592000), max_grant_age_s (a refresh past this many seconds since consent fails invalid_grant/grant_expired; null clears it), reconsent_after_s (a refresh past this many seconds since consent fails invalid_grant/reconsent_required and the next authorize shows consent again; null clears it).

Input parameters:

- `access_ttl_s` (integer)
- `allowlist` (array)
- `clients` (string)
- `max_grant_age_s` (integer)
- `reconsent_after_s` (integer)
- `refresh_ttl_s` (integer)
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.policy` (~82 tokens)

This tenant's current hosted-authorization-server client and session policy (host.oauth.policy_set's own field shape); the documented defaults for a tenant that has never called host.oauth.policy_set.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.pending` (~58 tokens)

List clients awaiting approval under this tenant's clients: approve policy.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.client_approve` (~88 tokens)

Approve a pending client (from host.oauth.pending): its next /oauth/authorize reaches consent directly.

Input parameters:

- `client_id` (string, required): The client_id to approve, as listed by host.oauth.pending.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.client_deny` (~87 tokens)

Deny a pending client (from host.oauth.pending): every later authorize attempt reads client_not_allowed.

Input parameters:

- `client_id` (string, required): The client_id to deny, as listed by host.oauth.pending.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.revoke_all` (~74 tokens)

Revoke every one of this tenant's live grants, refresh tokens and pending clients at once: access tokens fail within 60s.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.audit` (~146 tokens)

Page this tenant's OAuth auth audit log (authorize/consent/token/refresh/revoke/ policy_change/approved/denied/refused events), newest additions last. Optional since/until (unix seconds) and event filters; limit defaults to 50, max 500; cursor resumes from a previous page's cursor field.

Input parameters:

- `cursor` (string)
- `event` (string)
- `limit` (integer)
- `since` (integer)
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `until` (integer)

### `host.oauth.audit_export` (~127 tokens)

Export this tenant's OAuth auth audit log for since..until as JSON lines (one object per line, same fields host.oauth.audit pages). Refuses export_too_large (with a suggested narrower window) past 50 MiB.

Input parameters:

- `since` (integer, required): Start of the export window, unix seconds (inclusive).
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.
- `until` (integer, required): End of the export window, unix seconds (exclusive).

### `host.oauth.provider_set` (~278 tokens)

Register (or update) this tenant's own OIDC identity provider: end users who connect to this tenant's per-tenant resource log in through it. Fetches the issuer's discovery document once (https only) and stores authorization_endpoint, token_endpoint, and jwks_uri. client_secret is encrypted at rest and never shown again.

Input parameters:

- `claims_map` (object): Optional {"email": "<claim name>", "name": "<claim name>"} override; defaults to the claim names themselves.
- `client_id` (string, required): The client id your provider issued for mcphost.
- `client_secret` (string, required): The client secret your provider issued for mcphost; encrypted at rest and never shown again.
- `issuer` (string, required): The provider's issuer URL, e.g. https://your-idp.example.com.
- `owner_login` (boolean): Default false: also allow this tenant's own key/claim login on its per-tenant resource.
- `require_verified_email` (boolean): Default true: refuse login when the provider reports email_verified: false.
- `scopes` (array): Default ["openid", "email", "profile"].
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.provider` (~78 tokens)

This tenant's registered OIDC identity provider (issuer, client_id, endpoints, scopes, flags) -- null if none is set. Never carries the client secret.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.provider_remove` (~82 tokens)

Remove this tenant's OIDC identity provider: every federated grant it produced is revoked immediately, and the per-tenant resource falls back to key/claim (owner) login.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.doctor` (~104 tokens)

Diagnose this tenant's OIDC provider setup: discovery reachable, jwks_uri reachable, per-tenant resource metadata, whether the callback URL is listed in the provider's discovery document (when exposed), and a dry-run authorize URL. One line per check with ok|fail and a fix.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.trusted_issuer_set` (~221 tokens)

Register (or update) an identity-assertion issuer for this tenant's enterprise-managed auth: identity assertions with iss equal to issuer, from client_id, verified against jwks_url, mint a token for the employee they name -- no consent screen. Up to 4 trusted issuers per tenant; a 5th is refused quota_trusted_issuers; an issuer already trusted by another tenant is refused issuer_already_registered.

Input parameters:

- `audience` (string): Expected assertion `aud`, when the provider signs one other than this host's own issuer URL.
- `client_id` (string, required): The pre-registered enterprise client id allowed to use this issuer's grant.
- `issuer` (string, required): The identity assertion's `iss` claim value to match.
- `jwks_url` (string, required): URL this host fetches the issuer's JWKS from.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.trusted_issuer_remove` (~81 tokens)

Remove one of this tenant's trusted identity-assertion issuers; its assertions stop authenticating immediately.

Input parameters:

- `issuer` (string, required): The issuer to remove.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.oauth.trusted_issuers` (~71 tokens)

List this tenant's trusted identity-assertion issuers with their jwks_url, client_id and audience.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.enduser.whoami` (~97 tokens)

The end user (if any) this call itself carries: {subject, issuer, method, verified_at} from the OAuth bearer's sub/iss or a verified end_user_assertion; null when the call carries no verified end-user identity.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.enduser.assertion_secret_rotate` (~119 tokens)

Generate and store a new per-tenant secret for signing end_user_assertion (HS256 compact JWS, claims sub/iat/exp with exp <= iat + 3600). Returns the secret once; it is never shown again and never appears in host.secret_list. Assertions signed with any prior secret stop verifying immediately -- no overlap window.

Input parameters:

- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.enduser.list` (~180 tokens)

List this tenant's end users with last-seen and call counts, newest last-seen first. Optional since (unix seconds, filters last_seen), revoked (bool), limit (default 50, max 1000), and cursor (from a previous page's cursor field).

Input parameters:

- `cursor` (string): Opaque; resume after a previous response's cursor.
- `limit` (integer): Max rows per page (default 50, max 1000).
- `revoked` (boolean): true: only revoked end users; false: only active ones; omit for both.
- `since` (integer): Only end users last seen at or after this unix timestamp.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.enduser.get` (~102 tokens)

One end user's roster row (subject, issuer, first_seen, last_seen, calls_total, revoked_at, revoked_by, purged_at) plus its live state_rows, vault_connections, and runs_30d counts.

Input parameters:

- `subject` (string, required): The end user's subject.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.enduser.audit` (~145 tokens)

One end user's calls (tool, outcome, run_id, impersonated) merged with its revoke/unrevoke/purge control-plane events, newest first, paged by cursor.

Input parameters:

- `cursor` (string): Opaque; resume after a previous response's cursor.
- `limit` (integer): Max entries per page (default 50, max 1000).
- `since` (integer): Only entries at or after this unix timestamp.
- `subject` (string, required): The end user's subject.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.enduser.revoke` (~95 tokens)

Revoke an end user: its next identified call is refused with end_user_revoked, no tool runs, and its vault-token connections are disconnected.

Input parameters:

- `reason` (string)
- `subject` (string, required): The end user's subject.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.enduser.unrevoke` (~75 tokens)

Reverse a prior host.enduser.revoke; the end user's calls succeed again.

Input parameters:

- `subject` (string, required): The end user's subject.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.enduser.purge` (~113 tokens)

Delete a revoked end user's scoped state and vault-token rows, de-identify its calls rows (kept, never deleted), and set purged_at. Requires the end user to be revoked first (revoke_required otherwise). Returns {state_rows, vault_tokens} counts.

Input parameters:

- `subject` (string, required): The end user's subject.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

### `host.enduser.export` (~93 tokens)

Export one end user's state rows and call history as a bundle at /exports/<run_id>, the same envelope host.export returns (download_url, size_bytes, expires_unix).

Input parameters:

- `subject` (string, required): The end user's subject.
- `tenant_key` (string): The key `signup` returned. Required only when this connection carries no Authorization: Bearer header -- when both are present, the header wins.

## Diagnostics

Captured diagnostic sections: TLS, DNSSEC, Authorisation, Transports. The full working is on the page: https://verifymcp.io/servers/dev-mcphost-mcphost/mcphost#diagnostics

## Score history

- 2026-09-29: 88
- 2026-09-28: 87
- 2026-09-27: 83
- 2026-09-26: 83
- 2026-09-25: 72
- 2026-09-24: 71
- 2026-09-23: 71
- 2026-09-22: 70
- 2026-09-21: 70
- 2026-09-20: 70
- 2026-09-19: 69
- 2026-09-18: 69
- 2026-09-17: 68
- 2026-09-16: 68
- 2026-09-15: 67
- 2026-09-14: 67
- 2026-09-13: 67
- 2026-09-12: 66
- 2026-09-11: 63
- 2026-09-10: 62
- 2026-09-09: 62
- 2026-09-08: 62
- 2026-09-07: 62
- 2026-09-06: 61

## Common questions

### What is the mcphost MCP server?

mcphost is an MCP server listed in the public MCP registry as dev.mcphost/mcphost. Host your MCP tool over streamable HTTP in one command. This page covers its hosted endpoint (https://mcphost.dev/mcp).

### Is the mcphost MCP server safe to use?

mcphost scores 88 out of 100 on VerifyMCP. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the mcphost MCP server expose?

mcphost exposes 136 tools: signup, host.whoami, host.redeem, host.key_rotate, host.self_offboard, and 131 more. Their descriptions and schemas cost roughly 17,493 tokens of context every time the server is loaded.

### Does the mcphost MCP server require authentication?

Yes. mcphost asked us for credentials when we connected, so you will need to authorise it in your MCP client before it can do anything.

### Is the mcphost MCP server still maintained?

mcphost is still listed as active in the MCP registry. We last reached this channel on 29 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

## Links

- Remote endpoint: https://mcphost.dev/mcp
- Website: https://mcphost.dev/docs
- Changelog RSS feed: https://verifymcp.io/servers/dev-mcphost-mcphost/mcphost.xml
- Changelog JSON feed: https://verifymcp.io/servers/dev-mcphost-mcphost/mcphost.json
- HTML version of this page: https://verifymcp.io/servers/dev-mcphost-mcphost/mcphost
