// Generated from types/*.ts — do not edit. // Regenerate with: npm run generate:typescript /** * Common Command Types — Connection-level commands (handshake, ping, * reconnect, subscribe/unsubscribe, dispatchAction) plus the filesystem * `resource*` family and `authenticate` that aren't specific to any one * state channel. * * @module common/commands */ import type { URI, Snapshot } from './state.js'; import type { ActionEnvelope, StateAction } from './actions.js'; import type { AutomationRunCancelRequestedAction } from '../channels-automation-run/actions.js'; import type { AutomationCreateRequestedAction } from '../channels-automation/actions.js'; import type { AutomationSchedule, AutomationScheduleTrigger, AutomationEntry, AutomationState, } from '../channels-automation/state.js'; import type { TelemetryCapabilities } from '../channels-otlp/state.js'; // ─── BaseParams ────────────────────────────────────────────────────────────── /** * Base shape every command's params extends. * * `channel` identifies the channel the command targets, mirroring the * `channel` field on every protocol notification. For commands that operate * on a specific channel (a session, terminal, or changeset), `channel` is * that channel's URI. For commands that are connection-level rather than * channel-scoped (e.g. {@link InitializeParams | `initialize`}, * {@link PingParams | `ping`}, {@link ListSessionsParams | `listSessions`}, * the `resource*` filesystem commands, and {@link AuthenticateParams | * `authenticate`}), the params type narrows `channel` to the literal * root URI `'ahp-root://'`. * * This invariant lets implementations route every incoming message — * request, response, or notification — by inspecting `params.channel` * without needing to know the per-method param shape. * * @category Commands */ export interface BaseParams { /** Channel URI this command targets. */ channel: URI; /** * Optional JSON-serializable metadata associated with this request. * Receivers MUST ignore keys they do not understand. */ _meta?: Record; } // ─── Pagination ────────────────────────────────────────────────────────────── /** * Cursor-based pagination inputs, mixed into the params of any list command * that can page a large result set (e.g. {@link ListSessionsParams | * `listSessions`}). The paired output is {@link PaginatedResult}. * * Pagination is **opaque and cursor-based**, mirroring the shape `fetchTurns` * already uses for chat history: the server owns the ordering and keyset, and * the client walks pages by echoing the cursor from the previous * {@link PaginatedResult.nextCursor} back on the next request. * * The contract every paginated command shares: * * - To fetch the first page, omit `cursor`. Supply `limit` to bound the page. * - If the result carries a {@link PaginatedResult.nextCursor}, more entries * exist — pass it back as `cursor` to fetch the following page. A missing * `nextCursor` signals the end of the collection. * - Cursors are **server-defined and opaque**: clients MUST NOT parse, modify, * or persist them across connections. An unrecognised cursor SHOULD be * rejected with an `InvalidParams` error. * - Pagination is **fully additive**: a client that omits `limit`/`cursor` and * ignores `nextCursor` sees the pre-pagination behaviour (subject to any * server-imposed cap), and a server that does not paginate ignores the inputs * and returns everything in a single page. * * @category Commands */ export interface PaginatedParams { /** * Maximum number of entries to return in this page. The server SHOULD respect * this bound but MAY return fewer entries and MAY impose its own upper cap. * Omit to let the server choose the page size. */ limit?: number; /** * Opaque pagination cursor from a previous {@link PaginatedResult.nextCursor}. * Omit to fetch the first page. Cursors are server-defined and MUST be treated * as opaque — do not parse, modify, or persist them across connections. An * unrecognised cursor SHOULD be rejected with an `InvalidParams` error. */ cursor?: string; } /** * Cursor-based pagination output, extended by the result of any list command * that can page a large result set (e.g. {@link ListSessionsResult | * `listSessions`}). See {@link PaginatedParams} for the full pagination * contract shared by every paginated command. * * @category Commands */ export interface PaginatedResult { /** * Opaque cursor for the next page. Present when more entries exist beyond the * returned page; absent signals the end of the collection. Pass it back as * {@link PaginatedParams.cursor} to fetch the following page. */ nextCursor?: string; } // ─── initialize ────────────────────────────────────────────────────────────── /** * Identifies a protocol implementation — the software (and build) on one end * of the connection, as distinct from the {@link AgentInfo | agent persona} it * hosts. Carried as {@link InitializeParams.clientInfo | `clientInfo`} on the * client side and {@link InitializeResult.serverInfo | `serverInfo`} on the * server side, mirroring LSP's `clientInfo`/`serverInfo` and MCP's * `Implementation`. * * This is **informational only**: it exists for logging, telemetry, an * about/status affordance, and — as a last resort — a known-issue workaround * for a specific buggy build. It is **not** a feature-detection mechanism. * Feature availability stays with the capability model * ({@link ClientCapabilities} and the various `*.capabilities` declarations); * implementations SHOULD NOT gate protocol behaviour on parsing * {@link Implementation.version | `version`}. * * @category Commands */ export interface Implementation { /** Implementation name, e.g. a product or package identifier. */ name: string; /** * Implementation version. A [SemVer](https://semver.org) string is * recommended but not required. */ version?: string; /** Optional human-readable display name. */ title?: string; } /** * Establishes a new connection and negotiates the protocol version. * This MUST be the first message sent by the client. * * @category Commands * @method initialize * @direction Client → Server * @messageType Request * @version 1 * @see {@link /specification/lifecycle | Lifecycle} for the full handshake flow. */ export interface InitializeParams extends BaseParams { channel: 'ahp-root://'; /** * Protocol versions the client is willing to speak, ordered from most * preferred to least preferred. Each entry is a [SemVer](https://semver.org) * `MAJOR.MINOR.PATCH` string (e.g. `"0.1.0"`). * * The server selects one entry and returns it as `InitializeResult.protocolVersion`. * If the server cannot speak any of the offered versions, it MUST return * error code `-32005` (`UnsupportedProtocolVersion`) with required * `UnsupportedProtocolVersionErrorData` containing `supportedVersions`. */ protocolVersions: string[]; /** Unique client identifier */ clientId: string; /** * Optional identity of the client implementation (name and version). * Informational only — see {@link Implementation} for how it may and may not * be used. Distinct from {@link InitializeParams.clientId | `clientId`}, * which is an opaque per-connection identifier used for reconnection, not a * human-readable implementation name. */ clientInfo?: Implementation; /** URIs to subscribe to during handshake */ initialSubscriptions?: URI[]; /** * IETF BCP 47 language tag indicating the client's preferred locale * (e.g. `"en-US"`, `"ja"`). The server SHOULD use this to localise * user-facing strings such as confirmation option labels. */ locale?: string; /** * Optional client capability declarations. * * Servers SHOULD only advertise features whose corresponding client * capability is set here. Absent means "not declared" — the server * MUST assume the client does not support the feature. */ capabilities?: ClientCapabilities; } /** * Optional capabilities a client declares during `initialize`. * * Each field is a presence flag: an empty object `{}` means "supported", * absence means "not supported". Sub-fields on individual capabilities * are reserved for future per-capability options. * * @category Commands */ export interface ClientCapabilities { /** * Client can render * [MCP Apps](https://github.com/modelcontextprotocol/ext-apps) — i.e. * it can host the View sandbox, run the `ui/*` protocol against it, * and forward `mcp://`-channel traffic on the App's behalf. * * Hosts SHOULD only populate * {@link McpServerCustomization.mcpApp | `McpServerCustomization.mcpApp`} * (and expose the corresponding * {@link McpServerCustomization.channel | `mcp://` channel}) when this * capability is declared. Clients that omit it MUST treat * App-bearing tool calls as ordinary MCP tool calls. */ mcpApps?: Record; } /** * Result of the `initialize` command. * * `protocolVersion` is the version the server has selected from the client's * `protocolVersions` list. The client and server MUST use this version for * the rest of the connection. If the server cannot speak any of the offered * versions it MUST return error code `-32005` (`UnsupportedProtocolVersion`) * with required `UnsupportedProtocolVersionErrorData` containing * `supportedVersions`, instead of a result. */ export interface InitializeResult { /** * Protocol version selected by the server. MUST be one of the entries in * `InitializeParams.protocolVersions`. Formatted as a [SemVer](https://semver.org) * `MAJOR.MINOR.PATCH` string (e.g. `"0.1.0"`). */ protocolVersion: string; /** Current server sequence number */ serverSeq: number; /** * Optional identity of the server implementation (name and version). * Informational only — see {@link Implementation} for how it may and may not * be used. Whereas {@link InitializeResult.protocolVersion | `protocolVersion`} * identifies the negotiated protocol, `serverInfo` identifies the host * software behind it. */ serverInfo?: Implementation; /** * Optional implementation-specific extension metadata advertised by the host. * * Hosts and clients MAY agree on namespaced keys for capabilities that are not * part of the standardized protocol. Clients MUST ignore keys they do not * understand. Capabilities needed for interoperable behavior SHOULD use typed * fields on {@link InitializeResult} instead. */ _meta?: Record; /** Snapshots for each `initialSubscriptions` URI */ snapshots: Snapshot[]; /** Suggested default directory for remote filesystem browsing */ defaultDirectory?: URI; /** * Characters that, when typed in a {@link Message} input, SHOULD cause * the client to issue a `completions` request with * {@link CompletionItemKind.UserMessage}. Typically includes characters like * `'@'` or `'/'`. */ completionTriggerCharacters?: string[]; /** * Prefix that the host recognizes at the start of a user {@link Message.text} * as a shorthand for executing the remainder as a terminal command. Currently * the standardized convention is `"!"`; absence means the host does not * support command prefixes. */ terminalCommandPrefix?: string; /** * OTLP telemetry channels the host emits, if any. Each populated field is * either a literal `ahp-otlp:` channel URI or an RFC 6570 URI template a * client expands before subscribing (currently only the `logs` channel * defines a template variable, `{level}`, for subscriber-side severity * filtering). Clients MAY ignore signals they cannot process. * * @see {@link /specification/telemetry-channel | Telemetry Channel} */ telemetry?: TelemetryCapabilities; /** * Host-owned automation support. Presence means clients may subscribe to * `ahp-automations://` for {@link AutomationState}; absence means the * host does not expose an automation catalogue or automation commands. * * @see {@link /guide/automations | Automations Guide} */ automations?: AutomationCapabilities; } /** * Automation features supported by this host authority. * * The presence of this object advertises the baseline `ahp-automations://` * catalogue. Optional fields describe additional host features and * restrictions. * * Capabilities describe implementation support. * {@link AutomationEntry.operations} remains authoritative for which * definition mutations are currently allowed on a particular automation. * * @category Commands */ export interface AutomationCapabilities { /** Present when clients may dispatch {@link AutomationCreateRequestedAction}. */ create?: AutomationCreateCapability; /** Present when definitions may contain {@link AutomationScheduleTrigger | schedule triggers}. */ schedules?: AutomationScheduleCapabilities; /** * Present when clients may request cancellation of `pending` or `running` * automation runs. */ runCancellation?: AutomationRunCancellationCapability; /** * Maximum terminal entries retained in {@link AutomationEntry.runs}. Active * runs are not counted toward the limit. Absence means the retention limit is * implementation-defined. */ runHistoryLimit?: number; } /** * Presence capability for {@link AutomationCreateRequestedAction | * `automation/createRequested`}. * * The empty object means "supported"; fields are reserved for future * create-specific options. * * @category Commands */ export interface AutomationCreateCapability {} /** * Host restrictions on portable {@link AutomationSchedule} triggers. * * The cron grammar itself is fixed by AHP. Hosts MUST accept every expression * in that grammar unless it violates an advertised interval restriction. * * @category Commands */ export interface AutomationScheduleCapabilities { /** * Smallest permitted interval between consecutive occurrences produced by * {@link AutomationSchedule.expression}. Omission means no restriction beyond * the cron format's one-minute resolution. */ minIntervalMinutes?: number; } /** * Presence capability for {@link AutomationRunCancelRequestedAction | * `automationRun/cancelRequested`}. * * The empty object means "supported." Clients may dispatch the action for * `pending` or `running` runs; terminal runs cannot be cancelled. * * @category Commands */ export interface AutomationRunCancellationCapability {} // ─── ping ──────────────────────────────────────────────────────────────────── /** * Verifies that the AHP connection is still alive and keeps it from being * closed by idle-timeout intermediaries (proxies, load balancers, etc.). * * The server MUST respond regardless of whether the client has completed * `initialize` or holds any subscriptions. Ping carries no payload in either * direction; the response itself is the signal. * * @category Commands * @method ping * @direction Client → Server * @messageType Request * @version 1 */ export interface PingParams extends BaseParams { channel: 'ahp-root://'; } // ─── reconnect ─────────────────────────────────────────────────────────────── /** * Discriminant for reconnect result types. * * @category Commands * @exhaustive */ export const enum ReconnectResultType { Replay = 'replay', Snapshot = 'snapshot', } /** * Re-establishes a dropped connection. The server replays missed actions or * provides fresh snapshots. * * @category Commands * @method reconnect * @direction Client → Server * @messageType Request * @version 1 * @see {@link /specification/lifecycle | Lifecycle} for details. */ export interface ReconnectParams extends BaseParams { channel: 'ahp-root://'; /** Client identifier from the original connection */ clientId: string; /** Last `serverSeq` the client received */ lastSeenServerSeq: number; /** URIs the client was subscribed to */ subscriptions: URI[]; } /** * Reconnect result when the server can replay from the requested sequence. * * The server MUST include all replayed data in the response. */ export interface ReconnectReplayResult { /** Discriminant */ type: ReconnectResultType.Replay; /** Missed action envelopes since `lastSeenServerSeq` */ actions: ActionEnvelope[]; /** * URIs from `ReconnectParams.subscriptions` that the server cannot resume. * This includes resources that no longer exist (e.g. disposed sessions or * terminals) as well as resources the client is no longer permitted to * observe. Clients SHOULD drop these from their local subscription set. */ missing: URI[]; } /** * Reconnect result when the gap exceeds the replay buffer. */ export interface ReconnectSnapshotResult { /** Discriminant */ type: ReconnectResultType.Snapshot; /** Fresh snapshots for each subscription */ snapshots: Snapshot[]; } /** Result of the `reconnect` command. */ export type ReconnectResult = ReconnectReplayResult | ReconnectSnapshotResult; // ─── subscribe ─────────────────────────────────────────────────────────────── /** * Subscribe to a URI-identified channel. * * A channel MAY have state associated with it (e.g. root, sessions, * terminals) or be stateless (pure pub/sub for streaming data). For * state-bearing channels the result includes a snapshot; for stateless * channels `snapshot` is omitted. * * @category Commands * @method subscribe * @direction Client → Server * @messageType Request * @version 1 * @see {@link /specification/subscriptions | Subscriptions} */ export interface SubscribeParams extends BaseParams { /** * Optional delivery preferences for this subscription. * * Servers MAY use these preferences to buffer and coalesce high-frequency * updates while preserving the same reduced state. Omit this field for the * server's default delivery behavior. */ delivery?: SubscriptionDeliveryOptions; /** * Optional client-requested shape for the returned snapshot. * * Servers that do not understand a requested view ignore it and return their * default snapshot. Clients MUST tolerate receiving more state than requested. */ view?: SubscribeView; } /** * Optional client-requested shape for a subscription snapshot. * * @category Commands */ export interface SubscribeView { /** * Advisory number of most-recent completed turns to expose in a chat * snapshot. * * Servers MAY return more or fewer turns than requested. When omitted, the * host MUST return all retained turns. When older turns remain available, the * returned {@link ChatState} carries `turnsNextCursor`; clients pass that * cursor to `fetchTurns` to ask the host to page more turns into the chat * state. */ turns?: number; } /** * Advisory delivery preferences for a single subscription. * * @category Commands */ export interface SubscriptionDeliveryOptions { /** * Maximum time, in milliseconds, that the server may intentionally delay * delivery while buffering/coalescing updates for this subscription. * * A value of `0` requests immediate delivery with no intentional coalescing. */ maxLatencyMs?: number; } /** * Result of the `subscribe` command. * * `snapshot` is present when the subscribed channel has associated state, and * absent for stateless channels. */ export interface SubscribeResult { /** Snapshot of the subscribed channel's state (omitted for stateless channels) */ snapshot?: Snapshot; } // ─── unsubscribe ───────────────────────────────────────────────────────────── /** * Stop receiving updates for a channel. * * @category Commands * @method unsubscribe * @direction Client → Server * @messageType Notification * @version 1 * @see {@link /specification/subscriptions | Subscriptions} */ export interface UnsubscribeParams { /** Channel URI to unsubscribe from */ channel: URI; } // ─── dispatchAction ────────────────────────────────────────────────────────── /** * Fire-and-forget action dispatch (write-ahead). The client applies actions * optimistically to local state and the server echoes them back as an * {@link ActionEnvelope} once accepted. * * The client → server method is named `dispatchAction`; the server's reply * arrives on the server → client `action` notification (params: * {@link ActionEnvelope}). * * @category Commands * @method dispatchAction * @direction Client → Server * @messageType Notification * @version 1 * @see {@link /guide/actions | Actions} for the full list of client-dispatchable actions. */ export interface DispatchActionParams { /** Channel URI this action targets */ channel: URI; /** Client sequence number */ clientSeq: number; /** The action to dispatch */ action: StateAction; } // ─── resourceRead ──────────────────────────────────────────────────────── /** * Encoding of fetched content data. * * @category Commands * @exhaustive */ export const enum ContentEncoding { Base64 = 'base64', Utf8 = 'utf-8', } /** * Reads the content of a resource by URI. * * Content references keep the state tree small by storing large data (images, * long tool outputs) by reference rather than inline. * * Binary content (images, etc.) MUST use `base64` encoding. Text content MAY * use `utf-8` encoding. * * Like all `resource*` methods, `resourceRead` is symmetrical and MAY be * sent in either direction. Hosts use it to fetch content from a * client-published URI (e.g. `virtual://my-client/...` plugins); clients * use it to read host-side files. The receiver enforces access via the * same permission/`resourceRequest` flow regardless of which peer initiated. * * @category Commands * @method resourceRead * @direction Client ↔ Server * @messageType Request * @version 1 * @throws `NotFound` (`-32008`) if the URI does not exist. * @throws `PermissionDenied` (`-32009`) if the client is not permitted to read the URI. * @example * ```jsonc * // Client → Server * { "jsonrpc": "2.0", "id": 10, "method": "resourceRead", * "params": { "uri": "ahp-session://content/img-1" } } * * // Server → Client * { "jsonrpc": "2.0", "id": 10, "result": { * "data": "iVBORw0KGgo...", * "encoding": "base64", * "contentType": "image/png" * }} * ``` */ export interface ResourceReadParams extends BaseParams { channel: 'ahp-root://'; /** Content URI from a `ContentRef` */ uri: string; /** Preferred encoding for the returned data (default: server-chosen) */ encoding?: ContentEncoding; } /** * Result of the `resourceRead` command. * * The server SHOULD honor the `encoding` requested in the params. If the * server cannot provide the requested encoding, it MUST fall back to either * `base64` or `utf-8`. */ export interface ResourceReadResult { /** Content encoded as a string */ data: string; /** How `data` is encoded */ encoding: ContentEncoding; /** Content type (e.g. `"image/png"`, `"text/plain"`) */ contentType?: string; } // ─── resourceWrite ─────────────────────────────────────────────────────────── /** * How {@link ResourceWriteParams.data} is placed within the target file. * * Each mode interprets {@link ResourceWriteParams.position} differently: * * - `truncate` (default): rooted at the **start** of the file. The file is * truncated at `position` (0 by default) and `data` is written from that * offset, so the resulting file is `existing[0..position] + data`. With * `position` omitted this is a full overwrite. * - `append`: rooted at the **end** of the file. `position` counts bytes * backwards from EOF, so `position: 0` (the default) writes at EOF — * POSIX append — and `position: 5` inserts `data` 5 bytes before the * current EOF, shifting those trailing 5 bytes after the inserted region. * The server MUST evaluate the effective EOF and write atomically with * respect to other appenders so concurrent `append` writes do not * clobber each other. * - `insert`: rooted at the **start** of the file. `position` (0 by default) * is the byte offset at which `data` is spliced in; bytes at or after * `position` are shifted right by `data.length`. `insert` always grows * the file — use `truncate` to overwrite bytes in place. * * @category Commands * @exhaustive */ export const enum ResourceWriteMode { Truncate = 'truncate', Append = 'append', Insert = 'insert', } /** * Writes content to a file on the server's filesystem. * * Binary content (images, etc.) MUST use `base64` encoding. Text content MAY * use `utf-8` encoding. * * If the file does not exist, it is created. If the file already exists, the * effect on existing bytes depends on {@link ResourceWriteParams.mode}: * `truncate` (default) overwrites from the chosen offset onward, `append` * preserves all existing bytes and adds `data` at a position rooted at EOF, * and `insert` preserves all existing bytes and splices `data` in at an * offset rooted at the start of the file. * * Like all `resource*` methods, `resourceWrite` is symmetrical and MAY be * sent in either direction. * * @category Commands * @method resourceWrite * @direction Client ↔ Server * @messageType Request * @version 1 * @throws `NotFound` (`-32008`) if the parent directory does not exist. * @throws `PermissionDenied` (`-32009`) if the client is not permitted to write to the path. * @throws `AlreadyExists` (`-32010`) if `createOnly` is set and the file already exists. * @throws `Conflict` (`-32011`) if `ifMatch` is set and the current `etag` does not match. * @example * ```jsonc * // Client → Server * { "jsonrpc": "2.0", "id": 11, "method": "resourceWrite", * "params": { "uri": "file:///workspace/hello.txt", "data": "SGVsbG8=", * "encoding": "base64", "contentType": "text/plain" } } * * // Server → Client * { "jsonrpc": "2.0", "id": 11, "result": {} } * ``` */ export interface ResourceWriteParams extends BaseParams { channel: 'ahp-root://'; /** Target file URI on the server filesystem */ uri: URI; /** Content encoded as a string */ data: string; /** How `data` is encoded */ encoding: ContentEncoding; /** Content type (e.g. `"text/plain"`, `"image/png"`) */ contentType?: string; /** * If `true`, the server MUST fail if the file already exists instead of * overwriting it. Useful for safe creation of new files. */ createOnly?: boolean; /** * How `data` is placed within the target file. Defaults to `'truncate'` * (full overwrite) when omitted. See {@link ResourceWriteMode} for the * meaning of each mode and how it interprets {@link position}. */ mode?: ResourceWriteMode; /** * Byte offset interpreted according to {@link mode}. Defaults to `0`. * - `truncate`: offset from the start of the file at which to truncate * before writing. * - `append`: bytes back from EOF at which to insert `data`. * - `insert`: offset from the start of the file at which to splice in * `data`. */ position?: number; /** * Optimistic-concurrency token previously returned by * {@link ResourceResolveResult.etag}. When set, the server MUST fail with * `Conflict` if the current `etag` does not match — preventing lost * updates between a `resourceResolve` and a subsequent `resourceWrite`. */ ifMatch?: string; } /** * Result of the `resourceWrite` command. * * An empty object on success. */ export interface ResourceWriteResult { } // ─── resourceList ──────────────────────────────────────────────────────── /** * Lists directory entries at a file URI on the server's filesystem. * * This is intended for remote folder pickers and similar UI that needs to let * users navigate the server's local filesystem. * * The server MUST return success only if the target exists and is a directory. * If the target does not exist, is not a directory, or cannot be accessed, the * server MUST return a JSON-RPC error. * * Like all `resource*` methods, `resourceList` is symmetrical and MAY be * sent in either direction. * * @category Commands * @method resourceList * @direction Client ↔ Server * @messageType Request * @version 1 * @throws `NotFound` (`-32008`) if the directory does not exist. * @throws `PermissionDenied` (`-32009`) if the client is not permitted to browse the directory. */ export interface ResourceListParams extends BaseParams { channel: 'ahp-root://'; /** Directory URI on the server filesystem */ uri: URI; } /** * Directory entry returned by `resourceList`. */ export interface DirectoryEntry { /** Base name of the entry */ name: string; /** Whether the entry is a file or directory */ type: 'file' | 'directory'; } /** * Result of the `resourceList` command. */ export interface ResourceListResult { /** Entries directly contained in the requested directory */ entries: DirectoryEntry[]; } // ─── resourceCopy ──────────────────────────────────────────────────────────── /** * Copies a resource from one URI to another on the server's filesystem. * * If the destination already exists, it is overwritten unless `failIfExists` * is set. * * Like all `resource*` methods, `resourceCopy` is symmetrical and MAY be * sent in either direction. * * @category Commands * @method resourceCopy * @direction Client ↔ Server * @messageType Request * @version 1 * @throws `NotFound` (`-32008`) if the source does not exist. * @throws `PermissionDenied` (`-32009`) if the client is not permitted to read the source or write to the destination. * @throws `AlreadyExists` (`-32010`) if `failIfExists` is set and the destination already exists. */ export interface ResourceCopyParams extends BaseParams { channel: 'ahp-root://'; /** Source URI to copy from */ source: URI; /** Destination URI to copy to */ destination: URI; /** * If `true`, the server MUST fail if the destination already exists instead * of overwriting it. */ failIfExists?: boolean; } /** * Result of the `resourceCopy` command. * * An empty object on success. */ export interface ResourceCopyResult { } // ─── resourceDelete ────────────────────────────────────────────────────────── /** * Deletes a resource at a URI on the server's filesystem. * * Like all `resource*` methods, `resourceDelete` is symmetrical and MAY be * sent in either direction. * * @category Commands * @method resourceDelete * @direction Client ↔ Server * @messageType Request * @version 1 * @throws `NotFound` (`-32008`) if the resource does not exist. * @throws `PermissionDenied` (`-32009`) if the client is not permitted to delete the resource. */ export interface ResourceDeleteParams extends BaseParams { channel: 'ahp-root://'; /** URI of the resource to delete */ uri: URI; /** * If `true` and the target is a directory, delete it and all its contents * recursively. If `false` (default), deleting a non-empty directory MUST fail. */ recursive?: boolean; } /** * Result of the `resourceDelete` command. * * An empty object on success. */ export interface ResourceDeleteResult { } // ─── resourceRequest ───────────────────────────────────────────────────────── /** * Requests permission to access a resource on the receiver's filesystem. * * `resourceRequest` is symmetrical and MAY be sent in either direction: a * client asks the server to grant access to a server-side resource, or a * server asks the client to grant access to a client-side resource. The * receiver decides whether to allow, deny, or prompt the user for the * requested access. * * If the receiver denies access, it MUST respond with `PermissionDenied` * (-32009). The error data MAY include a `ResourceRequestParams` value * describing the access the caller would need to be granted for the * operation to succeed; see `PermissionDeniedErrorData` in * `types/errors.ts`. * * After a successful `resourceRequest`, the caller MAY use the corresponding * `resource*` commands (e.g. `resourceRead`, `resourceWrite`) to perform the * operation. Receivers MAY rescind access at any time by returning * `PermissionDenied` on subsequent operations. * * Either `read`, `write`, or both SHOULD be set to `true`. A request with * neither flag set is treated as `read: true` by receivers. * * @category Commands * @method resourceRequest * @direction Client ↔ Server * @messageType Request * @version 1 * @throws `PermissionDenied` (`-32009`) if access is denied. */ export interface ResourceRequestParams extends BaseParams { channel: 'ahp-root://'; /** * Resource URI being requested. Typically a `file:` URI on the receiver's * filesystem, but any URI scheme that the receiver mediates access to is * allowed. */ uri: URI; /** Whether the caller needs read access to the resource. */ read?: boolean; /** Whether the caller needs write access to the resource. */ write?: boolean; } /** * Result of the `resourceRequest` command. * * An empty object on success. */ export interface ResourceRequestResult { } // ─── resourceMove ──────────────────────────────────────────────────────────── /** * Moves (renames) a resource from one URI to another on the server's filesystem. * * If the destination already exists, it is overwritten unless `failIfExists` * is set. * * Like all `resource*` methods, `resourceMove` is symmetrical and MAY be * sent in either direction. * * @category Commands * @method resourceMove * @direction Client ↔ Server * @messageType Request * @version 1 * @throws `NotFound` (`-32008`) if the source does not exist. * @throws `PermissionDenied` (`-32009`) if the client is not permitted to move the resource. * @throws `AlreadyExists` (`-32010`) if `failIfExists` is set and the destination already exists. */ export interface ResourceMoveParams extends BaseParams { channel: 'ahp-root://'; /** Source URI to move from */ source: URI; /** Destination URI to move to */ destination: URI; /** * If `true`, the server MUST fail if the destination already exists instead * of overwriting it. */ failIfExists?: boolean; } /** * Result of the `resourceMove` command. * * An empty object on success. */ export interface ResourceMoveResult { } // ─── resourceResolve ───────────────────────────────────────────────────────── /** * Discriminant for {@link ResourceResolveResult.type}. * * @category Commands * @nonexhaustive */ export const enum ResourceType { File = 'file', Directory = 'directory', Symlink = 'symlink', } /** * Resolves a resource — the combination of POSIX `stat` and `realpath`. * * `resourceResolve` returns metadata about the resource together with its * canonical URI after symlink resolution. Use this in place of any * `resourceExists` shim: a missing resource MUST surface as a `NotFound` * JSON-RPC error rather than a success with a sentinel value. Callers that * truly need a boolean check should attempt `resourceResolve` and treat * `NotFound` as "does not exist". * * Like all `resource*` methods, `resourceResolve` is symmetrical and MAY be * sent in either direction. * * @category Commands * @method resourceResolve * @direction Client ↔ Server * @messageType Request * @version 1 * @throws `NotFound` (`-32008`) if the resource does not exist. * @throws `PermissionDenied` (`-32009`) if the caller is not permitted to stat the URI. * @example * ```jsonc * // Client → Server * { "jsonrpc": "2.0", "id": 20, "method": "resourceResolve", * "params": { "channel": "ahp-root://", "uri": "file:///workspace/hello.txt" } } * * // Server → Client * { "jsonrpc": "2.0", "id": 20, "result": { * "uri": "file:///workspace/hello.txt", * "type": "file", * "size": 5, * "mtime": "2026-01-15T12:34:56.789Z", * "etag": "W/\"5-abc123\"" * }} * ``` */ export interface ResourceResolveParams extends BaseParams { channel: 'ahp-root://'; /** URI to resolve */ uri: URI; /** * When `true` (default), follow symlinks and report the metadata of the * link target — and set `uri` in the result to the canonical (realpath) * URI. When `false`, stat the link itself (lstat semantics) and report * `type: 'symlink'`. */ followSymlinks?: boolean; } /** * Result of the `resourceResolve` command. */ export interface ResourceResolveResult { /** * Canonical URI after symlink resolution. Equal to the requested URI when * `followSymlinks` is `false` or the URI does not traverse a symlink. */ uri: URI; /** Resource kind. */ type: ResourceType; /** * Size in bytes. Omitted for directories when the provider cannot * cheaply compute it. */ size?: number; /** Last-modified time in ISO 8601 format, when known. */ mtime?: string; /** Creation time in ISO 8601 format, when known. */ ctime?: string; /** Sniffed MIME type, when known (e.g. `"text/plain"`, `"image/png"`). */ contentType?: string; /** * Opaque per-provider version token. When present, pass it as * {@link ResourceWriteParams.ifMatch} on a subsequent `resourceWrite` to * detect concurrent modifications. */ etag?: string; } // ─── resourceMkdir ─────────────────────────────────────────────────────────── /** * Creates a directory on the server's filesystem with `mkdir -p` semantics. * * The server MUST create any missing parent directories. Creating a * directory that already exists is a no-op success. If `uri` already * exists but is **not** a directory, the server MUST fail with * `AlreadyExists`. * * Like all `resource*` methods, `resourceMkdir` is symmetrical and MAY be * sent in either direction. * * @category Commands * @method resourceMkdir * @direction Client ↔ Server * @messageType Request * @version 1 * @throws `PermissionDenied` (`-32009`) if the caller is not permitted to create the directory. * @throws `AlreadyExists` (`-32010`) if `uri` already exists as a non-directory. */ export interface ResourceMkdirParams extends BaseParams { channel: 'ahp-root://'; /** Directory URI to create (parents created as needed). */ uri: URI; } /** * Result of the `resourceMkdir` command. * * An empty object on success. */ export interface ResourceMkdirResult { } // ─── authenticate ──────────────────────────────────────────────────────────── /** * Pushes a Bearer token for a protected resource. The `resource` field MUST * match a protected-resource identifier the client has discovered from the * server — whether declared statically in `AgentInfo.protectedResources`, * or discovered dynamically from a live `McpServerAuthRequiredState.resource` * or `ToolCallAuthRequiredState.auth.resource` (both surfaced only once the * corresponding MCP server or tool call actually challenges for auth). * Servers MUST accept any `resource` value they have themselves advertised * through one of these three mechanisms. * * Tokens are delivered using [RFC 6750](https://datatracker.ietf.org/doc/html/rfc6750) * (Bearer Token Usage) semantics. The client obtains the token from the * authorization server(s) listed in the resource's metadata and pushes it * to the server via this command. * * @category Commands * @method authenticate * @direction Client → Server * @messageType Request * @version 1 * @see {@link /specification/authentication | Authentication} * @example * ```jsonc * // Client → Server * { "jsonrpc": "2.0", "id": 3, "method": "authenticate", * "params": { "channel": "ahp-root://", "resource": "https://api.github.com", "token": "gho_xxxx" } } * * // Server → Client (success) * { "jsonrpc": "2.0", "id": 3, "result": {} } * * // Server → Client (failure — invalid token) * { "jsonrpc": "2.0", "id": 3, "error": { "code": -32007, "message": "Invalid token" } } * ``` */ export interface AuthenticateParams extends BaseParams { channel: 'ahp-root://'; /** * The protected resource identifier. MUST match a `resource` value the * server has advertised — via `ProtectedResourceMetadata` in * `AgentInfo.protectedResources`, or via a live * `McpServerAuthRequiredState.resource` / `ToolCallAuthRequiredState.auth.resource`. */ resource: string; /** Bearer token obtained from the resource's authorization server */ token: string; /** * OAuth scopes the token grants, when known. Lets the server determine * whether a specific challenge — e.g. the `requiredScopes` on a live * `McpServerAuthRequiredState` or `ToolCallAuthRequiredState.auth` — is * satisfied without decoding the (opaque, server-specific) token itself. * Omit when the client doesn't track granted scopes separately from the * token. */ scopes?: string[]; } /** * Result of the `authenticate` command. * * An empty object on success. If the token is invalid or the resource is * unrecognized, the server MUST return a JSON-RPC error (e.g. `AuthRequired` * `-32007` or `InvalidParams` `-32602`). */ export interface AuthenticateResult { }