{"serverId":"mcp-registry/dev.mcphost/mcphost","tools":[{"name":"billing.plans","fixed":{"name":"billing_plans","description":"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.","inputSchema":{"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}},"changes":[{"kind":"name","detail":"Renamed \"billing.plans\" → \"billing_plans\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":226,"tokensAfter":226},{"name":"host.errors","fixed":{"name":"host_errors","description":"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.","inputSchema":{"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}},"changes":[{"kind":"name","detail":"Renamed \"host.errors\" → \"host_errors\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":312,"tokensAfter":312},{"name":"host.feedback.list","fixed":{"name":"host_feedback_list","description":"List your own feedback (newest first, status received). Anonymous callers get [].","inputSchema":{"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},"annotations":{"readOnlyHint":true}},"changes":[{"kind":"name","detail":"Renamed \"host.feedback.list\" → \"host_feedback_list\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true},{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":230,"tokensAfter":230},{"name":"host.feedback.send","fixed":{"name":"host_feedback_send","description":"Tell the host's humans what you needed: kind, up to 2048 bytes of text, optional context. Works before signup. Returns feedback_id.","inputSchema":{"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","minLength":1,"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},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false}},"changes":[{"kind":"name","detail":"Renamed \"host.feedback.send\" → \"host_feedback_send\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true},{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":319,"tokensAfter":319},{"name":"host.help.get","fixed":{"name":"host_help_get","description":"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.","inputSchema":{"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},"annotations":{"readOnlyHint":true}},"changes":[{"kind":"name","detail":"Renamed \"host.help.get\" → \"host_help_get\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true},{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":354,"tokensAfter":354},{"name":"host.help.search","fixed":{"name":"host_help_search","description":"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.","inputSchema":{"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},"annotations":{"readOnlyHint":true}},"changes":[{"kind":"name","detail":"Renamed \"host.help.search\" → \"host_help_search\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true},{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":382,"tokensAfter":382},{"name":"host.quickstart","fixed":{"name":"host_quickstart","description":"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 u","inputSchema":{"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}},"changes":[{"kind":"name","detail":"Renamed \"host.quickstart\" → \"host_quickstart\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":436,"tokensAfter":436},{"name":"host.redeem","fixed":{"name":"host_redeem","description":"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.","inputSchema":{"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}},"changes":[{"kind":"name","detail":"Renamed \"host.redeem\" → \"host_redeem\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":287,"tokensAfter":287},{"name":"host.resume","fixed":{"name":"host_resume","description":"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.","inputSchema":{"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}},"changes":[{"kind":"name","detail":"Renamed \"host.resume\" → \"host_resume\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":310,"tokensAfter":310},{"name":"host.state.get","fixed":{"name":"host_state_get","description":"Read one key from this tenant's key-value state namespace. Returns found: false (not an error) if the key was never set.","inputSchema":{"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},"annotations":{"readOnlyHint":true}},"changes":[{"kind":"name","detail":"Renamed \"host.state.get\" → \"host_state_get\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true},{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":312,"tokensAfter":312},{"name":"host.state.list","fixed":{"name":"host_state_list","description":"List keys (with their current values) in this tenant's key-value state namespace, optionally filtered by prefix.","inputSchema":{"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},"annotations":{"readOnlyHint":true}},"changes":[{"kind":"name","detail":"Renamed \"host.state.list\" → \"host_state_list\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true},{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":332,"tokensAfter":332},{"name":"host.state.set","fixed":{"name":"host_state_set","description":"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.","inputSchema":{"type":"object","required":["key","value"],"properties":{"key":{"type":"string","description":"Key to write in this tenant's key-value state namespace."},"value":{"type":["string","number","integer","boolean","array","object","null"],"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},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true}},"changes":[{"kind":"name","detail":"Renamed \"host.state.set\" → \"host_state_set\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true},{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":396,"tokensAfter":396},{"name":"host.tool_call","fixed":{"name":"host_tool_call","description":"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 versio","inputSchema":{"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}},"changes":[{"kind":"name","detail":"Renamed \"host.tool_call\" → \"host_tool_call\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":874,"tokensAfter":874},{"name":"host.tool_publish","fixed":{"name":"host_tool_publish","description":"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.","inputSchema":{"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},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false}},"changes":[{"kind":"name","detail":"Renamed \"host.tool_publish\" → \"host_tool_publish\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true},{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":3189,"tokensAfter":3189},{"name":"host.tool_share","fixed":{"name":"host_tool_share","description":"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>.","inputSchema":{"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"},"minItems":1,"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","maximum":10000,"minimum":1,"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}},"changes":[{"kind":"name","detail":"Renamed \"host.tool_share\" → \"host_tool_share\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":636,"tokensAfter":636},{"name":"host.tool_test","fixed":{"name":"host_tool_test","description":"Dry-run a published tool by name: verdict (pass/will_fail/unverifiable), writes rolled back (dry_run); see host.quickstart.","inputSchema":{"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}},"changes":[{"kind":"name","detail":"Renamed \"host.tool_test\" → \"host_tool_test\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":413,"tokensAfter":413},{"name":"host.whoami","fixed":{"name":"host_whoami","description":"Return the calling tenant's identity, including key_age_s and key_rotated_at for auditing credential hygiene.","inputSchema":{"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}},"changes":[{"kind":"name","detail":"Renamed \"host.whoami\" → \"host_whoami\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":215,"tokensAfter":215}],"toolsChanged":17,"tokensSaved":0,"todo":[],"note":"Deterministic fixes. Changes marked verify need a human look before shipping (renames, inferred annotations, inferred types, removed text). Parameter descriptions in `todo` need to be written by someone who knows the API."}