import { type ReceiptFault } from "./mods/kernel/receive.js";
import type { ToolContentOrigin, ToolEffect } from "./tool-spec.js";
import type { ToolFamily, ToolPathTarget, ToolRenderHints, ToolRuleFace } from "./tool-face.js";
/** Definition of an MCP server to connect to for the duration of one task, then discard. */
export interface McpServerSpec {
    /** Stable name; tool names are namespaced as `mcp__<server>__<tool>` (the protocol prefix, then this name as the peer segment) to avoid collisions. */
    name: string;
    /**
     * Where this declaration CAME FROM, in the declaring side's own words (a shell's `plugin` / `user` /
     * `project` / `local` config tiers, or anything else the deployment finds useful). Core reads
     * nothing off it: it is echoed verbatim (single-line, length-bounded) onto the wiring manifest's
     * per-server read face (`WiringManifest.mcp[].source`) so a consumer can group servers by their
     * declaring tier without keeping a side table keyed on names. Optional; absent stays absent.
     */
    source?: string;
    transport: {
        kind: "stdio";
        command: string;
        args?: string[];
        env?: Record<string, string>;
    } | {
        kind: "http";
        url: string;
        /** Static headers sent on every request (e.g. an auth bearer for the MCP server itself). */
        headers?: Record<string, string>;
        /**
         * Per-task **end-user principal** header (design/62). When set, the Runner injects the running task's
         * authenticated {@link TaskSpec.principal} as this header (e.g. `"X-Agent-Principal"`) on every call to
         * this server's tools, so the MCP server can enforce per-user RBAC. Absent {@link TaskSpec.principal}
         * ⇒ the header is **not** sent (the MCP server must default to deny/public, never admin). A static `headers`
         * entry under the same name in any case refuses this server at its dial (`config.protocol_header_collision`,
         * header names being case-insensitive). The principal is Runner-held and the model/worker can neither read
         * nor set it (it is not a tool argument) — see {@link TaskSpec.principal}.
         */
        principalHeader?: string;
    };
    /** Optional allowlist of tool names to expose (others are dropped). ORTHOGONAL to
     *  {@link contentOrigin} and usefully paired with it (design/378 §2): the class declaration follows
     *  the server's roster, so a high-assurance deployment that wants a CLOSED tool set writes both —
     *  a tool a later refresh adds then lands outside this list and is simply not mounted. Existing
     *  semantics, no new mechanism; the refresh receipt still names every added tool either way. */
    allowTools?: string[];
    /**
     * design/99 §E23 — opt in to INBOUND elicitation for THIS server: when `true` AND a {@link RunnerDeps.onElicit}
     * seam is wired, core advertises the `elicitation` capability to this server and registers a handler, so the
     * server may send an `elicitation/create` request to ask the END USER for input mid-tool-call. **Default OFF
     * (fail-closed)**: never advertise unless explicitly wired, so a untrusted/over-eager server cannot pull a human
     * into the loop. v1 is LIVE-ONLY — `onElicit` answers synchronously on the open connection (no durable
     * suspend; a durable/cross-replica elicitation needs the deferred E22 longer-lived connection).
     */
    elicitation?: boolean;
    /**
     * Caller-side per-tool safety-axis overrides, keyed by the server's REMOTE (un-namespaced) tool name. The
     * CALLER is the trust root: unlike a server's self-declared annotations (which may only TIGHTEN), a caller
     * override is AUTHORITATIVE and may LOWER an effect (vouch a tool is `read`/`idempotent`) as well as raise it
     * (`egress` / irreversible). This is the ONLY trusted way to drop an MCP tool below the fail-closed `write`
     * default (design F). Folds over the server hints in prepare-task (caller > server hint > fail-closed write).
     *
     * A DIFFERENT AXIS from {@link contentOrigin}: this one is about what a call DOES (repeat-safety,
     * blast radius, reversibility — it feeds the approval gate); the content class is about what a call
     * BRINGS BACK (memory-write governance, no gate/policy/roster effect). Neither implies the other —
     * a read-only tool can return third-party text, and a deployment's own writer brings back nothing
     * external — so vouching on one axis never quietly vouches on the other.
     *
     * THE SHAPE IS JUDGED, NOT TRUSTED: {@link readToolAxes} is the one reader of this declaration (an A2A peer's `toolAxes` is read by it too). The
     * preparation door runs it on every entry, and a declaration it cannot read refuses the whole prepare
     * (`config.invalid_argument`) — one bad tool refuses the entry, a bad key is never dropped and a bad word
     * never defaults, because a caller's safety axis that silently reads as absent is a trust root that is not
     * in force. The materialization entrance (`materializeMcpTools`, which the no-run probe dials through) asks
     * it again per server: a declaration it cannot read fails THAT server's dial. A host that assembles this
     * field from JSON (a console, a deployment intake) asks the same reader at its own door, so both sides
     * answer one question one way.
     */
    toolAxes?: Record<string, {
        effect?: ToolEffect;
        egress?: boolean;
        irreversibility?: "always" | "never";
    }>;
    /**
     * design/388 §1.1 / §2.7 — the OPTIONAL per-tool FACE overlay for this server's tools (keyed by the server's
     * RAW tool name, like {@link allowTools} / {@link toolAxes}): a deployment lets an MCP tool enter a specialised
     * approval card, be confirmed by path, carry a display name / summary, or narrow its rule vocabulary. TRUSTED
     * (the deployment writes it), but validated against the MATERIALIZED schema at every listing (first mount and
     * every refresh): a `pathTarget.param` that is not a top-level property, an `approvalCard` whose keys the schema
     * lacks, a `ruleFace` naming a non-scalar key ⇒ the tool mounts WITHOUT the overlay and the leg announces
     * `config.tool_face_invalid` once; a key naming a tool the listing does not carry announces
     * `config.tool_face_undeclared` once. Applied whole or not at all.
     */
    toolFaces?: Record<string, {
        family?: ToolFamily;
        pathTarget?: ToolPathTarget;
        renderHints?: ToolRenderHints;
        ruleFace?: ToolRuleFace;
    }>;
    /**
     * design/378 — declare {@link ToolSpec.contentOrigin} on behalf of THIS SERVER'S ENTIRE TOOL SET
     * (tools a mid-task refresh adds included), with the same authority and the same responsibility a
     * directly-mounted host tool's own declaration carries.
     *
     * WHY THE SEAT EXISTS. Without it the class keys on the MOUNT SHAPE rather than on lineage: a tool
     * the deployment wrote and runs itself is structurally `"external"` the moment it arrives over the
     * MCP protocol namespace, so every call marks the session's memory externally exposed. The
     * per-name channels cannot express the fact either — {@link import("./memory.js").MemorySpecInput.trustedTools}
     * is a per-REQUEST allowlist keyed on the MINTED name (the host would have to predict the charset
     * normalization) whose own definition is "the exception channel for UNDECLARED tools", and it says
     * nothing about tools the server adds later.
     *
     * THIS IS A TRUST DECLARATION, not a routing hint. Use it only for servers inside the deployment's
     * trust boundary — a process, socket or service the deployment itself runs. Declaring a THIRD-PARTY
     * server means treating its output as content the deployment wrote: the class names are
     * BOUNDARY-relative, never topological, so neither the transport kind nor the address is evidence
     * of lineage (a stdio child can be an untrusted package; a loopback URL can be your own service) and
     * core deliberately does not gate on either. The declaration covers THE PEER THIS ENTRY CONNECTS TO
     * — authenticating that peer (socket permissions, credentials) is the host's mounting duty.
     *
     * SEMANTICS. `"local"` ⇒ invocations no longer mark this session's memory; `"execution"` ⇒ the same,
     * except that {@link import("./memory.js").MemorySpecInput.execIsExternalContent} can still upgrade
     * the class for a strict deployment (which is why this seat takes the three-value vocabulary and not
     * a single "mine" flag — an execution-shaped tool mounted over MCP must stay inside that knob's
     * reach); `"external"` is an explicit PIN, and pins are not no-ops — a declaration beats the
     * `trustedTools` allowlist, so writing it forecloses the per-name exemption for this server's tools.
     * ABSENT ⇒ the pre-378 behavior byte for byte: the protocol namespace classifies the tools
     * `"external"` (fail-closed). A value outside the vocabulary is refused at the preparation door
     * (`config.mcp_content_class`), never folded to a class.
     *
     * COVERAGE, stated honestly: the class rides this server's own mounted tools. The cross-server
     * resource faces (ListMcpResourcesTool / ReadMcpResourceTool / ReadMcpResourceDirTool) aggregate
     * over every connected server in one call, so they stay `"external"` and still mark — over-marking,
     * the safe direction. A delegated child's pool is a separate static declaration surface
     * ({@link ToolSpec.agentToolPool} entries carry their own `contentOrigin`): a deployment handing
     * this server's tools to children mirrors the value there, and not mirroring it over-marks.
     *
     * TRUST SOURCE — a DEPLOYMENT-plane key. It redefines where the trust boundary runs, which puts it
     * on the same authority plane as {@link RunnerDeps} wiring, not on the request plane. Core sees one
     * `TaskSpec` and cannot tell a deployment-baseline entry from one a request supplied, so any
     * assembly layer that accepts REQUEST-side MCP entries must reject or strip this key from them:
     * "allowed to mount a server" is not "allowed to redefine the deployment's trust boundary", and a
     * caller-supplied `"local"` would otherwise be self-authorization around the session mark. A
     * single-tenant superuser surface (a host reading its own `--mcp-config` file) IS the deployment
     * plane and needs no such gate.
     */
    contentOrigin?: ToolContentOrigin;
    /**
     * The host's identity of THIS MOUNT of the server — a non-empty string (≤ 128 characters) the host
     * minted from the declaration; the engine computes nothing from it and reads nothing off it. When present
     * it rides the revocation probe ({@link McpRevocationLedger.isRevoked}) as the second argument, so the
     * host can tell one mount generation of a server from a re-declared one under the same name. Absent ⇒
     * the probe is asked with the name alone. Any other value refuses this server at its dial
     * (`config.mcp_fingerprint_invalid`).
     */
    fingerprint?: string;
    /**
     * THIS server's startup bound, in whole milliseconds: the handshake (connect + initialize) and the initial tool listing each carry it
     * (the listing as one walk, however many pages). One knob, three seats, read by one function in this order — this member, else the
     * process-level `MCP_TIMEOUT`, else the MCP SDK's own 60 000 ms — so a server that hangs at startup is cut on its own clock while its
     * siblings keep the deployment's. It bounds only that startup phase: a call's own timeout (`MCP_TOOL_TIMEOUT`) is untouched.
     *
     * The range is the one every MCP millisecond bound keeps, 1 000 to 2 147 483 647 (a larger delay is silently rewritten to 1 ms by the
     * timer, a smaller one is a unit slip). Unlike the environment seat — a string a process may clamp and announce — a declaration is typed
     * data, so anything else (a string, a fraction, zero, a negative, NaN, `null`, a number outside the range) refuses THIS server at its
     * dial (`config.mcp_startup_timeout_invalid`; siblings mount) rather than being clamped or read as the default.
     *
     * The bound a dial runs under (this member, else the environment seat) is part of a pooled connection's identity: mounts under one
     * bound lease ONE connection, mounts under different bounds dial their own — so a mount is never held by another mount's clock.
     * The no-run probe has no clock of its own: each startup phase carries this same bound (a caller's `timeoutMs` is an overall ceiling beside it).
     */
    startupTimeoutMs?: number;
}
type ToolAxes = NonNullable<McpServerSpec["toolAxes"]>;
/**
 * The surfaces that declare `toolAxes`, which {@link readToolAxes} names its reading by: an MCP server's keys are the server's
 * remote TOOL names, an A2A peer's keys are the peer's remote SKILL ids.
 */
