Source: mcp_surface.md
Generated automatically from the published contract sources.
Source path: mcp_surface.md.
Contract text
The MCP Surface — Contract
Purpose
This file is the contract for the Turn Zero Cloud MCP server's surface: how a customer's AI tool connects and authenticates, which kinds of capability surface as tools, resources, and prompts, and what the launch surface is. It settles the open point the AI tool interface PRD's open questions and the management API PRD's open questions both nominated, on the launch definition's own rule — the scenarios drive, the API guarantees (CHI-L0-02). It states the surface of a *client*: every capability here is the one API's (API-L0-01), reached through the MCP server acting as the connected identity (API-L0-02), and nothing here is MCP-only.
The launch surface's enumeration has one home: the catalog at schemas/mcp_surface.json beside this document — capability by capability, each with its form and its authority tier — held coherent by a test in the platform's suite. This document states the rules the catalog obeys and deliberately repeats none of its rows.
What this document does not cover: the API's own resource contract and versioning (management_api_contract.md); the pending action's mechanics (API-L0-07 owns them; this surface only reaches them); and the super-admin's capability inventory (MAPI-09's grant rows). Nor does it cover the launch skill set, whose rows are the contract's in schemas/skills.json under API-L0-10's derivation rule.
Requirements are numbered MCP-nn.
The server and the connection
MCP-01 (decided): The Turn Zero Cloud MCP server is one remote server, hosted and operated by Turn Zero Cloud, reached over the Model Context Protocol's streamable HTTP transport at a URL the customer adds to their tool. It needs no local install, no sidecar, and nothing on the customer's machine beyond their own AI tool.
The server declares itself turnzero-cloud. That one name is its protocol identity and the name every install stanza Turn Zero Cloud publishes uses. A client prefixes a server's tools with the name it is bound under, so the name is also the word a customer's assistant reads on every action it takes here. It spells the product's approved public name, Turn Zero Cloud (azure:AZD-08), rather than the family, the host, or the code name the workspace writes internally, Turn Zero Cloud being the actor a management action reaches (Q-238). The spelling stays inside lowercase letters, digits, and hyphens. A client composes a tool name from the bound name, and the tool-name grammars in use do not all admit a dot, so a name carrying the domain's punctuation is not addressable everywhere the product is installed.
What a customer's own tool stores as the label for the connection is that customer's to choose and no requirement's to impose. This statement fixes what Turn Zero Cloud declares and publishes, which is the whole of what Turn Zero Cloud controls. The published name is a stable identifier on MCP-08's terms rather than a spelling free to drift. A later change to it is therefore a versioned contract change carrying every published stanza with it, never a quiet edit.
Which protocol revision the server speaks, and how it negotiates with older clients, is versioned call configuration beneath this contract, not a statement in it. The transport's JSON answers declare charset=utf-8 in their Content-Type, so a client that applies a default charset to a bare media type decodes the server's UTF-8 bytes as written.
MCP-02 (decided; conforms: ACC-04): The authentication binding is OAuth 2.1 authorization code with PKCE, discoverable by the standard authorization-server metadata, with dynamic client registration so a customer's tool connects without a preconfigured client identity. The authorization moment is the sign-in page (WEB-L0-12): the builder realm's own surface (ACS-L0-01), served on the control plane's origin (ACS-L0-04), and the one browser interruption of CHI-L0-03. There a first sign-in creates the account where the builder realm's creation policy admits it (ACB-L0-77; ACS-L0-07) and is refused by name where it does not. The token the flow issues is the builder realm's session (ACS-L0-11), the credential the authority tiers bind to (API-L0-06). The connected session acts as that identity and nothing else, and disconnecting or signing out revokes the session rather than orphaning it.
A minted token (API-L0-05) connects the same server as its bearer with no browser moment, the sign-in flow never run for it. The connected session then acts as the token's own bounded identity under the same challenge. The platform credential connects nothing here and draws the standing challenge (SEC-L0-07).
Deployment configuration fixes one canonical authorization-server origin through OAUTH_ORIGIN and one protected-service resource identifier; neither is inferred from a request Host header or widened by an alias. The deployment template sets the origin from its trusted public API origin. An explicitly configured origin is validated before database migration or provisioning; an empty or malformed value refuses startup. Startup also refuses a missing OAUTH_ORIGIN when PGHOST has a nonempty value. Without OAUTH_ORIGIN or that deployment setting, a local executable selects the loopback origin from its actual bound listener, including an assigned ephemeral port. An application factory with no listener defaults to http://127\.0\.0\.1:8080 unless its caller supplies the trusted origin.
Changing the origin makes prior-origin builder OAuth access and refresh grants ineligible and requires new OAuth authorization; other credential kinds keep their own validity rules, and an existing valid browser session may authorize the new grant without another human sign-in. The identifier advertised by protected-resource metadata names the existing Turn Zero Cloud protected service: the MCP endpoint and the API, documentation and data-plane surfaces already admitting this bearer under ACS-L0-11; it does not grant access to another service. Protected-resource metadata advertises the canonical resource and authorization-server issuer; authorization-server metadata repeats that issuer and its canonical endpoints. Both publish the supported OAuth scopes. Generated callback and return URLs whose destination is the control plane use its configured origin; the client's redirect remains its exact registered URI.
Authorization, code exchange, access-token records and refresh-family records preserve the resource, issuer, client and granted scopes. A supplied resource must match exactly; omission selects the configured service at authorization and retains the recorded resource at exchange or renewal, never a wildcard. Scope omission selects the documented default at authorization and retains the grant thereafter; an unknown scope or attempted broadening refuses. The scope names and default are versioned call configuration. OAuth scopes are separate from authority tiers and application grants and cannot create either. The shared credential resolver rejects unbound or foreign OAuth access credentials before dispatch; a protected call with a valid OAuth credential lacking its required scope answers insufficient_scope with HTTP 403.
Every MCP request the plane admits, presenting no credential or one resolving to no account, initialize included, answers 401 and a WWW-Authenticate challenge naming the protected-resource metadata and applicable scopes. An invalid presented credential also carries invalid_token and its error description; missing credentials carry none; the wire's anonymous rows stay readable (MAPI-11). The challenge's JSON body states in its detail the same case the header distinguishes: a connection that presented no credential, which reconnects with sign-in or starts the OAuth flow, or a presented credential that resolved to no account, which signs in again. Neither adds OAuth error information to the header, and the wire route's refusal states the same two texts. Every body the server's 401 challenge answers carries help, the address of its refusal's row on the refusals page (MAPI-10): authentication_required, end_user_credential_not_admitted, transfer_grant_not_admitted, secret_grant_not_admitted, egress_key_not_admitted, and app_credential_not_admitted. Browser-only approval and all other credential-kind boundaries remain MAPI-03 and API-L0-07's.
This paragraph qualifies the paragraph above for a presented bearer of a grant's form that resolves to no credential. The challenge's body and the wire route's refusal state a third text in that case: the platform serves no grant of that value. The text names both ways to a fresh grant: the tool call whose answer carried it, made again, and the application's own request for one, made again (MAPI-03). The name, the status, and the header stand as the paragraph above states them for a presented credential.
Registration serves public clients with token_endpoint_auth_method=none. Authorization accepts only an exact registered HTTPS redirect or HTTP loopback redirect, with no URI credentials or fragment; code exchange requires S256 PKCE. An additive migration retains old rows as explicitly unbound. It may backfill only where recorded issuance provenance proves the binding, and production cutover otherwise requires the developer-approved one-time reauthentication disposition; an unbound row never means all audiences.
This paragraph and the six after it qualify four paragraphs above for one client: the first paragraph's token, the fourth's published scopes, the fifth's default scope and its separation of scopes from grants, and the eighth's exact redirect match. The plane registers one first-party public client of its own, turnzero-blueprint, the command of Turn Zero Blueprint, in its source and in schemas/mcp_surface.json's oauth member, never through dynamic registration. Its redirect is http://127.0.0.1/callback or http://[::1]/callback at any port the request names (RFC 8252). Its one scope, and its default, is issues, which no other client is given and the metadata does not advertise.
The issues scope gives no grant by itself: the token is minted on the person's confirmation, on MAPI-14's terms. The oauth member holds the client, its redirects, its scope, the request code, the request's and the exchange's paths, and the exchange's members as call configuration, and a test holds it to the server.
The client's authorization request is the accounts service's /oauth/authorize. It carries S256 PKCE, a state, a label in mint_token's form (MAPI-14), and optionally a space and a component in the issue contract's form. Each is refused by name before any sign-in where it is missing or malformed. The request reads no issue service. After the sign-in moment, or at once where the browser holds a site session signed in within WEB-L0-16's freshness window, it holds the confirmation and hands the browser to the confirm page. The management service serves that page under /approve/blueprint/. A request the browser marks as a prefetch holds nothing, nor does a completion of its sign-in the browser marks so (WEB-L0-24).
The confirm page names the account by its sign-in address, or by its identifier where it holds none. Beside it stands a control that signs the browser out and restarts the request at the sign-in. The page shows the request code: the first eight hexadecimal digits, in upper case, of the SHA-256 digest the code_challenge carries, which the client prints beside the address it opens. The page and its posts answer only the browser whose request held them, and a second request in that browser leaves the first open.
The page lists the spaces the account holds, the named space alone where the request names one, and otherwise offers to create one. It names the label, the level, owner, and the component, and says where confirming replaces a token of that label. Confirming mints a single-use code alone, and a refusal or a cancel on the page returns its name and the state to the client's redirect. Two refusals return nothing to the client: the admission window's (PLD-L0-67), answered before the ticket is read, which the client reads by its own timeout, and a choice the page does not offer, which leaves the ticket standing for another choice. No other site may frame the confirm page, or the sign-in page the request reaches.
The code exchange is the management service's /approve/blueprint/token, beside the page, and the token endpoint refuses that client's exchange by name, invalid_grant. The exchange reads the authorizing generation again, then the space's owner and the licence in mint_token's order. Where the confirmation chose a new space, it reads the licence and creates the space under create_issue_space's rules, ahead of the mint. It mints one issues token at the owner level for the space, issued to that client (MAPI-14). The answer carries the value once, with its space, level, label, and identity, the plane's origin, and the tokens it revoked, under Cache-Control: no-store. It carries no refresh token, and the exchange opens no session and no connection (MCP-10).
An account without the blueprint profile is refused blueprint_required on the page and at the exchange (ACB-L0-82), and a space it does not hold space_not_owned. Where the management service serves no issue service, both refuse not_yet_provisioned. A code never exchanged expires having created, minted, and revoked nothing. A mint that fails after the exchange created a space leaves that space with no token, and the refusal names the space.
The exchange's token has no expiry date. It ends when a later exchange under its label replaces it, when revoke_token revokes it, when it goes 30 days unused (PLD-L0-67), at sign out everywhere, at a passkey change's revert (ACS-L0-10), and at the account's suspension (API-L0-12). Sign out everywhere ends it before the generation's bump and again after the refresh rows are deleted, and a revert before the revert commits and again after its refresh rows, so an exchange that raced the act is caught. Each act's answer counts the tokens it ended as exchange_tokens_revoked, and a reinstatement restores none of them.
After its mint the exchange reads the generation again from the store; where it moved, the exchange revokes the token it minted and is refused as a sign-in ended after the confirmation is, naming a space it created, and answers no value. Where that revocation fails, the token stands unanswered and held by no one until the 30-day sweep or the next sign out everywhere ends it.
The three forms
MCP-03 (decided): Every management action callable by an AI client is a tool corresponding to one API capability. Its authority tier — observe, reversible or destructive — remains explicit in the authoritative catalog and enforced by the management API (API-L0-06); a host annotation neither grants authority nor supplies approval. Each tool advertises truthful standard MCP annotations derived from its action’s catalog metadata, under MCP-11. Served readable context retains its addressable resources, and skills retain their prompts. The same content is also available through the observe tools CTX-07 defines, so resource and prompt support enriches a client without being required for discovery. These protocol forms derive from the same API and content sources; none owns an independent capability or copy of the content.
MCP-04 (decided): Tools alone are the floor: every launch scenario’s management steps complete through tool calls and the browser moments CHI-L0-03 states, with no management step that requires resources or prompts. The signed-in site (WEB-L0-15) is a view of the same acts, required by none. Deployment starts from the externally prepared and uploaded artifact CHI-L0-01 requires; deploy receives its account-owned storage reference and hash, without requiring a filesystem or byte upload in the MCP client. A client supporting only tools loses the slash-command surface and the preloadable context, never a capability — discovery’s catalog and complete readable content arrive through list_context, read_context and read_documentation there, and the served documents remain readable outside the protocol (API-L0-09's other two forms). This is what makes "any AI tool's output is a first-class citizen" true of the tool's *client features* too.
MCP-05 (decided): Discovery is the protocol's own listings — tools, resources, and prompts, each entry carrying a description a newcomer can act on — plus the overview. The overview, available as both a resource and a read_context result, answers "what can the platform do and where do I start" in one read. Every listing description derives from the same one source as the human documentation and the authoring bundle (API-L0-09), so what the tool shows, the docs say, and the bundle teaches cannot disagree. The rule extends to library catalog rows: a catalog row's listing description derives from the package-owned selection summary the catalog quotes (FTR-L0-57's section), the same one-source discipline over the library's source.
A served string names the product by an approved public name — Turn Zero Cloud, or the platform; Turn Zero Blueprint for the kit (azure:AZD-08) — and never by a code name or an internal product name. This is the product-name half of the public-name rule the documentation suite and the served-surface suite share. A served string is every tool description and argument description, every resource description, every prompt description and prompt text, and every text the server composes — the overview, a refusal's detail, an action's response detail. It is also every field of the enumeration files the bundle and the service_contracts resource carry, the bundle's guides, and the selection summaries the catalog quotes.
The requirements documents the bundle packages verbatim are the source itself (CTX-02), and CTX-08 holds that source to the same product-name half. A clearly labeled reproduction of an indexed contract, enumeration, or guide in the generated human reference therefore carries the approved names because its source does. A reproduction preserves its source's identifiers. The reference distinguishes resolvable links within the published index from citations to sources that are not published there, without publishing additional sources merely to satisfy a citation.
No listing description carries a requirement or decision identifier: a tool's, an argument's, a resource's, a prompt's, or a catalog entry's summary list_context answers. No line of the overview carries one either. A catalog row names the statements its descriptions follow in its scenario and owners members (MCP-08), which reach a client in the whole-file reads alone. MCP-06's rendering of a skill's lead, the prompt description, keeps the identifiers of the row's must items and no other. A refusal's detail and an action's response detail may close on a rule code, the identifier of the rule behind the answer. The instructions say once what a rule code is, with one example, ahead of the origin line, and the overview with none. The served-surface suite holds the served strings to the product-name half, and the listing descriptions and the overview to this paragraph.
Beside the overview, the server's instructions name, on every connection, the estate's configured origin (MCP-02), never one read from a request, and what a script reaches there: the management actions at /api/v1/actions/<action>, the storage routes, and the library's anonymous reads. Before the line naming the origin, which stays their last, the instructions say that a management action's refusal may carry help, the address of its row on the refusals page at <origin>/cloud/reference/refusals/, where every refusal's name and remedy are explained. That origin is the public origin help is composed on, so an agent meeting a refusal name no help rides with, in a detail, a data plane's body, or a page, still learns where the name is explained.
The overview, as a resource and as a read_context result, carries the same origin line.
Each tool's summary opens with one sentence of at most 200 characters saying what the tool is for, so a host that cuts a description short still shows what the tool is for.
This paragraph qualifies the fifth paragraph's instructions. On a connection that lists read_status, they also say, ahead of the refusals page's sentence, that an answer to an act that is not the platform's own says nothing about whether the act was made (MAPI-04). They name a gateway's error page and a closed connection as such answers, read_status with wait_seconds as the read to make first, and what in it shows the act started. They say to repeat the act only where that read shows it did not start, never where it cannot tell, and send a schedule run to read_schedules and its same request_id. The text names no identifier, and the overview carries it under the same condition.
This paragraph qualifies the fifth paragraph's instructions too. On a connection that lists read_context, they open by saying what the platform is for and by naming the overview as the first read, with the call that reads it. The opening names no identifier.
This paragraph qualifies the fifth paragraph's instructions too. On a connection that lists deploy, they say, after the eighth paragraph's sentences where those stand and ahead of the refusals page's sentence, that a command this platform answers needs Node.js 24 or later, the version PLD-L0-82 holds every stated number to. The sentence names no identifier, and the overview does not carry it.
MCP-13: Each text the server lists is held to what a client shows of it: a tool's summary, a tool's served input schema, and the server's instructions; a row's reference holds what its summary cannot. A caller then reads the whole of what the listing says. A summary and the instructions, each counted in UTF-16 units, and a served input schema, counted in bytes of compact JSON, run to at most the figure the catalog's listing_bounds member holds for each, a row that member holds by name excepted. The instructions are measured at their longest composition on each estate's origin. That member of schemas/mcp_surface.json is the one home of the three figures, and family:Q-273 holds what each client shows of a listing, the versions it was read at, and the margins.
A summary holds what a caller cannot learn elsewhere in time. It says what the tool is for, in its opening sentence (MCP-05). It says when to call the tool and not a neighbour, and the acts before and after it where the call is one step of several. It says what the call changes, provisions, costs, or cannot undo, and the approval it waits for. It states a rule on how to call the tool that no single argument owns, and a value in the answer whose meaning the answer does not carry itself. Where the row carries a reference, its last sentence says where the rest is. A sentence another statement places in a description stays in it.
The rest of a row's text stands in the row's reference member, which the listing does not serve. The action's generated reference page renders it after the summary. A row that carries one closes its summary by naming that page's path, and by saying that read_documentation reads the page and the platform's origin serves it. A row's owners names the statements its reference follows too, and a reference carries no identifier, as a summary carries none.
An argument's description keeps what the argument means, the values it admits, and the refusal a wrong value draws. A row whose served input schema cannot meet its bound with those in the listing is named in listing_bounds with its reason and the size it is held at, and is cut no further. The suite refuses a named row that fits the bound, a named row over its held size, and an unnamed row over the bound.
The served-surface suite holds each bound against the listing a connection receives, and each closing sentence against its page's own path.
MCP-06 (decided): Each skill surfaces as one prompt, invocable as a slash command in clients that support them, and the prompt set is derived from what Turn Zero Cloud offers (API-L0-10). The server enumerates it from the same source as everything else, and no hand-kept prompt list exists to drift. A tools-only client obtains that same skill text through read_context, with the same implementation and credential-grant filtering (CTX-07); the tool path does not author a second recipe.
Each skill row carries a must member, an array of imperative sentences stating what the implementer must do, each ending with the identifier of the statement that owns the rule. The served skill text carries every item on exactly one of its pages under its list number; the human reference page places the whole list ahead of the whole summary. The prompt's description carries the summary's first sentence and then the whole list, and the prompt's text is the first page. The catalog entry for a skill and the overview's line carry no must item: each names the skill, its read_context identifier skill:<name>, and a one-line purpose, the summary's first sentence with each parenthetical holding an identifier dropped whole. No rendering restates a rule the list omits or reorders the list; each driven action is one line, its name, its tier, and its tool summary's opening sentence.
A skill row may carry a short_path member: a lead, a few steps for the common case, each naming by number the items it follows, and the items applying only where a condition holds. A scope naming a part, a slug, or a row marking its reasoning as a part, pages the skill: a first page under skill:<name> and parts under skill:<name>:<part>, the summary the part reasoning. The first page holds the short path, a routing line per part with its identifier, condition, and items, and every item no part holds; a part holds its condition and its items. A one-page skill fits the readers' default text limit, each page of a paged skill the maximum, and a longer first page holds its routing lines inside the first default chunk. A path naming a number outside the list, scoping an item twice, or breaking the measure fails generation.
A skill row may carry a page member: the route of the documentation page that answers its task, as the Cloud tree's index prints it. The overview's line names the page after the identifier, and a test holds each page to a route a page of the corpus declares. A row whose task no page answers carries none, and its line ends at the identifier. The overview's Where to start list says once, in its header, how a skill is read with read_context, and closes with one line naming the documentation page that maps tasks to guides.
This paragraph qualifies the third paragraph's first page. An item a scope holds there carries its condition ahead of its text, unless the item opens with "Where" and the condition's words. The reasoning part's routing line and catalog summary name it as the reasons behind the rules, and a scope naming its part reasoning fails generation. The human reference page, and a one-page skill's text where its row carries a short path, place the short path ahead of the list, a scoped item carrying its condition there as on the first page.
The fixed footer that closes every skill's first page, with its sentence on completing a destructive action through the browser approval, is the platform's own text and not a rendering of the row, so no row's list owes an item for it.
MCP-07 (decided): A destructive-tier tool never destroys: it creates the pending-action record and returns Turn Zero Cloud's description of what will be destroyed with the approval link (API-L0-07), and the outcome is readable through the surface once the browser click completes. No tool, resource, prompt, or other capability of this surface approves anything — at launch or ever — and the suite refuses a catalog that grows one.
The launch catalog
MCP-08 (decided): The launch surface is enumerated in schemas/mcp_surface.json, revision 2: each capability's name, form, tier, the launch scenario it serves, and owners, the statements its served description and its arguments' descriptions follow. Host annotations derive from the corresponding management action row under MCP-11. A shipped name is a stable identifier: renaming or removing one is a versioned contract change, never a quiet edit. A capability added later arrives as a catalog row with its form and tier assigned under MCP-03, which is how the destructive boundary stays enumerated per capability rather than judged per incident.
The served listing carries the catalog's rows whose implementations have landed. A row ahead of its implementation stays enumerated, its name stable and its tier assigned, and unlisted until the seam answers it, the rule the skills already follow (API-L0-10), so a connected tool never lists a capability that would refuse not_yet_provisioned.
The listing is also the connection's own. A row MAPI-09 marks with a grant is listed to a connection whose credential holds the row's grant or super_admin, the grant that admits every grant-marked row, or is bounded by a grant the row's admits mark names (MAPI-09). It is listed to no other connection: an anonymous connection, a customer's session, and a token minted with none of the grants among them (MAPI-14). The marks are grant: super_admin, grant: synthetic_estate on the synthetic estate's rows (MAPI-16), the operator signal's row (MAPI-17), and record_check (MAPI-18), and grant: publication on the two publish rows (MAPI-16). No row carries feedback_queue or issues, which bound their tokens and are decided at the handlers (MAPI-18; MAPI-14). A served skill (MCP-06) that drives a marked row is listed under the same rule, so a customer's tool lists no operator capability it could only be refused on.
The rule reads the enumeration's own mark and no list kept beside it (MAPI-11's discipline), and it conceals nothing. The catalog and the enumeration stay readable whole in the served bundle (CTX-02; API-L0-15), the overview names the operator's skill as the operator's, and the marked row itself is unchanged. The wire route answers it and refuses a credential the row does not admit, by the row's grant name (grant_required; MAPI-09; MAPI-10). A tools/call naming a row this connection does not list answers a refusal naming the tool, never not_yet_provisioned and never a silent success, and an anonymous call naming it draws the sign-in challenge (MCP-02).
An unmarked row a grant merely widens is listed to every connection as before, the grant deciding the subject or the form at the call. Those rows are delete_account, the builder realm's four realm rows, and read_feedback and settle_feedback, whose queue form and platform-space settle are the feedback queue grant's (MAPI-09).
A connection whose token a bounding grant bounds is listed less. A minted token holding synthetic_seed_purge, synthetic_estate, publication, feedback_queue, or issues and not super_admin (MAPI-16) is listed the rows its grant marks, the rows the enumeration marks admits with its grant's name, and the rows marked access: anonymous, and no other row. So the harness's token lists its six rows, list_tokens, submit_feedback (MAPI-16), and the anonymous four, and the publisher's token lists its two publish rows and the anonymous four. The hosted trial's token lists the seed, the purge, the purge's read, and the anonymous four. The feedback queue's triage token lists settle_feedback, read_feedback, and the anonymous four, and a token the issues grant bounds lists list_tokens, relay_issue_act, and the anonymous four (MAPI-18).
A served skill and a payload row of the context catalog list under the same rule, the listing reading the one predicate over the enumeration's marks that the dispatcher's bound gate reads (MAPI-16). A row marked access: anonymous is listed to every connection, a bounded token's included, on MAPI-11's mark.
The seven unmarked rows of the issue record, submit_feedback, read_feedback, rate_experience, settle_feedback, relay_issue_act, create_issue_space, and list_issue_spaces, and the marked record_check (MAPI-18; API-L0-20), are listed on the rules above while the build registers their handlers. It does so where the issue service's origin is configured and not otherwise, so before the service stands the eight are unlisted and refuse not_yet_provisioned as any row ahead of its implementation does.
While they are listed, a connection that lists submit_feedback under the rules above is served the feedback rule of the AI tool interface's feedback scenario (CHI-L0-14) in the server's instructions and in the overview's sentence. A connection whose bound leaves the row unlisted is served neither. Where such a connection presents a credential, every refused result but a refusal of submit_feedback itself carries a second content block naming submit_feedback and the refusal's reference after the unchanged JSON block. Every completed submit_feedback, read_feedback, settle_feedback, record_check, and relay_issue_act result is rendered as one block that opens with the untrusted marker and holds the answer between two delimiter lines, the reporters' text data and never instructions. The two status rows' fixed_block member is the one source of the live-fixed block's words, as their block member is of the ask's (CHI-L0-14; CTX-03).
A row the enumeration marks with a switch, switch: synthetic_estate on the two write rows of the synthetic estate (MAPI-16), is listed while the synthetic estate's posture is not off and unlisted while it is off. That follows the same derivation from the enumeration's own mark and that posture. The posture is the control plane's setting SYNTHETIC_ESTATE (MAPI-16). Its wire route stands and refuses by name, synthetic_estate_disabled, and a tools/call naming it while unlisted answers the refusal naming the tool. A row carrying both marks is listed where both admit it and unlisted where either does not. The catalog is data about the surface, not a second statement of the rules above; the suite holds the two together.
MCP-11: Every listed tool emits readOnlyHint, destructiveHint and openWorldHint from its management action’s explicit annotations, with idempotentHint only where its effects justify it. Metadata describes the action’s actual business effects and external interactions, not an inference from its authority tier; ordinary operational records and metering do not make a reader a business write. A destructive request describes the whole workflow even though only the browser may approve its completion (MCP-07). These annotations are descriptions, never authorization inputs. The standard MCP SDK serves tool listings and derives input schemas from the registered validators that check calls; the listed set follows the existing implementation, enabled and grant filters. schemas/mcp_surface.json records preferred and supported initialization revisions and the default for an absent HTTP revision header; protocol tests hold that call configuration to the installed server’s negotiation and refusal behavior.
MCP-09: Library entries may surface as resources derived from the served catalog, one enumeration entry recording the derivation — never a second row list beside the catalog. At launch none are derived and none are served. The agent writes an entry's files into the project once, from read_library_entry's answer, and a resource whose bytes change under a stable name would give it a second and conflicting source for files it already holds.
A derived library-resource name carries no resolution promise: API-L0-14 serves the latest publish alone, so a name that resolved yesterday may name different bytes today or nothing at all. That is why such a name is governed by API-L0-14 rather than by MCP-08's listing stability, exactly as the derived prompts are governed by API-L0-10's derivation rather than by a hand-kept list. Derived rows and the catalog's own resource row enter the enumeration when the registry serves them and not before — a shipped name is a promise, and an action has a refusal channel (not_yet_provisioned, MAPI-10) where a listed resource has none (Q-239).
MCP-10 (conforms: ACC-01, ACC-02, ACC-03, ACC-04): The connected session renews without the person, and the management plane's token endpoint is where the Account package's session contract lands. The endpoint issues a refresh token beside the access token and accepts the refresh_token grant, so a tool whose access token lapses renews its own. The browser sign-in then stays the one moment CHI-L0-03 names rather than a recurring interruption every working day. The code exchange of Turn Zero Blueprint's first-party client at /approve/blueprint/token (MCP-02) is no session flow: it answers one minted token and no refresh token, and the next exchange under the token's label for the same account and space replaces it (MAPI-14).
The renewal mechanics are the Account package's, cited in this statement's conformance edges and not restated here (Q-80's consumption by citation): rotation on redemption, a replayed credential revoking its chain beyond this plane's window, and renewal ending where the session ends. Sign out everywhere, suspension, and account deletion are this plane's session ends (ACS-L0-18; CHI-L0-12 for deletion; API-L0-12 for suspension). Each of the three ends the builder realm's OAuth leg and browser leg together on the terms ACS-L0-11 states; an ordinary sign-out ends one browser session and no connection (ACS-L0-18). Beside them, the connection's own revocation, revoke_connection (API-L0-21), ends one OAuth leg alone — that connection's refresh family and the access token issued in it — and touches the browser leg and every other connection not at all (ACS-L0-11).
The conformance is deliberately partial, and this paragraph is the edges' scope note. ACC-L0-06's custody clause — the refresh credential resting in the platform's secure store, never a synced file — is about the account holder's client device. A management-plane consumer cannot honor it, the refresh token living wherever the customer's own tool keeps it. Conformance runs to the session mechanics and not to custody.
The reuse window is this plane's second stated exception. A redeemed refresh credential presented again within ten minutes of its rotation answers a fresh pair from the same chain; presented later, it revokes the chain. The package states a shorter grace (ACC-03). The width serves a developer's tool that keeps one stored credential for several processes on one machine, whose rightful replays arrive minutes apart. Its cost is bounded: renewal falls at a term's end alone, so the detection the window yields is the ten minutes after each rotation and never a standing exposure, and a copy presented later still ends the chain. The end-user realm's token endpoint keeps the package's grace (ACS-L0-14). The ACC-03 edge runs to the grace's existence and to the chain's revocation beyond it, and not to its width, which the item raised in the package's document settles.
The lifetimes of each credential are call configuration below this statement, which states that renewal happens and not how long anything lives. One relation is fixed here. The access token, a realm session row the plane ends at once at sign out everywhere, suspension, and erasure (ACS-L0-11), lives the session's whole term rather than a short slice of it. The refresh token outlives it by a further term so that renewal stays possible. A shorter access life buys nothing a revocation does not. Renewal then falls at a term's end alone, which keeps the parallel sessions of one client from racing on a routine renewal and revoking their chain as a replay beyond this plane's window. Each of those sessions holds its own copy of the one token home ACC-05 recommends.
Every renewal path, including the consumed-token grace, checks the same eligibility before issuing either credential: the registered client and any supplied client identifier, lifetime, recorded resource/issuer, permitted scopes, and the account's current standing, revocation state and original authorizing generation under ACS-L0-11. A supplied resource must equal the recorded service. Requested access-token scopes may be a subset of the recorded grant; omission retains that grant. Rotation and grace retain the refresh grant's resource, issuer, client, original scope set and authorizing generation. Missing legacy binding is a named invalid_grant, not a default audience. The grace changes only the treatment of a recent repeat redemption; it bypasses none of these checks. A future redemption timestamp is not within the grace.
A control-plane release is not, of itself, a session end: the ends are the three ACS-L0-11 states, the per-device sign-out, and the per-connection revocation, and a release is none of them. Where each credential rests, and what form it takes, ACS-L0-02 and ACS-L0-11 state; none of it lives in a service process, and a release replaces the services' processes and holds none of it in them.
A release is inside this bound only when four conditions all hold. Its migrate-Job set is empty. Its settings change moves neither the issuer and resource the rows are bound to nor the reference to the secret the cookies are signed under. It does not rotate that secret. It changes no credential's or cookie's form. Such a release leaves an access token, a refresh credential, and the browser leg's cookies minted before it standing after it as they stood before.
The upgrade test reads an access token and its refresh credential across each control-plane release: the two reads an operator session makes from its stored credentials without the person. It reads the site's signed-in page, the read that needs the person's browser session, once: the measurement on record in the release plan. No later release owes that read. A browser session a release outside the bound ends is raised as an item beside this statement when the person meets it. A refusal it reads across a release inside the bound is a defect against this statement's release clause, found under RLC-L0-96, never a session end this statement admits.
A release outside the bound is named as such in its record before it runs, and the ends it causes are that release's to state. A refusal read across it is raised as an item beside this statement, the pinned credential and the release's record its evidence (RLC-L0-93).
The answers
The answers the management-action surface composes follow one convention, their budgets held in schemas/answer_budgets.json.
MCP-12: Every answer the management-action surface composes, on the wire and over MCP, keeps the prose of each of its forms within that form's budget, and so do the texts an MCP result carries beside its first block. These are served strings as MCP-05 defines them. The forms are a completed answer's detail and summary, and a version row's outcome detail as read_status and list_versions answer it. They are also a row's note, an environment's grain_note, a pending answer's detail and description, a refusal's detail, a text read's continuation, and an MCP result's second content block.
Each form's budget is one row of schemas/answer_budgets.json, the one home of its figure. A budget counts Unicode code points over the composed text and bounds the answer's fixed words. A list of the caller's own names or identifiers counts at one entry, and so does one such value, measured at its member's default where it has one.
A completed answer whose explanation a page holds says in its detail what happened and what the caller does next, and names that page in page, one typed member. Its value is an absolute address on the estate's public origin (PLD-L0-85), composed by the handler from a route it names: a guide where one explains the act, and otherwise the action's generated reference page. The address's path is a route read_documentation reads as its page (CTX-07).
page rides a completed answer the dispatcher answers to a dispatched call. A pending answer and a refusal carry none, a refusal's pointer being its help (MAPI-10). A destructive action's stored outcome carries none either; its explanation stands on the action's reference page, found by the action's name.
Whether a composed text keeps its requirement identifiers is MCP-05's rule, and this statement adds none. The served-surface suite holds the composed answers to their budgets and each page to a public page.
Exact source Markdown
---
document: mcp_surface
prefix: MCP
---
# The MCP Surface — Contract
## Purpose
This file is the contract for the Turn Zero Cloud MCP server's surface: how a customer's AI tool connects and authenticates, which kinds of capability surface as tools, resources, and prompts, and what the launch surface is. It settles the open point the AI tool interface PRD's open questions and the management API PRD's open questions both nominated, on the launch definition's own rule — the scenarios drive, the API guarantees (CHI-L0-02). It states the surface of a *client*: every capability here is the one API's (API-L0-01), reached through the MCP server acting as the connected identity (API-L0-02), and nothing here is MCP-only.
The launch surface's enumeration has one home: the catalog at `schemas/mcp_surface.json` beside this document — capability by capability, each with its form and its authority tier — held coherent by a test in the platform's suite. This document states the rules the catalog obeys and deliberately repeats none of its rows.
What this document does not cover: the API's own resource contract and versioning (`management_api_contract.md`); the pending action's mechanics (API-L0-07 owns them; this surface only reaches them); and the super-admin's capability inventory (MAPI-09's grant rows). Nor does it cover the launch skill set, whose rows are the contract's in `schemas/skills.json` under API-L0-10's derivation rule.
Requirements are numbered MCP-nn.
## The server and the connection
MCP-01 (decided): The Turn Zero Cloud MCP server is one remote server, hosted and operated by Turn Zero Cloud, reached over the Model Context Protocol's streamable HTTP transport at a URL the customer adds to their tool. It needs no local install, no sidecar, and nothing on the customer's machine beyond their own AI tool.
The server declares itself `turnzero-cloud`. That one name is its protocol identity and the name every install stanza Turn Zero Cloud publishes uses. A client prefixes a server's tools with the name it is bound under, so the name is also the word a customer's assistant reads on every action it takes here. It spells the product's approved public name, Turn Zero Cloud (azure:AZD-08), rather than the family, the host, or the code name the workspace writes internally, Turn Zero Cloud being the actor a management action reaches (Q-238). The spelling stays inside lowercase letters, digits, and hyphens. A client composes a tool name from the bound name, and the tool-name grammars in use do not all admit a dot, so a name carrying the domain's punctuation is not addressable everywhere the product is installed.
What a customer's own tool stores as the label for the connection is that customer's to choose and no requirement's to impose. This statement fixes what Turn Zero Cloud declares and publishes, which is the whole of what Turn Zero Cloud controls. The published name is a stable identifier on MCP-08's terms rather than a spelling free to drift. A later change to it is therefore a versioned contract change carrying every published stanza with it, never a quiet edit.
Which protocol revision the server speaks, and how it negotiates with older clients, is versioned call configuration beneath this contract, not a statement in it. The transport's JSON answers declare `charset=utf-8` in their Content-Type, so a client that applies a default charset to a bare media type decodes the server's UTF-8 bytes as written.
MCP-02 (decided; conforms: ACC-04): The authentication binding is OAuth 2.1 authorization code with PKCE, discoverable by the standard authorization-server metadata, with dynamic client registration so a customer's tool connects without a preconfigured client identity. The authorization moment is the sign-in page (WEB-L0-12): the builder realm's own surface (ACS-L0-01), served on the control plane's origin (ACS-L0-04), and the one browser interruption of CHI-L0-03. There a first sign-in creates the account where the builder realm's creation policy admits it (ACB-L0-77; ACS-L0-07) and is refused by name where it does not. The token the flow issues is the builder realm's session (ACS-L0-11), the credential the authority tiers bind to (API-L0-06). The connected session acts as that identity and nothing else, and disconnecting or signing out revokes the session rather than orphaning it.
A minted token (API-L0-05) connects the same server as its bearer with no browser moment, the sign-in flow never run for it. The connected session then acts as the token's own bounded identity under the same challenge. The platform credential connects nothing here and draws the standing challenge (SEC-L0-07).
Deployment configuration fixes one canonical authorization-server origin through OAUTH_ORIGIN and one protected-service resource identifier; neither is inferred from a request Host header or widened by an alias. The deployment template sets the origin from its trusted public API origin. An explicitly configured origin is validated before database migration or provisioning; an empty or malformed value refuses startup. Startup also refuses a missing OAUTH_ORIGIN when PGHOST has a nonempty value. Without OAUTH_ORIGIN or that deployment setting, a local executable selects the loopback origin from its actual bound listener, including an assigned ephemeral port. An application factory with no listener defaults to http://127.0.0.1:8080 unless its caller supplies the trusted origin.
Changing the origin makes prior-origin builder OAuth access and refresh grants ineligible and requires new OAuth authorization; other credential kinds keep their own validity rules, and an existing valid browser session may authorize the new grant without another human sign-in. The identifier advertised by protected-resource metadata names the existing Turn Zero Cloud protected service: the MCP endpoint and the API, documentation and data-plane surfaces already admitting this bearer under ACS-L0-11; it does not grant access to another service. Protected-resource metadata advertises the canonical resource and authorization-server issuer; authorization-server metadata repeats that issuer and its canonical endpoints. Both publish the supported OAuth scopes. Generated callback and return URLs whose destination is the control plane use its configured origin; the client's redirect remains its exact registered URI.
Authorization, code exchange, access-token records and refresh-family records preserve the resource, issuer, client and granted scopes. A supplied resource must match exactly; omission selects the configured service at authorization and retains the recorded resource at exchange or renewal, never a wildcard. Scope omission selects the documented default at authorization and retains the grant thereafter; an unknown scope or attempted broadening refuses. The scope names and default are versioned call configuration. OAuth scopes are separate from authority tiers and application grants and cannot create either. The shared credential resolver rejects unbound or foreign OAuth access credentials before dispatch; a protected call with a valid OAuth credential lacking its required scope answers insufficient_scope with HTTP 403.
Every MCP request the plane admits, presenting no credential or one resolving to no account, `initialize` included, answers 401 and a WWW-Authenticate challenge naming the protected-resource metadata and applicable scopes. An invalid presented credential also carries invalid_token and its error description; missing credentials carry none; the wire's anonymous rows stay readable (MAPI-11). The challenge's JSON body states in its detail the same case the header distinguishes: a connection that presented no credential, which reconnects with sign-in or starts the OAuth flow, or a presented credential that resolved to no account, which signs in again. Neither adds OAuth error information to the header, and the wire route's refusal states the same two texts. Every body the server's 401 challenge answers carries `help`, the address of its refusal's row on the refusals page (MAPI-10): `authentication_required`, `end_user_credential_not_admitted`, `transfer_grant_not_admitted`, `secret_grant_not_admitted`, `egress_key_not_admitted`, and `app_credential_not_admitted`. Browser-only approval and all other credential-kind boundaries remain MAPI-03 and API-L0-07's.
This paragraph qualifies the paragraph above for a presented bearer of a grant's form that resolves to no credential. The challenge's body and the wire route's refusal state a third text in that case: the platform serves no grant of that value. The text names both ways to a fresh grant: the tool call whose answer carried it, made again, and the application's own request for one, made again (MAPI-03). The name, the status, and the header stand as the paragraph above states them for a presented credential.
Registration serves public clients with token_endpoint_auth_method=none. Authorization accepts only an exact registered HTTPS redirect or HTTP loopback redirect, with no URI credentials or fragment; code exchange requires S256 PKCE. An additive migration retains old rows as explicitly unbound. It may backfill only where recorded issuance provenance proves the binding, and production cutover otherwise requires the developer-approved one-time reauthentication disposition; an unbound row never means all audiences.
This paragraph and the six after it qualify four paragraphs above for one client: the first paragraph's token, the fourth's published scopes, the fifth's default scope and its separation of scopes from grants, and the eighth's exact redirect match. The plane registers one first-party public client of its own, `turnzero-blueprint`, the command of Turn Zero Blueprint, in its source and in `schemas/mcp_surface.json`'s `oauth` member, never through dynamic registration. Its redirect is `http://127.0.0.1/callback` or `http://[::1]/callback` at any port the request names (RFC 8252). Its one scope, and its default, is `issues`, which no other client is given and the metadata does not advertise.
The `issues` scope gives no grant by itself: the token is minted on the person's confirmation, on MAPI-14's terms. The `oauth` member holds the client, its redirects, its scope, the request code, the request's and the exchange's paths, and the exchange's members as call configuration, and a test holds it to the server.
The client's authorization request is the accounts service's `/oauth/authorize`. It carries S256 PKCE, a `state`, a `label` in `mint_token`'s form (MAPI-14), and optionally a `space` and a `component` in the issue contract's form. Each is refused by name before any sign-in where it is missing or malformed. The request reads no issue service. After the sign-in moment, or at once where the browser holds a site session signed in within WEB-L0-16's freshness window, it holds the confirmation and hands the browser to the confirm page. The management service serves that page under `/approve/blueprint/`. A request the browser marks as a prefetch holds nothing, nor does a completion of its sign-in the browser marks so (WEB-L0-24).
The confirm page names the account by its sign-in address, or by its identifier where it holds none. Beside it stands a control that signs the browser out and restarts the request at the sign-in. The page shows the request code: the first eight hexadecimal digits, in upper case, of the SHA-256 digest the `code_challenge` carries, which the client prints beside the address it opens. The page and its posts answer only the browser whose request held them, and a second request in that browser leaves the first open.
The page lists the spaces the account holds, the named space alone where the request names one, and otherwise offers to create one. It names the label, the level, `owner`, and the component, and says where confirming replaces a token of that label. Confirming mints a single-use code alone, and a refusal or a cancel on the page returns its name and the `state` to the client's redirect. Two refusals return nothing to the client: the admission window's (PLD-L0-67), answered before the ticket is read, which the client reads by its own timeout, and a choice the page does not offer, which leaves the ticket standing for another choice. No other site may frame the confirm page, or the sign-in page the request reaches.
The code exchange is the management service's `/approve/blueprint/token`, beside the page, and the token endpoint refuses that client's exchange by name, `invalid_grant`. The exchange reads the authorizing generation again, then the space's owner and the licence in `mint_token`'s order. Where the confirmation chose a new space, it reads the licence and creates the space under `create_issue_space`'s rules, ahead of the mint. It mints one `issues` token at the `owner` level for the space, issued to that client (MAPI-14). The answer carries the value once, with its space, level, label, and identity, the plane's origin, and the tokens it revoked, under `Cache-Control: no-store`. It carries no refresh token, and the exchange opens no session and no connection (MCP-10).
An account without the `blueprint` profile is refused `blueprint_required` on the page and at the exchange (ACB-L0-82), and a space it does not hold `space_not_owned`. Where the management service serves no issue service, both refuse `not_yet_provisioned`. A code never exchanged expires having created, minted, and revoked nothing. A mint that fails after the exchange created a space leaves that space with no token, and the refusal names the space.
The exchange's token has no expiry date. It ends when a later exchange under its label replaces it, when `revoke_token` revokes it, when it goes 30 days unused (PLD-L0-67), at sign out everywhere, at a passkey change's revert (ACS-L0-10), and at the account's suspension (API-L0-12). Sign out everywhere ends it before the generation's bump and again after the refresh rows are deleted, and a revert before the revert commits and again after its refresh rows, so an exchange that raced the act is caught. Each act's answer counts the tokens it ended as `exchange_tokens_revoked`, and a reinstatement restores none of them.
After its mint the exchange reads the generation again from the store; where it moved, the exchange revokes the token it minted and is refused as a sign-in ended after the confirmation is, naming a space it created, and answers no value. Where that revocation fails, the token stands unanswered and held by no one until the 30-day sweep or the next sign out everywhere ends it.
## The three forms
MCP-03 (decided): Every management action callable by an AI client is a tool corresponding to one API capability. Its authority tier — observe, reversible or destructive — remains explicit in the authoritative catalog and enforced by the management API (API-L0-06); a host annotation neither grants authority nor supplies approval. Each tool advertises truthful standard MCP annotations derived from its action’s catalog metadata, under MCP-11. Served readable context retains its addressable resources, and skills retain their prompts. The same content is also available through the observe tools CTX-07 defines, so resource and prompt support enriches a client without being required for discovery. These protocol forms derive from the same API and content sources; none owns an independent capability or copy of the content.
MCP-04 (decided): Tools alone are the floor: every launch scenario’s management steps complete through tool calls and the browser moments CHI-L0-03 states, with no management step that requires resources or prompts. The signed-in site (WEB-L0-15) is a view of the same acts, required by none. Deployment starts from the externally prepared and uploaded artifact CHI-L0-01 requires; deploy receives its account-owned storage reference and hash, without requiring a filesystem or byte upload in the MCP client. A client supporting only tools loses the slash-command surface and the preloadable context, never a capability — discovery’s catalog and complete readable content arrive through list_context, read_context and read_documentation there, and the served documents remain readable outside the protocol (API-L0-09's other two forms). This is what makes "any AI tool's output is a first-class citizen" true of the tool's *client features* too.
MCP-05 (decided): Discovery is the protocol's own listings — tools, resources, and prompts, each entry carrying a description a newcomer can act on — plus the overview. The overview, available as both a resource and a read_context result, answers "what can the platform do and where do I start" in one read. Every listing description derives from the same one source as the human documentation and the authoring bundle (API-L0-09), so what the tool shows, the docs say, and the bundle teaches cannot disagree. The rule extends to library catalog rows: a catalog row's listing description derives from the package-owned selection summary the catalog quotes (FTR-L0-57's section), the same one-source discipline over the library's source.
A served string names the product by an approved public name — Turn Zero Cloud, or the platform; Turn Zero Blueprint for the kit (azure:AZD-08) — and never by a code name or an internal product name. This is the product-name half of the public-name rule the documentation suite and the served-surface suite share. A served string is every tool description and argument description, every resource description, every prompt description and prompt text, and every text the server composes — the overview, a refusal's detail, an action's response detail. It is also every field of the enumeration files the bundle and the `service_contracts` resource carry, the bundle's guides, and the selection summaries the catalog quotes.
The requirements documents the bundle packages verbatim are the source itself (CTX-02), and CTX-08 holds that source to the same product-name half. A clearly labeled reproduction of an indexed contract, enumeration, or guide in the generated human reference therefore carries the approved names because its source does. A reproduction preserves its source's identifiers. The reference distinguishes resolvable links within the published index from citations to sources that are not published there, without publishing additional sources merely to satisfy a citation.
No listing description carries a requirement or decision identifier: a tool's, an argument's, a resource's, a prompt's, or a catalog entry's summary list_context answers. No line of the overview carries one either. A catalog row names the statements its descriptions follow in its `scenario` and `owners` members (MCP-08), which reach a client in the whole-file reads alone. MCP-06's rendering of a skill's lead, the prompt description, keeps the identifiers of the row's must items and no other. A refusal's detail and an action's response detail may close on a rule code, the identifier of the rule behind the answer. The instructions say once what a rule code is, with one example, ahead of the origin line, and the overview with none. The served-surface suite holds the served strings to the product-name half, and the listing descriptions and the overview to this paragraph.
Beside the overview, the server's instructions name, on every connection, the estate's configured origin (MCP-02), never one read from a request, and what a script reaches there: the management actions at `/api/v1/actions/<action>`, the storage routes, and the library's anonymous reads. Before the line naming the origin, which stays their last, the instructions say that a management action's refusal may carry `help`, the address of its row on the refusals page at `<origin>/cloud/reference/refusals/`, where every refusal's name and remedy are explained. That origin is the public origin `help` is composed on, so an agent meeting a refusal name no `help` rides with, in a detail, a data plane's body, or a page, still learns where the name is explained.
The overview, as a resource and as a `read_context` result, carries the same origin line.
Each tool's summary opens with one sentence of at most 200 characters saying what the tool is for, so a host that cuts a description short still shows what the tool is for.
This paragraph qualifies the fifth paragraph's instructions. On a connection that lists `read_status`, they also say, ahead of the refusals page's sentence, that an answer to an act that is not the platform's own says nothing about whether the act was made (MAPI-04). They name a gateway's error page and a closed connection as such answers, `read_status` with `wait_seconds` as the read to make first, and what in it shows the act started. They say to repeat the act only where that read shows it did not start, never where it cannot tell, and send a schedule run to `read_schedules` and its same `request_id`. The text names no identifier, and the overview carries it under the same condition.
This paragraph qualifies the fifth paragraph's instructions too. On a connection that lists `read_context`, they open by saying what the platform is for and by naming the overview as the first read, with the call that reads it. The opening names no identifier.
This paragraph qualifies the fifth paragraph's instructions too. On a connection that lists `deploy`, they say, after the eighth paragraph's sentences where those stand and ahead of the refusals page's sentence, that a command this platform answers needs Node.js 24 or later, the version PLD-L0-82 holds every stated number to. The sentence names no identifier, and the overview does not carry it.
MCP-13: **Each text the server lists is held to what a client shows of it: a tool's summary, a tool's served input schema, and the server's instructions; a row's `reference` holds what its summary cannot.** A caller then reads the whole of what the listing says. A summary and the instructions, each counted in UTF-16 units, and a served input schema, counted in bytes of compact JSON, run to at most the figure the catalog's `listing_bounds` member holds for each, a row that member holds by name excepted. The instructions are measured at their longest composition on each estate's origin. That member of `schemas/mcp_surface.json` is the one home of the three figures, and family:Q-273 holds what each client shows of a listing, the versions it was read at, and the margins.
A summary holds what a caller cannot learn elsewhere in time. It says what the tool is for, in its opening sentence (MCP-05). It says when to call the tool and not a neighbour, and the acts before and after it where the call is one step of several. It says what the call changes, provisions, costs, or cannot undo, and the approval it waits for. It states a rule on how to call the tool that no single argument owns, and a value in the answer whose meaning the answer does not carry itself. Where the row carries a `reference`, its last sentence says where the rest is. A sentence another statement places in a description stays in it.
The rest of a row's text stands in the row's `reference` member, which the listing does not serve. The action's generated reference page renders it after the summary. A row that carries one closes its summary by naming that page's path, and by saying that `read_documentation` reads the page and the platform's origin serves it. A row's `owners` names the statements its `reference` follows too, and a `reference` carries no identifier, as a summary carries none.
An argument's description keeps what the argument means, the values it admits, and the refusal a wrong value draws. A row whose served input schema cannot meet its bound with those in the listing is named in `listing_bounds` with its reason and the size it is held at, and is cut no further. The suite refuses a named row that fits the bound, a named row over its held size, and an unnamed row over the bound.
The served-surface suite holds each bound against the listing a connection receives, and each closing sentence against its page's own path.
MCP-06 (decided): Each skill surfaces as one prompt, invocable as a slash command in clients that support them, and the prompt set is derived from what Turn Zero Cloud offers (API-L0-10). The server enumerates it from the same source as everything else, and no hand-kept prompt list exists to drift. A tools-only client obtains that same skill text through read_context, with the same implementation and credential-grant filtering (CTX-07); the tool path does not author a second recipe.
Each skill row carries a `must` member, an array of imperative sentences stating what the implementer must do, each ending with the identifier of the statement that owns the rule. The served skill text carries every item on exactly one of its pages under its list number; the human reference page places the whole list ahead of the whole summary. The prompt's description carries the summary's first sentence and then the whole list, and the prompt's text is the first page. The catalog entry for a skill and the overview's line carry no must item: each names the skill, its `read_context` identifier `skill:<name>`, and a one-line purpose, the summary's first sentence with each parenthetical holding an identifier dropped whole. No rendering restates a rule the list omits or reorders the list; each driven action is one line, its name, its tier, and its tool summary's opening sentence.
A skill row may carry a `short_path` member: a lead, a few steps for the common case, each naming by number the items it follows, and the items applying only where a condition holds. A scope naming a `part`, a slug, or a row marking its reasoning as a part, pages the skill: a first page under `skill:<name>` and parts under `skill:<name>:<part>`, the summary the part `reasoning`. The first page holds the short path, a routing line per part with its identifier, condition, and items, and every item no part holds; a part holds its condition and its items. A one-page skill fits the readers' default text limit, each page of a paged skill the maximum, and a longer first page holds its routing lines inside the first default chunk. A path naming a number outside the list, scoping an item twice, or breaking the measure fails generation.
A skill row may carry a `page` member: the route of the documentation page that answers its task, as the Cloud tree's index prints it. The overview's line names the page after the identifier, and a test holds each `page` to a route a page of the corpus declares. A row whose task no page answers carries none, and its line ends at the identifier. The overview's Where to start list says once, in its header, how a skill is read with `read_context`, and closes with one line naming the documentation page that maps tasks to guides.
This paragraph qualifies the third paragraph's first page. An item a scope holds there carries its condition ahead of its text, unless the item opens with "Where" and the condition's words. The reasoning part's routing line and catalog summary name it as the reasons behind the rules, and a scope naming its part `reasoning` fails generation. The human reference page, and a one-page skill's text where its row carries a short path, place the short path ahead of the list, a scoped item carrying its condition there as on the first page.
The fixed footer that closes every skill's first page, with its sentence on completing a destructive action through the browser approval, is the platform's own text and not a rendering of the row, so no row's list owes an item for it.
MCP-07 (decided): A destructive-tier tool never destroys: it creates the pending-action record and returns Turn Zero Cloud's description of what will be destroyed with the approval link (API-L0-07), and the outcome is readable through the surface once the browser click completes. No tool, resource, prompt, or other capability of this surface approves anything — at launch or ever — and the suite refuses a catalog that grows one.
## The launch catalog
MCP-08 (decided): The launch surface is enumerated in `schemas/mcp_surface.json`, revision 2: each capability's name, form, tier, the launch scenario it serves, and `owners`, the statements its served description and its arguments' descriptions follow. Host annotations derive from the corresponding management action row under MCP-11. A shipped name is a stable identifier: renaming or removing one is a versioned contract change, never a quiet edit. A capability added later arrives as a catalog row with its form and tier assigned under MCP-03, which is how the destructive boundary stays enumerated per capability rather than judged per incident.
The served listing carries the catalog's rows whose implementations have landed. A row ahead of its implementation stays enumerated, its name stable and its tier assigned, and unlisted until the seam answers it, the rule the skills already follow (API-L0-10), so a connected tool never lists a capability that would refuse `not_yet_provisioned`.
The listing is also the connection's own. A row MAPI-09 marks with a grant is listed to a connection whose credential holds the row's grant or `super_admin`, the grant that admits every grant-marked row, or is bounded by a grant the row's `admits` mark names (MAPI-09). It is listed to no other connection: an anonymous connection, a customer's session, and a token minted with none of the grants among them (MAPI-14). The marks are `grant: super_admin`, `grant: synthetic_estate` on the synthetic estate's rows (MAPI-16), the operator signal's row (MAPI-17), and `record_check` (MAPI-18), and `grant: publication` on the two publish rows (MAPI-16). No row carries `feedback_queue` or `issues`, which bound their tokens and are decided at the handlers (MAPI-18; MAPI-14). A served skill (MCP-06) that drives a marked row is listed under the same rule, so a customer's tool lists no operator capability it could only be refused on.
The rule reads the enumeration's own mark and no list kept beside it (MAPI-11's discipline), and it conceals nothing. The catalog and the enumeration stay readable whole in the served bundle (CTX-02; API-L0-15), the overview names the operator's skill as the operator's, and the marked row itself is unchanged. The wire route answers it and refuses a credential the row does not admit, by the row's grant name (`grant_required`; MAPI-09; MAPI-10). A tools/call naming a row this connection does not list answers a refusal naming the tool, never `not_yet_provisioned` and never a silent success, and an anonymous call naming it draws the sign-in challenge (MCP-02).
An unmarked row a grant merely widens is listed to every connection as before, the grant deciding the subject or the form at the call. Those rows are `delete_account`, the builder realm's four realm rows, and `read_feedback` and `settle_feedback`, whose queue form and platform-space settle are the feedback queue grant's (MAPI-09).
A connection whose token a bounding grant bounds is listed less. A minted token holding `synthetic_seed_purge`, `synthetic_estate`, `publication`, `feedback_queue`, or `issues` and not `super_admin` (MAPI-16) is listed the rows its grant marks, the rows the enumeration marks `admits` with its grant's name, and the rows marked `access: anonymous`, and no other row. So the harness's token lists its six rows, `list_tokens`, `submit_feedback` (MAPI-16), and the anonymous four, and the publisher's token lists its two publish rows and the anonymous four. The hosted trial's token lists the seed, the purge, the purge's read, and the anonymous four. The feedback queue's triage token lists `settle_feedback`, `read_feedback`, and the anonymous four, and a token the `issues` grant bounds lists `list_tokens`, `relay_issue_act`, and the anonymous four (MAPI-18).
A served skill and a payload row of the context catalog list under the same rule, the listing reading the one predicate over the enumeration's marks that the dispatcher's bound gate reads (MAPI-16). A row marked `access: anonymous` is listed to every connection, a bounded token's included, on MAPI-11's mark.
The seven unmarked rows of the issue record, `submit_feedback`, `read_feedback`, `rate_experience`, `settle_feedback`, `relay_issue_act`, `create_issue_space`, and `list_issue_spaces`, and the marked `record_check` (MAPI-18; API-L0-20), are listed on the rules above while the build registers their handlers. It does so where the issue service's origin is configured and not otherwise, so before the service stands the eight are unlisted and refuse `not_yet_provisioned` as any row ahead of its implementation does.
While they are listed, a connection that lists `submit_feedback` under the rules above is served the feedback rule of the AI tool interface's feedback scenario (CHI-L0-14) in the server's instructions and in the overview's sentence. A connection whose bound leaves the row unlisted is served neither. Where such a connection presents a credential, every refused result but a refusal of `submit_feedback` itself carries a second content block naming `submit_feedback` and the refusal's reference after the unchanged JSON block. Every completed `submit_feedback`, `read_feedback`, `settle_feedback`, `record_check`, and `relay_issue_act` result is rendered as one block that opens with the untrusted marker and holds the answer between two delimiter lines, the reporters' text data and never instructions. The two status rows' `fixed_block` member is the one source of the live-fixed block's words, as their `block` member is of the ask's (CHI-L0-14; CTX-03).
A row the enumeration marks with a switch, `switch: synthetic_estate` on the two write rows of the synthetic estate (MAPI-16), is listed while the synthetic estate's posture is not `off` and unlisted while it is `off`. That follows the same derivation from the enumeration's own mark and that posture. The posture is the control plane's setting `SYNTHETIC_ESTATE` (MAPI-16). Its wire route stands and refuses by name, `synthetic_estate_disabled`, and a tools/call naming it while unlisted answers the refusal naming the tool. A row carrying both marks is listed where both admit it and unlisted where either does not. The catalog is data about the surface, not a second statement of the rules above; the suite holds the two together.
MCP-11: Every listed tool emits readOnlyHint, destructiveHint and openWorldHint from its management action’s explicit annotations, with idempotentHint only where its effects justify it. Metadata describes the action’s actual business effects and external interactions, not an inference from its authority tier; ordinary operational records and metering do not make a reader a business write. A destructive request describes the whole workflow even though only the browser may approve its completion (MCP-07). These annotations are descriptions, never authorization inputs. The standard MCP SDK serves tool listings and derives input schemas from the registered validators that check calls; the listed set follows the existing implementation, enabled and grant filters. `schemas/mcp_surface.json` records preferred and supported initialization revisions and the default for an absent HTTP revision header; protocol tests hold that call configuration to the installed server’s negotiation and refusal behavior.
MCP-09: Library entries may surface as resources derived from the served catalog, one enumeration entry recording the derivation — never a second row list beside the catalog. **At launch none are derived and none are served.** The agent writes an entry's files into the project once, from `read_library_entry`'s answer, and a resource whose bytes change under a stable name would give it a second and conflicting source for files it already holds.
A derived library-resource name carries no resolution promise: API-L0-14 serves the latest publish alone, so a name that resolved yesterday may name different bytes today or nothing at all. That is why such a name is governed by API-L0-14 rather than by MCP-08's listing stability, exactly as the derived prompts are governed by API-L0-10's derivation rather than by a hand-kept list. Derived rows and the catalog's own resource row enter the enumeration when the registry serves them and not before — a shipped name is a promise, and an action has a refusal channel (`not_yet_provisioned`, MAPI-10) where a listed resource has none (Q-239).
MCP-10 (conforms: ACC-01, ACC-02, ACC-03, ACC-04): The connected session renews without the person, and the management plane's token endpoint is where the Account package's session contract lands. The endpoint issues a refresh token beside the access token and accepts the refresh_token grant, so a tool whose access token lapses renews its own. The browser sign-in then stays the one moment CHI-L0-03 names rather than a recurring interruption every working day. The code exchange of Turn Zero Blueprint's first-party client at `/approve/blueprint/token` (MCP-02) is no session flow: it answers one minted token and no refresh token, and the next exchange under the token's label for the same account and space replaces it (MAPI-14).
The renewal mechanics are the Account package's, cited in this statement's conformance edges and not restated here (Q-80's consumption by citation): rotation on redemption, a replayed credential revoking its chain beyond this plane's window, and renewal ending where the session ends. Sign out everywhere, suspension, and account deletion are this plane's session ends (ACS-L0-18; CHI-L0-12 for deletion; API-L0-12 for suspension). Each of the three ends the builder realm's OAuth leg and browser leg together on the terms ACS-L0-11 states; an ordinary sign-out ends one browser session and no connection (ACS-L0-18). Beside them, the connection's own revocation, `revoke_connection` (API-L0-21), ends one OAuth leg alone — that connection's refresh family and the access token issued in it — and touches the browser leg and every other connection not at all (ACS-L0-11).
The conformance is deliberately partial, and this paragraph is the edges' scope note. ACC-L0-06's custody clause — the refresh credential resting in the platform's secure store, never a synced file — is about the account holder's client device. A management-plane consumer cannot honor it, the refresh token living wherever the customer's own tool keeps it. Conformance runs to the session mechanics and not to custody.
The reuse window is this plane's second stated exception. A redeemed refresh credential presented again within ten minutes of its rotation answers a fresh pair from the same chain; presented later, it revokes the chain. The package states a shorter grace (ACC-03). The width serves a developer's tool that keeps one stored credential for several processes on one machine, whose rightful replays arrive minutes apart. Its cost is bounded: renewal falls at a term's end alone, so the detection the window yields is the ten minutes after each rotation and never a standing exposure, and a copy presented later still ends the chain. The end-user realm's token endpoint keeps the package's grace (ACS-L0-14). The ACC-03 edge runs to the grace's existence and to the chain's revocation beyond it, and not to its width, which the item raised in the package's document settles.
The lifetimes of each credential are call configuration below this statement, which states that renewal happens and not how long anything lives. One relation is fixed here. The access token, a realm session row the plane ends at once at sign out everywhere, suspension, and erasure (ACS-L0-11), lives the session's whole term rather than a short slice of it. The refresh token outlives it by a further term so that renewal stays possible. A shorter access life buys nothing a revocation does not. Renewal then falls at a term's end alone, which keeps the parallel sessions of one client from racing on a routine renewal and revoking their chain as a replay beyond this plane's window. Each of those sessions holds its own copy of the one token home ACC-05 recommends.
Every renewal path, including the consumed-token grace, checks the same eligibility before issuing either credential: the registered client and any supplied client identifier, lifetime, recorded resource/issuer, permitted scopes, and the account's current standing, revocation state and original authorizing generation under ACS-L0-11. A supplied resource must equal the recorded service. Requested access-token scopes may be a subset of the recorded grant; omission retains that grant. Rotation and grace retain the refresh grant's resource, issuer, client, original scope set and authorizing generation. Missing legacy binding is a named invalid_grant, not a default audience. The grace changes only the treatment of a recent repeat redemption; it bypasses none of these checks. A future redemption timestamp is not within the grace.
A control-plane release is not, of itself, a session end: the ends are the three ACS-L0-11 states, the per-device sign-out, and the per-connection revocation, and a release is none of them. Where each credential rests, and what form it takes, ACS-L0-02 and ACS-L0-11 state; none of it lives in a service process, and a release replaces the services' processes and holds none of it in them.
A release is inside this bound only when four conditions all hold. Its migrate-Job set is empty. Its settings change moves neither the issuer and resource the rows are bound to nor the reference to the secret the cookies are signed under. It does not rotate that secret. It changes no credential's or cookie's form. Such a release leaves an access token, a refresh credential, and the browser leg's cookies minted before it standing after it as they stood before.
The upgrade test reads an access token and its refresh credential across each control-plane release: the two reads an operator session makes from its stored credentials without the person. It reads the site's signed-in page, the read that needs the person's browser session, once: the measurement on record in the release plan. No later release owes that read. A browser session a release outside the bound ends is raised as an item beside this statement when the person meets it. A refusal it reads across a release inside the bound is a defect against this statement's release clause, found under RLC-L0-96, never a session end this statement admits.
A release outside the bound is named as such in its record before it runs, and the ends it causes are that release's to state. A refusal read across it is raised as an item beside this statement, the pinned credential and the release's record its evidence (RLC-L0-93).
## The answers
The answers the management-action surface composes follow one convention, their budgets held in `schemas/answer_budgets.json`.
MCP-12: Every answer the management-action surface composes, on the wire and over MCP, keeps the prose of each of its forms within that form's budget, and so do the texts an MCP result carries beside its first block. These are served strings as MCP-05 defines them. The forms are a completed answer's `detail` and `summary`, and a version row's outcome `detail` as `read_status` and `list_versions` answer it. They are also a row's `note`, an environment's `grain_note`, a pending answer's `detail` and `description`, a refusal's `detail`, a text read's `continuation`, and an MCP result's second content block.
Each form's budget is one row of `schemas/answer_budgets.json`, the one home of its figure. A budget counts Unicode code points over the composed text and bounds the answer's fixed words. A list of the caller's own names or identifiers counts at one entry, and so does one such value, measured at its member's default where it has one.
A completed answer whose explanation a page holds says in its `detail` what happened and what the caller does next, and names that page in `page`, one typed member. Its value is an absolute address on the estate's public origin (PLD-L0-85), composed by the handler from a route it names: a guide where one explains the act, and otherwise the action's generated reference page. The address's path is a route read_documentation reads as its `page` (CTX-07).
`page` rides a completed answer the dispatcher answers to a dispatched call. A pending answer and a refusal carry none, a refusal's pointer being its `help` (MAPI-10). A destructive action's stored outcome carries none either; its explanation stands on the action's reference page, found by the action's name.
Whether a composed text keeps its requirement identifiers is MCP-05's rule, and this statement adds none. The served-surface suite holds the composed answers to their budgets and each `page` to a public page.