Hosted MCP runtime where your agent publishes its own tools by tool call and keeps working.
Maintain this server? Claim it
Call this server's tools from your browser. Nothing to install.
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
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.
The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins.
This tool isn't marked read-only, so it may change something on the server or in an account you connected.
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.
| Argument | Type | Description |
|---|---|---|
| tenant_key | string | The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins. |
{
"type": "object",
"required": [],
"properties": {
"tenant_key": {
"type": "string",
"description": "The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins."
}
},
"x-mcphost-validated": true,
"additionalProperties": false
}List every error code this host can return, each with its class (agent_fault | host_refusal | upstream_fault | plan_limit | host_fault), family, remedy, docs anchor, retryable flag and help_url -- the same object GET /errors.json serves. Pass code to get one row; a misspelt code answers tool_not_found with did_you_mean. Read-only, anonymous, no tenant data.
| Argument | Type | Description |
|---|---|---|
| code | string | An error code, e.g. tool_exception. Omit to list every code. |
| tenant_key | string | The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins. |
{
"type": "object",
"required": [],
"properties": {
"code": {
"type": "string",
"description": "An error code, e.g. tool_exception. Omit to list every code."
},
"tenant_key": {
"type": "string",
"description": "The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins."
}
},
"x-mcphost-validated": true,
"additionalProperties": false
}List your own feedback (newest first, status received). Anonymous callers get [].
| Argument | Type | Description |
|---|---|---|
| limit | integer | Max rows, up to 100; default 20. |
| tenant_key | string | The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins. |
{
"type": "object",
"required": [],
"properties": {
"limit": {
"type": "integer",
"description": "Max rows, up to 100; default 20."
},
"tenant_key": {
"type": "string",
"description": "The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins."
}
},
"x-mcphost-validated": true,
"additionalProperties": false
}Tell the host's humans what you needed: kind, up to 2048 bytes of text, optional context. Works before signup. Returns feedback_id.
| Argument | Type | Description |
|---|---|---|
| kind* | string | What you are telling the host. |
| text* | string | What you needed or saw; 1 to 2048 bytes after trim. |
| context | object | Optional, at most 1 KB: tool, error_code, free. |
| tenant_key | string | The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins. |
{
"type": "object",
"required": [
"kind",
"text"
],
"properties": {
"kind": {
"enum": [
"missing_tool",
"wrong_error",
"docs_gap",
"bug",
"praise"
],
"type": "string",
"description": "What you are telling the host."
},
"text": {
"type": "string",
"description": "What you needed or saw; 1 to 2048 bytes after trim."
},
"context": {
"type": "object",
"description": "Optional, at most 1 KB: tool, error_code, free."
},
"tenant_key": {
"type": "string",
"description": "The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins."
}
},
"x-mcphost-validated": true,
"additionalProperties": false
}Return the documentation section an anchor points at: its text (at most 4 KB) and its first fenced example. Pass an anchor exactly as an error, hint or help entry printed it, e.g. a rate_limited error's `anchor`. Read-only, anonymous, no tenant data. An unknown anchor is anchor_not_found with the nearest anchors in did_you_mean.
| Argument | Type | Description |
|---|---|---|
| anchor* | string | A `<path>#<slug>` anchor, e.g. README.md#call-limits, as printed by an error's `anchor` field or a `host.help.search` hit. `<path>#top` and a bare `<path>` (e.g. docs/kinds/chain.md) both return that document's first section. |
| tenant_key | string | The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins. |
{
"type": "object",
"required": [
"anchor"
],
"properties": {
"anchor": {
"type": "string",
"description": "A `<path>#<slug>` anchor, e.g. README.md#call-limits, as printed by an error's `anchor` field or a `host.help.search` hit. `<path>#top` and a bare `<path>` (e.g. docs/kinds/chain.md) both return that document's first section."
},
"tenant_key": {
"type": "string",
"description": "The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins."
}
},
"x-mcphost-validated": true,
"additionalProperties": false
}Search this host's own documentation and tool descriptions. Returns up to k hits (default 3, response under 2 KB), each with a snippet, the nearest runnable example and an anchor. Read-only, anonymous, no tenant data -- call it with the error text or import line you are stuck on before reading any docs file.
| Argument | Type | Description |
|---|---|---|
| k | integer | How many hits to return (default 3). |
| q* | string | What you are stuck on: a tool name, an error code or message, an import line. |
| kind | string | Only search the page of this registered kind (docs/kinds/<kind>.md). |
| tenant_key | string | The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins. |
{
"type": "object",
"required": [
"q"
],
"properties": {
"k": {
"type": "integer",
"default": 3,
"maximum": 5,
"minimum": 1,
"description": "How many hits to return (default 3)."
},
"q": {
"type": "string",
"description": "What you are stuck on: a tool name, an error code or message, an import line."
},
"kind": {
"enum": [
"chain",
"echo",
"http",
"jq",
"js",
"python",
"wasm"
],
"type": "string",
"description": "Only search the page of this registered kind (docs/kinds/<kind>.md)."
},
"tenant_key": {
"type": "string",
"description": "The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins."
}
},
"x-mcphost-validated": true,
"additionalProperties": false
}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 -- this call alone never creates a tenant. Call this before host.tool_publish if you're not sure what a spec should look like. Unauthenticated callers get a worked example with no tenant data; any other host.*/billing.* call creates a tenant on first use, no signup required.
| Argument | Type | Description |
|---|---|---|
| kind | string | Which registered kind to return a worked example for, e.g. echo, http, python -- or a job-word alias (webhook, event, cron, ...) for its recipe. Omit to see every kind, alias and recipe name. |
| tenant_key | string | The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins. |
| retry_after_s | integer | Seconds a rate-limited signup said to wait; an error's next_call carries it back here. Informational, never required. |
{
"type": "object",
"required": [],
"properties": {
"kind": {
"type": "string",
"description": "Which registered kind to return a worked example for, e.g. echo, http, python -- or a job-word alias (webhook, event, cron, ...) for its recipe. Omit to see every kind, alias and recipe name."
},
"tenant_key": {
"type": "string",
"description": "The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins."
},
"retry_after_s": {
"type": "integer",
"description": "Seconds a rate-limited signup said to wait; an error's next_call carries it back here. Informational, never required."
}
},
"x-mcphost-validated": true,
"additionalProperties": false
}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.
| Argument | Type | Description |
|---|---|---|
| tenant_key | string | The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins. |
| handoff_token* | string | The handoff_token signup(handoff: true) returned. |
{
"type": "object",
"required": [
"handoff_token"
],
"properties": {
"tenant_key": {
"type": "string",
"description": "The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins."
},
"handoff_token": {
"type": "string",
"description": "The handoff_token signup(handoff: true) returned."
}
},
"x-mcphost-validated": true,
"additionalProperties": false
}Resume where you left off in one call (at most 4096 bytes): your tools with each one's last call status, unfinished runs, your newest notes, what changed on the host since your last call, and one suggested next_call. truncated names any section that was cut -- call that section's own tool (host.tool.list, host.runs.list, host.note.list, host.changelog) for the rest. Read-only. An unauthenticated caller gets the onboarding block and creates no tenant.
| Argument | Type | Description |
|---|---|---|
| tenant_key | string | The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins. |
{
"type": "object",
"required": [],
"properties": {
"tenant_key": {
"type": "string",
"description": "The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins."
}
},
"x-mcphost-validated": true,
"additionalProperties": false
}Read one key from this tenant's key-value state namespace. Returns found: false (not an error) if the key was never set.
| Argument | Type | Description |
|---|---|---|
| key* | string | Key to read from this tenant's key-value state namespace. |
| 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. |
| tenant_key | string | The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins. |
{
"type": "object",
"required": [
"key"
],
"properties": {
"key": {
"type": "string",
"description": "Key to read from this tenant's key-value state namespace."
},
"end_user": {
"type": [
"string",
"null"
],
"description": "\"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."
},
"tenant_key": {
"type": "string",
"description": "The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins."
}
},
"x-mcphost-validated": true,
"additionalProperties": false
}List keys (with their current values) in this tenant's key-value state namespace, optionally filtered by prefix.
| Argument | Type | Description |
|---|---|---|
| limit | integer | Max keys to return; default 100. |
| prefix | string | Only list keys starting with this prefix; default: all keys. |
| 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. |
| tenant_key | string | The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins. |
{
"type": "object",
"required": [],
"properties": {
"limit": {
"type": "integer",
"description": "Max keys to return; default 100."
},
"prefix": {
"type": "string",
"description": "Only list keys starting with this prefix; default: all keys."
},
"end_user": {
"type": [
"string",
"null"
],
"description": "\"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."
},
"tenant_key": {
"type": "string",
"description": "The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins."
}
},
"x-mcphost-validated": true,
"additionalProperties": false
}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.
| Argument | Type | Description |
|---|---|---|
| key* | string | Key to write in this tenant's key-value state namespace. |
| value* | any | Any JSON value to store under key. |
| dry_run | boolean | return the diff this call would make and commit nothing |
| 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. |
| tenant_key | string | The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins. |
{
"type": "object",
"required": [
"key",
"value"
],
"properties": {
"key": {
"type": "string",
"description": "Key to write in this tenant's key-value state namespace."
},
"value": {
"description": "Any JSON value to store under key."
},
"dry_run": {
"type": "boolean",
"description": "return the diff this call would make and commit nothing"
},
"end_user": {
"type": [
"string",
"null"
],
"description": "\"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."
},
"tenant_key": {
"type": "string",
"description": "The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins."
}
},
"x-mcphost-validated": true,
"additionalProperties": false
}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.
| Argument | Type | Description |
|---|---|---|
| args | object | Arguments to pass, validated against the tool's own args_schema. |
| name* | string | Local name of the tool to invoke. |
| 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. |
| budget | object | Lowers this call's budget below the plan default: any subset of max_child_calls, max_est_tokens, max_tool_latency_ms, max_wall_ms. A value above the plan's own ceiling is a validation error naming it; see host.runs.get's progress.budget. |
| dry_run | boolean | Ask instead of call: runs every admission check the real call runs, dispatches nothing, writes no call row, and returns {fits, units, remaining, refusal}; same as host.estimate. Default false. |
| version | integer | Pin the call to this version instead of whichever is current; see host.tool_history. An unknown version is an argument error. |
Publish a tool of a registered kind (e.g. python, http or echo; the kind argument's enum lists them all) under this tenant's namespace. Call host.quickstart(kind) first for a filled-in example spec and the full publish-to-call sequence. Python's sandbox API: import mcphost (mcphost.table, mcphost.state, mcphost.docs). 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.
| Argument | Type | Description |
|---|---|---|
| kind* | string | Which registered kind to publish under: one of this field's `enum` (host.quickstart with no kind lists every kind, alias and recipe). A job-word alias in the enum also resolves here -- webhook-style words for an inbound webhook, cron-style words for a timed run -- both resolve to kind http and the descriptor comes back with resolved_from naming the alias you asked for. Error contract per kind: chain (families: compose, tool_state; source_line: no); echo (families: none; source_line: no); http (families: upstream; source_line: no); jq (families: tool_code, tool_limit; source_line: no); js (families: tool_code, tool_limit, upstream, compose, tool_state; source_line: yes); python (families: tool_code, tool_limit, upstream, compose, tool_state; source_line: yes); wasm (families: tool_code, tool_limit; source_line: no). |
| name* | string | Local name for the new tool; must match ^[a-z][a-z0-9_]{1,40}$. |
| spec* | object | The kind-specific spec object; see host.quickstart(kind) for a filled-in example. For python's network field: "none" (every plan), "public" (requires the pro plan), "egress" (requires the pro plan) -- a tool's own code reaches this tenant's data with `import mcphost` (mcphost.table, mcphost.state, mcphost.docs, mcphost.lineage) even when network is "none". |
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>.
| Argument | Type | Description |
|---|---|---|
| name* | string | Local name of the tool to share. |
| tags | array | Catalog tags merged into the tool's existing ones (same rules as host.tool_publish). |
| group | string | Required when visibility is "group"; must already exist (host.group.create). |
| scopes | array | What the grantee may do: call, read_source, fork. Default ["call"] (["call","read_source"] with expose_spec: true). url shares allow only call. |
| tenant_key | string | The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins. |
| visibility* | string | "public" (needs a passing dry run of the current version), "unlisted", "group" or "url". |
Dry-run a published tool by name: verdict (pass/will_fail/unverifiable), writes rolled back (dry_run); see host.quickstart.
| Argument | Type | Description |
|---|---|---|
| args | object | Arguments to pass, same shape as a real call. Omit to run one example generated from the tool's args_schema; the response then carries example_args (what ran) and untyped (keys the schema gave no type for). |
| name* | string | Local name of the already-published tool to dry-run. |
| fixtures | object | Chain tools only: {"<step number or tool name>": <recorded result>}. A fixtured step executes nothing (no upstream call); later mappings resolve against it. host.runs.get(run_id, as_fixtures=true) exports a real run in this shape. |
| tenant_key | string | The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins. |
{
"type": "object",
"required": [
"name"
],
"properties": {
"args": {
"type": "object",
"description": "Arguments to pass, same shape as a real call. Omit to run one example generated from the tool's args_schema; the response then carries example_args (what ran) and untyped (keys the schema gave no type for)."
},
"name": {
"type": "string",
"description": "Local name of the already-published tool to dry-run."
},
"fixtures": {
"type": "object",
"description": "Chain tools only: {\"<step number or tool name>\": <recorded result>}. A fixtured step executes nothing (no upstream call); later mappings resolve against it. host.runs.get(run_id, as_fixtures=true) exports a real run in this shape."
},
"tenant_key": {
"type": "string",
"description": "The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins."
}
},
"x-deprecated": {
"sunset": "2026-12-31",
"replaced_by": "host.tool.test"
},
"x-mcphost-validated": true,
"additionalProperties": false
}Return the calling tenant's identity, including key_age_s and key_rotated_at for auditing credential hygiene.
| Argument | Type | Description |
|---|---|---|
| tenant_key | string | The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins. |
{
"type": "object",
"required": [],
"properties": {
"tenant_key": {
"type": "string",
"description": "The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins."
}
},
"x-mcphost-validated": true,
"additionalProperties": false
}Explicit signup, for a client that cannot keep a session across calls: create a tenant and receive a bearer key and namespace. Unauthenticated. Most clients never need this -- any other host.*/billing.* call from a fresh connection creates a tenant implicitly and returns its own /u/<secret>/mcp URL in the response's onboarding field. Recommended here: 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.
| Argument | Type | Description |
|---|---|---|
| name* | string | display name |
| source | string | Optional attribution tag for this signup (1-64 chars matching the pattern), e.g. "plugin", "www", "cli", "hn"; omit for none. Stored as the tenant's signup_source and counted in the signup-source funnel. Attribution only: whether a signup is real or synthetic is decided by the harness header and fleet IP, never by this value. "synthorg" is reserved for the discovery-chain harness. |
| handoff | boolean | Recommended: true to receive a handoff_token (redeem via host.redeem) instead of the raw key. Default false (raw key, unchanged). |
{
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string",
"description": "display name"
},
"source": {
"type": "string",
"pattern": "^[a-z0-9][a-z0-9._-]{0,63}$",
"description": "Optional attribution tag for this signup (1-64 chars matching the pattern), e.g. \"plugin\", \"www\", \"cli\", \"hn\"; omit for none. Stored as the tenant's signup_source and counted in the signup-source funnel. Attribution only: whether a signup is real or synthetic is decided by the harness header and fleet IP, never by this value. \"synthorg\" is reserved for the discovery-chain harness."
},
"handoff": {
"type": "boolean",
"description": "Recommended: true to receive a handoff_token (redeem via host.redeem) instead of the raw key. Default false (raw key, unchanged)."
}
},
"additionalProperties": false
}| tenant_key | string | The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins. |
{
"type": "object",
"required": [
"name"
],
"properties": {
"args": {
"type": "object",
"description": "Arguments to pass, validated against the tool's own args_schema."
},
"name": {
"type": "string",
"description": "Local name of the tool to invoke."
},
"async": {
"type": "boolean",
"description": "Run as a job instead of inline: returns {run_id, status} within ~50ms under the plan's job_max_s deadline; default false."
},
"budget": {
"type": "object",
"properties": {
"max_wall_ms": {
"type": "integer",
"maximum": 60000,
"minimum": 1,
"description": "Free-plan ceiling 60000; pro ceiling 600000. Maximum shown is the free floor -- see host.quickstart limits.plan.budget for your plan."
},
"max_est_tokens": {
"type": "integer",
"maximum": 200000,
"minimum": 1,
"description": "Free-plan ceiling 200000; pro ceiling 2000000. Maximum shown is the free floor -- see host.quickstart limits.plan.budget for your plan."
},
"max_child_calls": {
"type": "integer",
"maximum": 20,
"minimum": 1,
"description": "Free-plan ceiling 20; pro ceiling 50. Maximum shown is the free floor -- see host.quickstart limits.plan.budget for your plan."
},
"max_tool_latency_ms": {
"type": "integer",
"maximum": 30000,
"minimum": 1,
"description": "Free-plan ceiling 30000; pro ceiling 120000. Maximum shown is the free floor -- see host.quickstart limits.plan.budget for your plan."
}
},
"description": "Lowers this call's budget below the plan default: any subset of max_child_calls, max_est_tokens, max_tool_latency_ms, max_wall_ms. A value above the plan's own ceiling is a validation error naming it; see host.runs.get's progress.budget."
},
"dry_run": {
"type": "boolean",
"description": "Ask instead of call: runs every admission check the real call runs, dispatches nothing, writes no call row, and returns {fits, units, remaining, refusal}; same as host.estimate. Default false."
},
"version": {
"type": "integer",
"description": "Pin the call to this version instead of whichever is current; see host.tool_history. An unknown version is an argument error."
},
"tenant_key": {
"type": "string",
"description": "The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins."
}
},
"x-deprecated": {
"sunset": "2026-12-31",
"replaced_by": "host.tool.call"
},
"x-mcphost-validated": true,
"additionalProperties": false
}| tags | array | Catalog tags: at most 16, each 1-32 chars of a-z, 0-9 and '-', stored lower-case and deduped. |
| force | boolean | Publish a chain whose mapping can never resolve (verdict will_fail) anyway; the response's gates entry then carries forced: true. Default false. |
| 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 -- unaffected by any catalog. |
| dry_run | boolean | return the diff this call would make and commit nothing |
| tenant_key | string | The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins. |
| visibility | string | Who may find the tool (default private). unlisted: callable by full name and readable by host.catalog.get, never listed. public: listed in the catalog, and refused (untested_tool_cannot_be_public) unless the current version passes its dry run first. Use host.tool_share for group or url. |
{
"type": "object",
"allOf": [
{
"if": {
"required": [
"kind"
],
"properties": {
"kind": {
"const": "chain"
}
}
},
"then": {
"properties": {
"spec": {
"type": "object",
"required": [
"steps"
],
"properties": {
"ui": {
"type": "object",
"properties": {
"form": {
"type": "boolean"
},
"submit_label": {
"type": "string",
"maxLength": 40
},
"success_text": {
"type": "string",
"maxLength": 200
}
},
"description": "Optional presentation hints. `form: true` gives a url-shared tool a /f/ page where a person fills in the arguments and the submission lands in your inbox.",
"additionalProperties": false
},
"reads": {
"description": "tables this tool reads, recorded for lineage and blast-radius reports"
},
"steps": {},
"outputs": {
"description": "fields a caller can rely on in `result.payload`, optionally with a `$.a.b` path each (every kind)"
},
"description": {
"description": "the tool's description in `tools/list` (every kind)"
}
},
"additionalProperties": false
}
}
}
},
{
"if": {
"required": [
"kind"
],
"properties": {
"kind": {
"const": "echo"
}
}
},
"then": {
"properties": {
"spec": {
"type": "object",
"required": [
"schema"
],
"properties": {
"ui": {
"type": "object",
"properties": {
"form": {
"type": "boolean"
},
"submit_label": {
"type": "string",
"maxLength": 40
},
"success_text": {
"type": "string",
"maxLength": 200
}
},
"description": "Optional presentation hints. `form: true` gives a url-shared tool a /f/ page where a person fills in the arguments and the submission lands in your inbox.",
"additionalProperties": false
},
"reads": {
"description": "tables this tool reads, recorded for lineage and blast-radius reports"
},
"schema": {},
"outputs": {
"description": "fields a caller can rely on in `result.payload`, optionally with a `$.a.b` path each (every kind)"
},
"description": {
"description": "the tool's description in `tools/list` (every kind)"
}
},
"additionalProperties": false
}
}
}
},
{
"if": {
"required": [
"kind"
],
"properties": {
"kind": {
"const": "http"
}
}
},
"then": {
"properties": {
"spec": {
"type": "object",
"properties": {
"ui": {
"type": "object",
"properties": {
"form": {
"type": "boolean"
},
"submit_label": {
"type": "string",
"maxLength": 40
},
"success_text": {
"type": "string",
"maxLength": 200
}
},
"description": "Optional presentation hints. `form: true` gives a url-shared tool a /f/ page where a person fills in the arguments and the submission lands in your inbox.",
"additionalProperties": false
},
"url": {},
"body": {},
"query": {},
"reads": {
"description": "tables this tool reads, recorded for lineage and blast-radius reports"
},
"method": {},
"headers": {},
"outputs": {
"description": "fields a caller can rely on in `result.payload`, optionally with a `$.a.b` path each (every kind)"
},
"response": {},
"upstream": {},
"timeout_s": {},
"args_schema": {},
"description": {
"description": "the tool's description in `tools/list` (every kind)"
},
"upstream_provider": {}
},
"additionalProperties": false
}
}
}
},
{
"if": {
"required": [
"kind"
],
"properties": {
"kind": {
"const": "jq"
}
}
},
"then": {
"properties": {
"spec": {
"type": "object",
"required": [
"program"
],
"properties": {
"ui": {
"type": "object",
"properties": {
"form": {
"type": "boolean"
},
"submit_label": {
"type": "string",
"maxLength": 40
},
"success_text": {
"type": "string",
"maxLength": 200
}
},
"description": "Optional presentation hints. `form: true` gives a url-shared tool a /f/ page where a person fills in the arguments and the submission lands in your inbox.",
"additionalProperties": false
},
"reads": {
"description": "tables this tool reads, recorded for lineage and blast-radius reports"
},
"outputs": {
"description": "fields a caller can rely on in `result.payload`, optionally with a `$.a.b` path each (every kind)"
},
"program": {},
"timeout_s": {},
"args_schema": {},
"description": {
"description": "the tool's description in `tools/list` (every kind)"
},
"max_output_bytes": {}
},
"additionalProperties": false
}
}
}
},
{
"if": {
"required": [
"kind"
],
"properties": {
"kind": {
"const": "js"
}
}
},
"then": {
"properties": {
"spec": {
"type": "object",
"required": [
"source"
],
"properties": {
"ui": {
"type": "object",
"properties": {
"form": {
"type": "boolean"
},
"submit_label": {
"type": "string",
"maxLength": 40
},
"success_text": {
"type": "string",
"maxLength": 200
}
},
"description": "Optional presentation hints. `form: true` gives a url-shared tool a /f/ page where a person fills in the arguments and the submission lands in your inbox.",
"additionalProperties": false
},
"env": {
"description": "a map of name to string value; names must match ^[A-Z][A-Z0-9_]{0,63}$"
},
"reads": {
"description": "tables this tool reads, recorded for lineage and blast-radius reports"
},
"source": {
"description": "a string"
},
"network": {
"description": "\"none\" (every plan), \"public\" (requires the pro plan), \"egress\" (requires the pro plan) -- a tool's own code reaches this tenant's data with `import mcphost` (mcphost.table, mcphost.state, mcphost.docs, mcphost.lineage) even when network is \"none\""
},
"outputs": {
"description": "a list of field names or an object mapping field names to path strings"
},
"secrets": {
"description": "a list of strings"
},
"memory_mb": {
"description": "a positive integer number of megabytes"
},
"timeout_s": {
"description": "a positive integer number of seconds"
},
"args_schema": {
"description": "a JSON Schema object"
},
"description": {
"description": "a string"
}
},
"additionalProperties": false
}
}
}
},
{
"if": {
"required": [
"kind"
],
"properties": {
"kind": {
"const": "python"
}
}
},
"then": {
"properties": {
"spec": {
"type": "object",
"required": [
"source"
],
"properties": {
"ui": {
"type": "object",
"properties": {
"form": {
"type": "boolean"
},
"submit_label": {
"type": "string",
"maxLength": 40
},
"success_text": {
"type": "string",
"maxLength": 200
}
},
"description": "Optional presentation hints. `form: true` gives a url-shared tool a /f/ page where a person fills in the arguments and the submission lands in your inbox.",
"additionalProperties": false
},
"env": {
"description": "a map of name to string value; names must match ^[A-Z][A-Z0-9_]{0,63}$"
},
"reads": {
"description": "tables this tool reads, recorded for lineage and blast-radius reports"
},
"source": {
"description": "a string"
},
"network": {
"description": "\"none\" (every plan), \"public\" (requires the pro plan), \"egress\" (requires the pro plan) -- a tool's own code reaches this tenant's data with `import mcphost` (mcphost.table, mcphost.state, mcphost.docs, mcphost.lineage) even when network is \"none\""
},
"outputs": {
"description": "a list of field names or an object mapping field names to path strings"
},
"secrets": {
"description": "a list of strings"
},
"memory_mb": {
"description": "a positive integer number of megabytes"
},
"timeout_s": {
"description": "a positive integer number of seconds"
},
"args_schema": {
"description": "a JSON Schema object"
},
"description": {
"description": "a string"
},
"requirements": {
"description": "a list of strings"
}
},
"additionalProperties": false
}
}
}
},
{
"if": {
"required": [
"kind"
],
"properties": {
"kind": {
"const": "wasm"
}
}
},
"then": {
"properties": {
"spec": {
"type": "object",
"required": [
"component"
],
"properties": {
"ui": {
"type": "object",
"properties": {
"form": {
"type": "boolean"
},
"submit_label": {
"type": "string",
"maxLength": 40
},
"success_text": {
"type": "string",
"maxLength": 200
}
},
"description": "Optional presentation hints. `form: true` gives a url-shared tool a /f/ page where a person fills in the arguments and the submission lands in your inbox.",
"additionalProperties": false
},
"reads": {
"description": "tables this tool reads, recorded for lineage and blast-radius reports"
},
"outputs": {
"description": "fields a caller can rely on in `result.payload`, optionally with a `$.a.b` path each (every kind)"
},
"component": {},
"memory_mb": {},
"timeout_s": {},
"args_schema": {},
"description": {
"description": "the tool's description in `tools/list` (every kind)"
}
},
"additionalProperties": false
}
}
}
}
],
"required": [
"name",
"kind",
"spec"
],
"properties": {
"kind": {
"enum": [
"chain",
"echo",
"http",
"jq",
"js",
"python",
"wasm",
"event",
"events",
"webhook",
"webhooks",
"inbound",
"trigger",
"inbox",
"cron",
"schedule",
"scheduled",
"doc",
"docs",
"document",
"documents",
"message",
"messages",
"msg",
"database",
"db",
"table",
"tables",
"csv",
"sql",
"schedules",
"uptime",
"probe",
"probes",
"memory",
"memories"
],
"type": "string",
"description": "Which registered kind to publish under: one of this field's `enum` (host.quickstart with no kind lists every kind, alias and recipe). A job-word alias in the enum also resolves here -- webhook-style words for an inbound webhook, cron-style words for a timed run -- both resolve to kind http and the descriptor comes back with resolved_from naming the alias you asked for. Error contract per kind: chain (families: compose, tool_state; source_line: no); echo (families: none; source_line: no); http (families: upstream; source_line: no); jq (families: tool_code, tool_limit; source_line: no); js (families: tool_code, tool_limit, upstream, compose, tool_state; source_line: yes); python (families: tool_code, tool_limit, upstream, compose, tool_state; source_line: yes); wasm (families: tool_code, tool_limit; source_line: no)."
},
"name": {
"type": "string",
"pattern": "^[a-z][a-z0-9_]{1,40}$",
"description": "Local name for the new tool; must match ^[a-z][a-z0-9_]{1,40}$."
},
"spec": {
"type": "object",
"description": "The kind-specific spec object; see host.quickstart(kind) for a filled-in example. For python's network field: \"none\" (every plan), \"public\" (requires the pro plan), \"egress\" (requires the pro plan) -- a tool's own code reaches this tenant's data with `import mcphost` (mcphost.table, mcphost.state, mcphost.docs, mcphost.lineage) even when network is \"none\"."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Catalog tags: at most 16, each 1-32 chars of a-z, 0-9 and '-', stored lower-case and deduped."
},
"force": {
"type": "boolean",
"description": "Publish a chain whose mapping can never resolve (verdict will_fail) anyway; the response's gates entry then carries forced: true. Default false."
},
"scopes": {
"type": "array",
"items": {
"type": "string"
},
"description": "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 -- unaffected by any catalog."
},
"dry_run": {
"type": "boolean",
"description": "return the diff this call would make and commit nothing"
},
"tenant_key": {
"type": "string",
"description": "The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins."
},
"visibility": {
"enum": [
"private",
"unlisted",
"public"
],
"type": "string",
"description": "Who may find the tool (default private). unlisted: callable by full name and readable by host.catalog.get, never listed. public: listed in the catalog, and refused (untested_tool_cannot_be_public) unless the current version passes its dry run first. Use host.tool_share for group or url."
}
},
"x-deprecated": {
"sunset": "2026-12-31",
"replaced_by": "host.tool.publish"
},
"additionalProperties": false
}| 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. |
| rate_per_hour_per_caller | integer | Optional cap (1..10000) on calls per hour from any one grantee. |
{
"type": "object",
"required": [
"name",
"visibility"
],
"properties": {
"name": {
"type": "string",
"description": "Local name of the tool to share."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Catalog tags merged into the tool's existing ones (same rules as host.tool_publish)."
},
"group": {
"type": "string",
"description": "Required when visibility is \"group\"; must already exist (host.group.create)."
},
"scopes": {
"type": "array",
"items": {
"enum": [
"call",
"read_source",
"fork"
],
"type": "string"
},
"description": "What the grantee may do: call, read_source, fork. Default [\"call\"] ([\"call\",\"read_source\"] with expose_spec: true). url shares allow only call."
},
"tenant_key": {
"type": "string",
"description": "The key `signup` returned. Optional on the connection that ran signup (or host.redeem): that connection is already bound to the tenant it created, so later calls on it need no tenant_key. On a connection with no Authorization: Bearer header and no prior signup, omitting it implicitly signs that connection up as a brand-new tenant and runs this call as it -- see host.whoami's source field. When both a header and this argument are present, the header wins."
},
"visibility": {
"enum": [
"unlisted",
"group",
"public",
"url"
],
"type": "string",
"description": "\"public\" (needs a passing dry run of the current version), \"unlisted\", \"group\" or \"url\"."
},
"description": {
"type": "string",
"description": "Catalog-facing blurb; shown by host.catalog.search/get."
},
"expose_spec": {
"type": "boolean",
"description": "Default false. When true, any tenant this tool is shared with may call host.tool_spec_shared to read its (redacted) spec."
},
"rate_per_hour_per_caller": {
"type": "integer",
"description": "Optional cap (1..10000) on calls per hour from any one grantee."
}
},
"x-deprecated": {
"sunset": "2026-12-31",
"replaced_by": "host.tool.share"
},
"x-mcphost-validated": true,
"additionalProperties": false
}