export type ToolAxesSurface = "mcp" | "a2a";
/**
 * {@link readToolAxes}'s answer. `ok: true` carries the declaration as a PLAIN COPY the reader built from
 * what it judged (never the caller's own object); `toolAxes` is absent when the entry declares nothing — no
 * key at all, or only empty per-tool objects (which the engine reads the same as no declaration). `ok: false`
 * carries one sentence naming the tool (or skill) and the member that did not fit, never a value.
 */
export type ToolAxesRead = {
    ok: true;
    toolAxes?: ToolAxes;
} | {
    ok: false;
    problem: string;
};
/**
 * Where a declaration stops being one: the path from the declaration's root — a list index as a number, a member name as a string — and
 * the clause that says what is there ("it contains itself; …"): a kind and a remedy, never a value the declarer wrote.
 */
export interface DeclarationFault {
    readonly path: readonly (string | number)[];
    readonly problem: string;
}
/** {@link receiveDeclaration}'s answer: the engine's own frozen copy, or where and why the declaration could not be received. */
export type DeclarationRead = {
    readonly ok: true;
    readonly value: unknown;
} | {
    readonly ok: false;
    readonly fault: DeclarationFault;
};
/**
 * A receipt's refusal of a declaration (or of the list that carries declarations), said as a declaration refusal says it. The receipt's
 * path does not say which kind of container each name came from, so a segment of digits alone is read as a list index.
 */
