import type { AtribRecord } from './types.js'; /** SEP-2133 extension identifier. Frozen: breaking changes require a new id. */ export declare const ATTRIBUTION_EXTENSION_ID = "dev.atrib/attribution"; /** Settings-object `version` published by this implementation. */ export declare const ATTRIBUTION_EXTENSION_VERSION = "0.1"; /** * Core-reserved `_meta` key under which per-request client capabilities * travel in the stateless MCP model (extension spec §4.2). */ export declare const MCP_CLIENT_CAPABILITIES_META_KEY = "io.modelcontextprotocol/clientCapabilities"; /** * DNS labels reserved for official MCP extensions (SEP-2133). A vendor * prefix containing any of these labels is invalid for unofficial extensions. */ export declare const RESERVED_EXTENSION_PREFIX_LABELS: ReadonlySet; /** Receipt verbosities a client can request (extension spec §4.2 `accept`). */ export declare const ATTRIBUTION_ACCEPT_VALUES: readonly ["token", "record"]; export type AttributionAcceptValue = (typeof ATTRIBUTION_ACCEPT_VALUES)[number]; /** Closed queue-status enum for `receipt.log_submission` (extension spec §6.3). */ export declare const ATTRIBUTION_LOG_SUBMISSION_STATUSES: readonly ["queued", "submitted", "disabled", "failed"]; export type AttributionLogSubmissionStatus = (typeof ATTRIBUTION_LOG_SUBMISSION_STATUSES)[number]; /** * Every settings field recognized at v0.1 across BOTH sides (client `accept` * plus the server advisory fields). Unknown settings fields MUST be ignored * (extension spec §4.1/§4.2 forward compatibility). */ export declare const ATTRIBUTION_KNOWN_SETTINGS_FIELDS: ReadonlySet; /** Server capability settings object (extension spec §4.1). Advisory beyond `version`. */ export interface AttributionServerSettings { /** REQUIRED. Settings version, `"0.1"` for this document. */ version: string; /** atrib event-type short names this server signs (e.g. `"tool_call"`). */ signs?: string[]; /** Receipt verbosities the server can produce. */ receipts?: AttributionAcceptValue[]; /** Advisory disclosure posture per atrib spec §8.3. */ disclosure?: { args?: string; result?: string; tool_name?: string; }; /** base64url-encoded 32-byte Ed25519 public key the server expects to sign with. */ creator_key?: string; /** Transparency-log base URLs records are submitted to. */ logs?: string[]; /** Identity-claim directory base URL for the creator key. */ directory?: string; } /** Client capability settings object (extension spec §4.2). */ export interface AttributionClientSettings { /** REQUIRED. Settings version, `"0.1"`. */ version: string; /** Receipt verbosity negotiation. Defaults to `["token"]` when absent. */ accept?: AttributionAcceptValue[]; } /** Outcome of validating a settings object per extension spec §4. */ export interface AttributionSettingsValidation { /** Whether the peer validly declared the extension. */ declared: boolean; /** The declared settings `version` string, when declared. */ negotiatedVersion?: string; /** Effective `accept` after unknown-value filtering; defaults to `['token']`. */ effectiveAccept: string[]; /** Unknown settings fields, sorted (ignored per forward compatibility). */ ignoredSettingsFields: string[]; /** Unrecognized string `accept` values (ignored). */ ignoredAcceptValues: string[]; } /** * Validate an extension identifier per the SEP-2133 grammar * (`{vendor-prefix}/{extension-name}`, reverse-DNS prefix, no reserved * labels). Extension spec §3. */ export declare function validateExtensionIdentifier(identifier: string): boolean; /** * Validate a settings object per extension spec §4. A settings object * missing `version` (or whose `version` is not a non-empty string) is * malformed: the peer is treated as NOT having declared the extension, and * this MUST NOT produce a protocol error. Unknown settings fields and * unknown `accept` values are ignored (forward compatibility); an `accept` * array containing no recognized value is equivalent to `["token"]`. An * unrecognized `version` under this identifier is still a valid declaration: * the identifier, not the version string, is the compatibility unit. */ export declare function validateAttributionSettings(settings: unknown): AttributionSettingsValidation; /** * Per-request client declaration detection: reads * `_meta["io.modelcontextprotocol/clientCapabilities"].extensions` and * validates the `dev.atrib/attribution` settings object. * * NOTE: this is the RAW detector — pathological inputs (e.g. a throwing * Proxy for `requestMeta`) propagate their exception so callers on the * result path can abort BEFORE mutating anything, preserving byte-identical * passthrough per the degradation corpus. Hosts that want the §5.8-safe * form should call {@link declaresExtension} instead. */ export declare function detectClientDeclaration(requestMeta: unknown): AttributionSettingsValidation; /** Options for {@link declaresExtension}. */ export interface DeclaresExtensionOptions { /** * Legacy protocol versions (≤ 2025-11-25) carry client capabilities in the * `initialize` request instead of per-request `_meta`. Pass the session's * `initialize` `capabilities` object here (the object containing the * `extensions` map); a declaration there applies to every request on the * session (extension spec §4.2 / §6.1). Per-request declarations, when * validly present, take precedence. */ initializeCapabilities?: unknown; } /** * §6.1 negotiation gating check, §5.8-safe: whether the client declared * `dev.atrib/attribution` for this request, either per-request under the * `io.modelcontextprotocol/clientCapabilities` `_meta` key or (legacy * protocol versions) in the session's `initialize` capabilities. * * A missing, malformed, or non-object declaration — or any exception while * reading either carrier — is treated as **undeclared**; never an error. */ export declare function declaresExtension(requestMeta: unknown, options?: DeclaresExtensionOptions): AttributionSettingsValidation; /** The v0.1 request block under `_meta["dev.atrib/attribution"]`. */ export interface AttributionRequestBlock { /** §1.5.2 propagation token, ≤87 chars. */ token?: string; /** Raw 32-lowercase-hex session anchor (§1.5.1), carried explicitly. */ context_id?: string; } /** Input for {@link buildAttributionMetaBlock}. */ export interface BuildAttributionMetaBlockInput { /** Pre-encoded §1.5.2 propagation token. Mutually exclusive with `record`. */ token?: string; /** Signed record to derive the token from (via `encodeToken`). */ record?: AtribRecord; /** Explicit 32-lowercase-hex context_id to carry. */ contextId?: string; } /** * Build the prefixed `_meta` fragment a client attaches to a request * (extension spec §5): `{ "dev.atrib/attribution": { token?, context_id? } }`. * * Malformed inputs are dropped with an `atrib:` warning, never thrown: * a token that does not decode to two 32-byte parts is omitted; a * `contextId` that is not exactly 32 lowercase hex characters is omitted. * Returns `undefined` when no valid field remains (callers then attach * nothing — the legacy carriers still travel). * * Clients SHOULD write the legacy carriers alongside this block so * non-adopting servers keep chaining (extension spec §5.1); this helper * builds only the prefixed block and never touches the legacy keys. */ export declare function buildAttributionMetaBlock(input: BuildAttributionMetaBlockInput): { [ATTRIBUTION_EXTENSION_ID]: AttributionRequestBlock; } | undefined; export type AttributionTokenSource = 'extension' | 'meta-atrib' | 'tracestate' | 'x-atrib-chain' | null; /** Outcome of Ladder 1 resolution. */ export interface AttributionTokenResolution { /** Which carrier resolved, or null when all carriers are absent/malformed. */ source: AttributionTokenSource; /** Lowercase hex record_hash (no `sha256:` prefix) from the winning token. */ recordHashHex?: string; /** base64url creator_key from the winning token. */ creatorKey?: string; /** * True when the extension key and a legacy carrier decode to DIFFERENT * tokens (extension wins; the caller SHOULD have seen an `atrib:` warning). */ conflictWarning: boolean; } /** * Canonical Ladder 1 resolution (extension spec §5.2 / spec §1.5.4.1): * * `_meta["dev.atrib/attribution"].token` > `_meta.atrib` * > `tracestate` `atrib=` entry > `_meta["X-Atrib-Chain"]` * * Lenient parse: a malformed extension token falls through to the next * carrier; malformation is never an error. On conflict between the extension * key and a legacy carrier, the extension key wins and an `atrib:` warning * is logged. When nothing resolves, `source` is null and chain-root * resolution continues down the §1.2.3.1 / D067 ladder — this function * refines only the inbound-token rung and never replaces `resolveChainRoot`. */ export declare function resolveInboundToken(requestMeta: unknown): AttributionTokenResolution; export type AttributionContextSource = 'argument' | 'extension' | 'traceparent' | 'env-registry-fallthrough'; /** Outcome of Ladder 2 resolution. */ export interface AttributionContextResolution { /** Resolved 32-hex context_id, or undefined at the transport layer. */ contextId?: string; /** * Which rung resolved. `'env-registry-fallthrough'` means no per-request * carrier resolved: producer-local D078/D083 env-and-file discovery applies * next (its internal ordering stays defined by those decisions). */ source: AttributionContextSource; /** True when a lower carrier disagreed with the winner (warning logged). */ mismatchWarning: boolean; } /** * Canonical Ladder 2 resolution (extension spec §5.3 / spec §1.5.4.1): * * explicit context_id tool argument * > `_meta["dev.atrib/attribution"].context_id` * > `_meta.traceparent` trace-id * > D078/D083 env-file registry (producer-side, not resolved here) * > undefined * * An explicit tool argument always wins (application intent beats transport * metadata); an extension-block `context_id` that is not exactly 32 * lowercase hex is ignored and falls through — never an error. */ export declare function resolveContextIdentity(explicitArgument: unknown, requestMeta: unknown): AttributionContextResolution; /** The `receipt` object inside the result block (extension spec §6.2). */ export interface AttributionReceipt { /** `"sha256:" + lowercase hex of sha256(JCS(signed record))`. */ record_hash: string; /** The record's signer (base64url 32-byte Ed25519 public key). */ creator_key: string; /** The record's context_id. */ context_id: string; /** atrib event-type short name (e.g. `"tool_call"`) or the full URI. */ event_type: string; /** The record's chain_root. */ chain_root: string; /** Queue status at response time — never an awaited proof (§5.3.5). */ log_submission: AttributionLogSubmissionStatus; } /** The v0.1 result block under `result._meta["dev.atrib/attribution"]`. */ export interface AttributionResultBlock { /** Propagation token of the record named by the receipt. */ token: string; receipt: AttributionReceipt; /** OPTIONAL full signed record (only when the client's accept includes "record"). */ record?: AtribRecord; } /** Options for {@link buildAttributionReceipt}. */ export interface BuildAttributionReceiptOptions { /** Attach the full signed record body (extension spec §6.4). Default false. */ includeRecord?: boolean; /** * Queue status at response time (extension spec §6.3). Defaults to * `'queued'`. Use `'disabled'` for D100 sign-without-submission postures. * This is reporting only: callers MUST NOT await log submission before * returning the tool result. */ logSubmission?: AttributionLogSubmissionStatus; } /** * Build the gated result block for a record the server has ALREADY signed * locally (extension spec §6.2). Synchronous by construction: it reports the * submission queue's status, never awaits submission or inclusion proofs * (§5.3.5 / critical invariant 4). Attaching the full record is safe by * construction — records carry commitments, never payloads (§8.3). * * Gating is the CALLER's obligation (or use {@link applyAttributionReceipt}): * this block may be written to `result._meta` only when the client declared * the extension on that request. */ export declare function buildAttributionReceipt(record: AtribRecord, options?: BuildAttributionReceiptOptions): AttributionResultBlock; /** Options for {@link applyAttributionReceipt}. */ export interface ApplyAttributionReceiptOptions { /** Queue status to report (see {@link BuildAttributionReceiptOptions}). */ logSubmission?: AttributionLogSubmissionStatus; /** Legacy `initialize`-time declaration carrier (see {@link DeclaresExtensionOptions}). */ initializeCapabilities?: unknown; } /** * Gated receipt write for an already-signed record: emits the * `dev.atrib/attribution` block into `result._meta` ONLY when the client * declared the extension on that request (extension spec §6.1). §5.8-safe: * never throws, and on any failure the result object is left exactly as it * was. Returns true iff the block was written. * * This helper writes only the prefixed block. The legacy unprefixed result * keys are written unconditionally elsewhere (`writeOutboundContext`), * unchanged, regardless of negotiation state. */ export declare function applyAttributionReceipt(result: Record, requestMeta: unknown, record: AtribRecord, options?: ApplyAttributionReceiptOptions): boolean; /** Options for {@link extendResultWithAttribution}. */ export interface ExtendResultWithAttributionOptions { /** Queue status to report (see {@link BuildAttributionReceiptOptions}). */ logSubmission?: AttributionLogSubmissionStatus; /** Legacy `initialize`-time declaration carrier (see {@link DeclaresExtensionOptions}). */ initializeCapabilities?: unknown; } /** * §5.8-conformant reference composition of the full result path: sign, * detect the client declaration, write the legacy outbound keys, then the * gated extension block. Any failure — signing, capability read, carriage — * leaves the tool result byte-identical to passthrough and never throws to * the caller (degradation corpus contract: on failure NOT EVEN the legacy * keys are added by the failed attempt). * * Producers that sign elsewhere (e.g. the `@atrib/mcp` middleware, which * runs `writeOutboundContext` in its commit path) should use * {@link applyAttributionReceipt} instead. */ export declare function extendResultWithAttribution(result: Record, requestMeta: unknown, sign: () => AtribRecord, options?: ExtendResultWithAttributionOptions): void; /** Outcome of {@link verifyAttributionReceipt}. */ export interface AttributionReceiptVerification { /** True iff the block is structurally well-formed and internally consistent. */ valid: boolean; /** * Fields that disagreed (`'token'`, `'record_hash'`, `'creator_key'`, * `'context_id'`, `'chain_root'`, `'log_submission'`), or `['malformed']` * when the block is not structurally a v0.1 result block. */ mismatched: string[]; } /** * Consumer-side receipt integrity check (extension spec §6.2): the token, * `record_hash`, and `creator_key` must agree with each other and — when the * full record body is attached — recompute from the record's canonical * bytes. A consumer that detects an internal inconsistency MUST treat the * receipt as invalid and discard it; receipt invalidity never invalidates * the tool result itself. * * This checks internal consistency only. A receipt is a claim of local * signing, not a proof: callers wanting Tier-3 assurance additionally verify * the attached record's Ed25519 signature (`verifyRecord`) and, where * required, log inclusion via an independently fetched proof bundle. */ export declare function verifyAttributionReceipt(block: unknown): AttributionReceiptVerification; //# sourceMappingURL=extension-attribution.d.ts.map