# `ExMCP.Types.V20260728`
[🔗](https://github.com/azmaveth/ex_mcp/blob/v1.0.0/lib/ex_mcp/types/v20260728.ex#L1)

Type definitions for MCP protocol version 2026-07-28.

This revision is a breaking, stateless protocol era. These types describe
its wire surface. Runtime support is selected through the dual-era protocol
modes, and rc.6 defaults new connections to `:prefer_modern`.

Important changes represented here include per-request protocol metadata,
typed result envelopes, discovery, caching hints, subscriptions, and
multi-round-trip input requests.

# `cacheable_result`

```elixir
@type cacheable_result() :: %{
  :resultType =&gt; result_type(),
  :ttlMs =&gt; non_neg_integer(),
  :cacheScope =&gt; :public | :private,
  optional(:_meta) =&gt; result_meta_object(),
  optional(atom() | String.t()) =&gt; any()
}
```

A complete result with mandatory client-side caching hints.

# `call_tool_result`

```elixir
@type call_tool_result() :: %{
  :resultType =&gt; result_type(),
  :content =&gt; [ExMCP.Types.content()],
  optional(:structuredContent) =&gt; json_value(),
  optional(:isError) =&gt; boolean(),
  optional(:_meta) =&gt; result_meta_object()
}
```

A modern tool result whose structured content may be any JSON value.

# `cancel_task_request_params`

```elixir
@type cancel_task_request_params() :: %{
  _meta: request_meta_object(),
  taskId: String.t()
}
```

Parameters for cooperatively cancelling one task.

# `client_capabilities`

```elixir
@type client_capabilities() :: %{
  optional(:experimental) =&gt; %{optional(String.t()) =&gt; json_object()},
  optional(:roots) =&gt; %{},
  optional(:sampling) =&gt; %{
    optional(:context) =&gt; json_object(),
    optional(:tools) =&gt; json_object()
  },
  optional(:elicitation) =&gt; %{
    optional(:form) =&gt; json_object(),
    optional(:url) =&gt; json_object()
  },
  optional(:extensions) =&gt; %{optional(String.t()) =&gt; json_object()}
}
```

Capabilities declared by a modern client on each request.

# `create_task_result`

```elixir
@type create_task_result() :: %{
  :resultType =&gt; :task,
  :taskId =&gt; String.t(),
  :status =&gt; task_status(),
  :createdAt =&gt; String.t(),
  :lastUpdatedAt =&gt; String.t(),
  :ttlMs =&gt; non_neg_integer(),
  optional(:pollIntervalMs) =&gt; non_neg_integer(),
  optional(:statusMessage) =&gt; String.t(),
  optional(:_meta) =&gt; result_meta_object()
}
```

A server-directed task handle returned instead of an immediate result.

# `detailed_task`

```elixir
@type detailed_task() :: %{
  :taskId =&gt; String.t(),
  :status =&gt; task_status(),
  :createdAt =&gt; String.t(),
  :lastUpdatedAt =&gt; String.t(),
  :ttlMs =&gt; non_neg_integer(),
  optional(:pollIntervalMs) =&gt; non_neg_integer(),
  optional(:statusMessage) =&gt; String.t(),
  optional(:inputRequests) =&gt; input_requests(),
  optional(:result) =&gt; json_object(),
  optional(:error) =&gt; json_object()
}
```

Full task state embedded in `tasks/get` and `notifications/tasks`.

# `discover_result`

```elixir
@type discover_result() :: %{
  :resultType =&gt; result_type(),
  :ttlMs =&gt; non_neg_integer(),
  :cacheScope =&gt; :public | :private,
  :supportedVersions =&gt; [String.t()],
  :capabilities =&gt; server_capabilities(),
  optional(:instructions) =&gt; String.t(),
  optional(:_meta) =&gt; result_meta_object()
}
```

The result of `server/discover`.

# `get_task_request_params`

```elixir
@type get_task_request_params() :: %{_meta: request_meta_object(), taskId: String.t()}
```

Parameters for idempotently reading one task.

# `get_task_result`

```elixir
@type get_task_result() :: %{
  :resultType =&gt; :complete,
  :taskId =&gt; String.t(),
  :status =&gt; task_status(),
  :createdAt =&gt; String.t(),
  :lastUpdatedAt =&gt; String.t(),
  :ttlMs =&gt; non_neg_integer(),
  optional(:pollIntervalMs) =&gt; non_neg_integer(),
  optional(:statusMessage) =&gt; String.t(),
  optional(:inputRequests) =&gt; input_requests(),
  optional(:result) =&gt; json_object(),
  optional(:error) =&gt; json_object(),
  optional(:_meta) =&gt; result_meta_object()
}
```

A complete result returned by `tasks/get`.

# `header_mismatch_error`

```elixir
@type header_mismatch_error() :: %{
  :jsonrpc =&gt; String.t(),
  optional(:id) =&gt; request_id(),
  error: %{:code =&gt; -32020, :message =&gt; String.t(), optional(:data) =&gt; any()}
}
```

A JSON-RPC header/body mismatch response (`-32020`).

# `implementation`

```elixir
@type implementation() :: %{
  :name =&gt; String.t(),
  :version =&gt; String.t(),
  optional(:title) =&gt; String.t(),
  optional(:description) =&gt; String.t(),
  optional(:websiteUrl) =&gt; String.t(),
  optional(:icons) =&gt; [ExMCP.Types.V20251125.icon()]
}
```

Client or server implementation identity.

# `input_request`

```elixir
@type input_request() :: %{method: String.t(), params: map()}
```

A server-initiated request embedded in an MRTR result.

# `input_requests`

```elixir
@type input_requests() :: %{optional(String.t()) =&gt; input_request()}
```

Server-assigned input IDs mapped to requests.

# `input_required_result`

```elixir
@type input_required_result() :: %{
  :resultType =&gt; result_type(),
  optional(:inputRequests) =&gt; input_requests(),
  optional(:requestState) =&gt; String.t(),
  optional(:_meta) =&gt; result_meta_object()
}
```

An interim result requesting additional client input.

# `input_response`

```elixir
@type input_response() :: map()
```

A client result satisfying one server-initiated MRTR request.

# `input_response_request_params`

```elixir
@type input_response_request_params() :: %{
  :_meta =&gt; request_meta_object(),
  optional(:inputResponses) =&gt; input_responses(),
  optional(:requestState) =&gt; String.t(),
  optional(atom() | String.t()) =&gt; any()
}
```

Retry fields accepted on client-initiated requests after an MRTR result.

# `input_responses`

```elixir
@type input_responses() :: %{optional(String.t()) =&gt; input_response()}
```

Server-assigned input IDs mapped to client results.

# `json_object`

```elixir
@type json_object() :: %{optional(String.t()) =&gt; json_value()}
```

A JSON object with string keys.

# `json_schema`

```elixir
@type json_schema() :: map()
```

Any JSON Schema 2020-12 object, including extension keywords.

# `json_value`

```elixir
@type json_value() ::
  String.t()
  | number()
  | boolean()
  | nil
  | [json_value()]
  | %{optional(String.t()) =&gt; json_value()}
```

A value representable in JSON.

# `log_level`

```elixir
@type log_level() :: ExMCP.Types.log_level()
```

# `meta_object`

```elixir
@type meta_object() :: %{optional(String.t()) =&gt; any()}
```

An extensible MCP `_meta` object.

# `missing_required_client_capability_error`

```elixir
@type missing_required_client_capability_error() :: %{
  :jsonrpc =&gt; String.t(),
  optional(:id) =&gt; request_id(),
  error: %{
    code: -32021,
    message: String.t(),
    data: %{requiredCapabilities: client_capabilities()}
  }
}
```

A missing per-request client capability response (`-32021`).

# `notification_meta_object`

```elixir
@type notification_meta_object() :: %{
  optional(:&quot;io.modelcontextprotocol/subscriptionId&quot;) =&gt; request_id(),
  optional(String.t()) =&gt; any()
}
```

Metadata carried by notifications, including subscription correlation.

# `number_schema`

```elixir
@type number_schema() :: %{
  :type =&gt; :number | :integer,
  optional(:title) =&gt; String.t(),
  optional(:description) =&gt; String.t(),
  optional(:minimum) =&gt; number(),
  optional(:maximum) =&gt; number(),
  optional(:default) =&gt; number()
}
```

The numeric elicitation schema from the 2026-07-28 generator.

# `progress_token`

```elixir
@type progress_token() :: ExMCP.Types.progress_token()
```

# `request_id`

```elixir
@type request_id() :: ExMCP.Types.request_id()
```

# `request_meta_object`

```elixir
@type request_meta_object() :: %{
  :&quot;io.modelcontextprotocol/protocolVersion&quot; =&gt; String.t(),
  :&quot;io.modelcontextprotocol/clientCapabilities&quot; =&gt; client_capabilities(),
  optional(:&quot;io.modelcontextprotocol/clientInfo&quot;) =&gt; implementation(),
  optional(:&quot;io.modelcontextprotocol/logLevel&quot;) =&gt; log_level(),
  optional(:progressToken) =&gt; progress_token(),
  optional(String.t()) =&gt; any()
}
```

Metadata required on every modern request.

# `result`

```elixir
@type result() :: %{
  :resultType =&gt; result_type(),
  optional(:_meta) =&gt; result_meta_object(),
  optional(atom() | String.t()) =&gt; any()
}
```

Common fields present on every modern result.

# `result_meta_object`

```elixir
@type result_meta_object() :: %{
  optional(:&quot;io.modelcontextprotocol/serverInfo&quot;) =&gt; implementation(),
  optional(String.t()) =&gt; any()
}
```

Metadata carried by results.

# `result_type`

```elixir
@type result_type() :: String.t()
```

A recognized or negotiated extension result discriminator.

# `server_capabilities`

```elixir
@type server_capabilities() :: %{
  optional(:experimental) =&gt; %{optional(String.t()) =&gt; json_object()},
  optional(:logging) =&gt; json_object(),
  optional(:completions) =&gt; json_object(),
  optional(:prompts) =&gt; %{optional(:listChanged) =&gt; boolean()},
  optional(:resources) =&gt; %{
    optional(:subscribe) =&gt; boolean(),
    optional(:listChanged) =&gt; boolean()
  },
  optional(:tools) =&gt; %{optional(:listChanged) =&gt; boolean()},
  optional(:extensions) =&gt; %{optional(String.t()) =&gt; json_object()}
}
```

Capabilities returned by a modern server from `server/discover`.

# `subscription_filter`

```elixir
@type subscription_filter() :: %{
  optional(:toolsListChanged) =&gt; boolean(),
  optional(:promptsListChanged) =&gt; boolean(),
  optional(:resourcesListChanged) =&gt; boolean(),
  optional(:resourceSubscriptions) =&gt; [String.t()],
  optional(:taskIds) =&gt; [String.t()]
}
```

Notification categories selected by `subscriptions/listen`.

# `subscriptions_listen_request`

```elixir
@type subscriptions_listen_request() :: %{
  jsonrpc: String.t(),
  id: request_id(),
  method: String.t(),
  params: subscriptions_listen_request_params()
}
```

A request that opens a long-lived notification stream.

# `subscriptions_listen_request_params`

```elixir
@type subscriptions_listen_request_params() :: %{
  _meta: request_meta_object(),
  notifications: subscription_filter()
}
```

Parameters for `subscriptions/listen`.

# `subscriptions_listen_result`

```elixir
@type subscriptions_listen_result() :: %{
  resultType: result_type(),
  _meta: subscriptions_listen_result_meta_object()
}
```

The graceful close result for `subscriptions/listen`.

# `subscriptions_listen_result_meta_object`

```elixir
@type subscriptions_listen_result_meta_object() :: %{
  :&quot;io.modelcontextprotocol/subscriptionId&quot; =&gt; request_id(),
  optional(:&quot;io.modelcontextprotocol/serverInfo&quot;) =&gt; implementation(),
  optional(String.t()) =&gt; any()
}
```

Metadata on the graceful close result of a subscription stream.

# `task`

```elixir
@type task() :: %{
  :taskId =&gt; String.t(),
  :status =&gt; task_status(),
  :createdAt =&gt; String.t(),
  :lastUpdatedAt =&gt; String.t(),
  :ttlMs =&gt; non_neg_integer(),
  optional(:pollIntervalMs) =&gt; non_neg_integer(),
  optional(:statusMessage) =&gt; String.t()
}
```

Fields common to task handles and detailed task state.

# `task_status`

```elixir
@type task_status() :: :working | :input_required | :completed | :failed | :cancelled
```

Lifecycle state of a task in the official Tasks extension.

# `tool`

```elixir
@type tool() :: %{
  :name =&gt; String.t(),
  :inputSchema =&gt; json_schema(),
  optional(:title) =&gt; String.t(),
  optional(:description) =&gt; String.t(),
  optional(:outputSchema) =&gt; json_schema(),
  optional(:annotations) =&gt; ExMCP.Types.tool_annotations(),
  optional(:icons) =&gt; [ExMCP.Types.V20251125.icon()],
  optional(:_meta) =&gt; meta_object()
}
```

A tool definition using unrestricted JSON Schema 2020-12 objects.

# `unsupported_protocol_version_error`

```elixir
@type unsupported_protocol_version_error() :: %{
  :jsonrpc =&gt; String.t(),
  optional(:id) =&gt; request_id(),
  error: %{
    code: -32022,
    message: String.t(),
    data: %{supported: [String.t()], requested: String.t()}
  }
}
```

An unsupported protocol version response (`-32022`).

# `update_task_request_params`

```elixir
@type update_task_request_params() :: %{
  _meta: request_meta_object(),
  taskId: String.t(),
  inputResponses: input_responses()
}
```

Parameters for submitting responses to outstanding task inputs.

# `protocol_version`

```elixir
@spec protocol_version() :: String.t()
```

Returns the protocol version described by this module.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