export declare function declarationFaultOf(fault: ReceiptFault): DeclarationFault;
/** What a declaration's own type fixes at one path, beyond being plain data: a string there, or a record of names to strings. */
export interface DeclarationPathRule {
    readonly path: readonly string[];
    readonly holds: "a string" | "names to strings";
    /** The member must be there (a declaration with no value at the path is refused, as one with a value of another kind is). */
    readonly required?: true;
}
/**
 * Per surface, every path its declaration's type fixes beyond plain data — the declarer's `name` (a string, always there) and every record
 * the type writes as `Record<string, string>`: an MCP server's `transport.env` (a stdio server's environment) and `transport.headers` (an
 * HTTP server's headers); an A2A peer's `headers`. A path that is not its surface's (an A2A peer's `transport`) is not judged by another
 * surface's row: it is a member the surface does not read.
 */
export declare const DECLARATION_PATH_RULES: Readonly<Record<ToolAxesSurface, readonly DeclarationPathRule[]>>;
/**
 * The one reading of a declaration a caller hands the engine — an MCP server's or an A2A peer's entry (the snapshot), a `toolAxes`
 * record ({@link readToolAxes}), a lock declaration: the engine's one receipt of a caller's object in its declaration mode, so the
 * value is plain data held to the engine's one depth ({@link MODS_VALUE_DEPTH} levels below it) and every own member is read once, then, when the copy is a record, the declaration's own
 * vocabulary over the copy (a list holds names; no member is named `__proto__`; each path `rules` names holds what its rule says — an
 * entry's rules are its surface's {@link DECLARATION_PATH_RULES}). The copy is the answer — the caller's object is never handed on and
 * never read again. A copy that is not a record is answered as it is, for the reader that expected a record to word.
 */
export declare function receiveDeclaration(declared: unknown, rules?: readonly DeclarationPathRule[]): DeclarationRead;
/**
 * The one reader of a raw `toolAxes` declaration — {@link McpServerSpec.toolAxes} and {@link A2aServerSpec.toolAxes} are the same
 * declaration, and the engine's preparation door, its materialization of an MCP server and of an A2A peer, and every host that
 * assembles the field from JSON ask this same function. `at` names the surface the declaration sits on, because that decides what its
 * keys are called in the sentence: `"mcp"` — the server's remote tools; `"a2a"` — the peer's remote skills. Absent ⇒ `{ ok: true }`
 * (nothing declared). Anything else must be an object of per-tool objects whose members are exactly `effect` /
 * `egress` / `irreversibility` with legal values; a declaration of any other shape, an empty tool name, an
 * unknown member, a word outside the vocabulary or a non-boolean `egress` on ANY one tool refuses the whole
 * declaration (`ok: false`) — the good tools are not kept and nothing is defaulted, since a caller axis is
 * two-way (it can vouch a tool down as well as mark it up) and a silently lost half is a trust root that is
 * not in force. The reader judges SHAPE only; whether the axes contradict each other (`egress` over a
 * non-write effect) is the ingestion's own arithmetic. The declaration is read once, as plain data, by {@link receiveDeclaration} — a
 * Proxy, a map, a class instance, a record built on a prototype or in another realm, a getter that throws, a structure that contains
 * itself, a tool named `__proto__` are refusals that say where they sit (never the thrown text), not a throw — and judged on that copy.
 * `at` is the caller's own word, not the declarer's: one outside {@link ToolAxesSurface} throws `config.invalid_argument` naming the
 * surfaces, whatever is declared.
 */
export declare function readToolAxes(declared: unknown, at: ToolAxesSurface): ToolAxesRead;
/** {@link readToolAxes} for an MCP server's declaration — the entry a host that mounts MCP servers asks. */
export declare function readMcpToolAxes(declared: unknown): ToolAxesRead;
/**
 * The word a sentence about one declaration of the surface `at` names the declarer by — `MCP server`, `A2A peer`. The same row the
 * `toolAxes` refusal below reads, so every sentence the engine writes about a declaration it cannot read calls the declarer one thing.
 */
export declare function declarerWord(at: ToolAxesSurface): string;
/**
 * The refusal an entry's unreadable `toolAxes` becomes (`config.invalid_argument`), ONE sentence for every surface that declares them:
 * the subject is the surface's declarer word and `name` (already quoted and bounded by the caller: `MCP server "db"`, `A2A peer "agent"`),
 * `problem` is {@link readToolAxes}'s own sentence.
 */
export declare function toolAxesRefusal(at: ToolAxesSurface, name: string, problem: string): Error & {
    code: "config.invalid_argument";
};
/** The identity of one mount of a declared server, as the host minted it ({@link McpServerSpec.fingerprint}). */
export interface McpMountIdentity {
    readonly fingerprint: string;
}
/** The host's MCP revocation ledger ({@link RunnerDeps.mcpRevocations}) — declared once, read by every MCP dispatch outlet. */
export interface McpRevocationLedger {
    /** Synchronous. `mount` is passed exactly when the server's declaration carries a `fingerprint`. */
    isRevoked(serverName: string, mount?: McpMountIdentity): boolean;
}
/**
 * Definition of one A2A (agent-to-agent protocol) PEER to talk to for the duration of one task.
 *
 * The peer is a remote AGENT, not a data source: it acts on its own side. That single fact sets the
 * defaults — every skill this peer advertises mounts with `egress: true` and `effect: "write"` (ruled
 * 2026-08-03), so it registers the approval gate and is never auto-allowed on a no-policy deployment,
 * and its replies reach the model inside an untrusted-data fence. {@link toolAxes} is the only trusted
 * way down from those defaults (design F: the caller is the trust root).
 *
 * Skills mount as `a2a__<peer>__<skill>` (the protocol table's second namespace).
 */
export interface A2aServerSpec {
    /** Stable local name for this peer; it becomes the namespace segment of every mounted tool name. */
    name: string;
    /** The peer's service URL. Doubles as the origin the well-known agent-card paths resolve against, and
     *  as the JSON-RPC endpoint when the card does not name a different one. */
    url: string;
    /** Explicit agent-card location, when the peer does not publish at a well-known path. Set ⇒ it is used
     *  ALONE (no well-known probing behind the operator's back). */
    cardUrl?: string;
    /** Static headers sent on every request to this peer (e.g. an auth bearer). They travel only to the
     *  declared origins (`url`, `cardUrl`): a card naming an endpoint on another origin refuses the peer
     *  (`config.protocol_endpoint_unbound`), and a redirect is not followed. */
    headers?: Record<string, string>;
    /**
     * Per-task **end-user principal** header (design/62), same contract as the MCP side: when set, the
     * Runner injects the running task's authenticated {@link TaskSpec.principal} under this header name on
     * every call to this peer, so the peer can enforce per-user authorization. Absent principal ⇒ the
     * header is not sent (the peer must then default to deny/public, never admin). A static entry in
     * {@link headers} under the same name in any case refuses the peer (`config.protocol_header_collision`).
     * The principal is Runner-held: the model can neither read nor set it.
     */
    principalHeader?: string;
    /** Optional allowlist of skill ids to expose (others are not mounted). */
    allowSkills?: string[];
    /**
     * Caller-side per-skill safety-axis overrides, keyed by the peer's REMOTE skill id. The CALLER is the
     * trust root, so this may LOWER the fail-closed default (`egress:true` + `effect:"write"`) as well as
     * raise it — e.g. `{ egress: false, effect: "read" }` vouches that a skill only reads. Note that
     * lowering `effect` WITHOUT clearing `egress` is a contradiction prepare-task refuses by design (an
     * external write must be repeat-unsafe).
     *
     * THE SHAPE IS JUDGED, NOT TRUSTED, by the same reader as {@link McpServerSpec.toolAxes} ({@link readToolAxes} with `at: "a2a"`) and
     * with the same disposition: a task's preparation door runs it on every peer of `TaskSpec.a2a`, and a declaration it cannot read
     * refuses the whole prepare (`config.invalid_argument`, subject `A2A peer "<name>"`) before any peer is dialed — one bad skill refuses
     * the task, a bad key is never dropped and a bad word never defaults. The materialization entrance (`materializeA2aTools`, the library
     * entrance) asks it once per peer, when it reads that peer's declaration: there a declaration it cannot read fails THAT peer's dial
     * (never dialed, a warning whose cause is the same refusal), its siblings unaffected; a refresh does not ask again, it dials the copy
     * that was judged (a peer refused at the entrance is refused again by every refresh, from the stored refusal).
     */
    toolAxes?: Record<string, {
        effect?: ToolEffect;
        egress?: boolean;
        irreversibility?: "always" | "never";
    }>;
}
/**
 * design/99 §E23 — an INBOUND MCP elicitation request (a connected server asking the END USER for input
 * mid-tool-call). Handed to the deployment's {@link RunnerDeps.onElicit} seam. **UNTRUSTED**: `message` /
 * `requestedSchema` / `url` are SERVER-controlled — core never interprets `requestedSchema`; a consumer that
 * shows `message` to a human MUST fence it (`delimitUntrusted`).
 */
export interface McpElicitRequest {
    /** The {@link McpServerSpec.name} of the server that issued the request. */
    server: string;
    /** The server's human-facing prompt (UNTRUSTED — fence before display). */
    message: string;
    /** Form mode: the server's requested input schema (a flat object of scalars). OPAQUE to core. */
    requestedSchema?: unknown;
    /**
     * URL mode: a server-controlled URL the user is asked to visit (UNTRUSTED — a phishing/social-engineering
     * surface; a consumer MUST scrutinize/fence it before showing it). **Inactive**: core advertises FORM mode
     * only, so the SDK rejects url-mode requests before this seam — the field is never populated today.
     *
     * Where url mode is heading (MCP revision `2026-07-28`), because the earlier note here ("reserved for a
     * future url-mode opt-in") pointed at machinery that no longer exists: the revision REMOVES the
     * `2025-11-25` url-mode correlator (`elicitationId`) and the `notifications/elicitation/complete`
     * notification that went with it. A url interaction is instead carried by the revision's multi-round-trip
     * request flow — the server answers with an input-required result, the client RETRIES the original
     * request, and the server correlates across retries through its OWN opaque request state rather than a
     * client-visible id. The one thing both shapes agree on is the server-supplied URL itself, which is what
     * this field holds. So the field stays; anything that would have hung off the removed correlator must not
     * be added here without re-reading the protocol revision core actually speaks.
     */
    url?: string;
    /** The running task's authenticated end-user (design/62), if any — for routing the prompt to the right human. */
    principal?: string;
}
/** design/99 §E23 — the deployment's answer to an {@link McpElicitRequest} (returned to the MCP server). */
export interface McpElicitResponse {
    action: "accept" | "decline" | "cancel";
    /** Submitted values (accept only); core passes them through opaquely, never validated against the schema. */
    content?: Record<string, string | number | boolean | string[]>;
}
/**
 * design/99 §E23 — the LIVE-ONLY inbound-elicitation seam. A deployment provides it (e.g. the sema shell
 * prompts the user at the terminal) and returns the answer SYNCHRONOUSLY; core replies to the server on the
 * still-open connection. Absent ⇒ no server is advertised the elicitation capability (fail-closed). Not a
 * durable suspend — a crash/replica-change loses an in-flight elicitation (acceptable for an interactive shell).
 *
 * 🔴 THROTTLING IS THE DEPLOYMENT'S JOB: once a server is opted in, it may issue elicitations at any frequency
 * (one per tool call, or many) — core imposes NO rate/count limit (an elicitation is not a tool call and does
 * not ride the policy gate). `onElicit` is the choke point: throttle, aggregate, or `decline`/`cancel` an
 * over-eager or untrusted server here (the request's `AbortSignal` is forwarded so a deadline can cancel it).
 */
export type OnElicit = (req: McpElicitRequest, signal?: AbortSignal) => Promise<McpElicitResponse>;
export {};
