ExMCP.Types (ex_mcp v1.0.0-rc.8)

Copy Markdown View Source

Type definitions for the Model Context Protocol.

MCP 2026-07-28 is the latest stable protocol revision. This module holds the shared type surface used across both protocol eras. Version-specific modules document the wire differences for each revision.

Version-specific modules

Prefer the documented :protocol_mode client/server option for negotiation rather than hard-coding version strings in application code.

Unqualified initialize results, roots, sampling, session, and legacy task types remain here for 1.x source compatibility. For fields that changed on the wire, use ExMCP.Types.V20260728 as the modern reference instead of assuming the shared legacy shape applies to MCP 2026-07-28.

Protocol-mode rollout

rc.6 defaults new connections to :prefer_modern, with evidence-based fallback to legacy peers. The zero-arity legacy compatibility accessor continues to return 2025-11-25 during the soak and throughout 1.x.

Summary

Types

Functions

Converts a content type atom to a string.

Converts an include context atom to a string.

Returns the newest legacy protocol revision used by compatibility helpers.

Converts a log level atom to a string.

Converts a role atom to a string.

Converts a string content type to an atom.

Converts a string include context to an atom.

Converts a string log level to an atom.

Converts a string role to an atom.

Types

annotations()

@type annotations() :: %{
  optional(:audience) => [role()],
  optional(:priority) => float(),
  optional(:lastModified) => String.t()
}

atom_initialize_result()

@type atom_initialize_result() :: %{
  :protocolVersion => String.t(),
  :capabilities => server_capabilities(),
  :serverInfo => server_info(),
  optional(:instructions) => String.t()
}

audio_content()

@type audio_content() :: %{
  :type => :audio,
  :data => String.t(),
  :mimeType => String.t(),
  optional(:annotations) => annotations()
}

blob_resource_contents()

@type blob_resource_contents() :: %{
  :uri => String.t(),
  :blob => String.t(),
  optional(:mimeType) => String.t()
}

cache_scope()

@type cache_scope() :: :public | :private | String.t()

cacheable_result()

@type cacheable_result() :: %{
  optional(:resultType) => String.t(),
  optional(:ttlMs) => non_neg_integer(),
  optional(:cacheScope) => cache_scope()
}

call_tool_request()

@type call_tool_request() :: %{
  :name => String.t(),
  optional(:arguments) => %{required(String.t()) => any()}
}

call_tool_result()

@type call_tool_result() :: tool_result()

cancelled_notification()

@type cancelled_notification() :: %{
  :requestId => request_id(),
  optional(:reason) => String.t()
}

client_capabilities()

@type client_capabilities() :: %{
  optional(:experimental) => %{required(String.t()) => map()},
  optional(:roots) => %{optional(:listChanged) => boolean()},
  optional(:sampling) => %{},
  optional(:elicitation) => %{},
  optional(:extensions) => %{required(String.t()) => map()}
}

client_info()

@type client_info() :: implementation()

client_notification()

client_request()

client_result()

@type client_result() ::
  empty_result()
  | create_message_result()
  | list_roots_result()
  | elicit_result()

complete_argument()

@type complete_argument() :: completion_argument()

complete_ref()

@type complete_ref() :: completion_reference()

complete_request()

@type complete_request() :: %{
  ref: completion_reference(),
  argument: completion_argument()
}

complete_result()

@type complete_result() :: completion_result()

completion_argument()

@type completion_argument() :: %{name: String.t(), value: String.t()}

completion_reference()

@type completion_reference() :: resource_reference() | prompt_reference()

completion_result()

@type completion_result() :: %{
  completion: %{
    :values => [String.t()],
    optional(:total) => integer(),
    optional(:hasMore) => boolean()
  }
}

content()

@type content() ::
  text_content() | image_content() | audio_content() | embedded_resource()

content_type()

@type content_type() :: :text | :image | :audio | :resource

create_message_params()

@type create_message_params() :: %{
  :messages => [sampling_message()],
  :maxTokens => integer(),
  optional(:modelPreferences) => model_preferences(),
  optional(:systemPrompt) => String.t(),
  optional(:includeContext) => include_context(),
  optional(:temperature) => float(),
  optional(:stopSequences) => [String.t()],
  optional(:metadata) => map(),
  optional(:tools) => [tool()],
  optional(:toolChoice) => tool_choice()
}

create_message_result()

@type create_message_result() :: %{
  :role => role(),
  :content => text_content() | image_content() | audio_content(),
  :model => String.t(),
  optional(:stopReason) => String.t()
}

cursor()

@type cursor() :: String.t()

elicit_request()

@type elicit_request() :: %{
  message: String.t(),
  requestedSchema: %{
    :type => String.t(),
    :properties => %{required(String.t()) => primitive_schema()},
    optional(:required) => [String.t()]
  }
}

elicit_result()

@type elicit_result() :: %{
  :action => :accept | :decline | :cancel,
  optional(:content) => %{required(String.t()) => any()}
}

embedded_resource()

@type embedded_resource() :: %{
  :type => :resource,
  :resource => resource_contents(),
  optional(:annotations) => annotations()
}

empty_result()

@type empty_result() :: %{}

error_code()

@type error_code() :: integer()

error_data()

@type error_data() :: any()

get_prompt_request()

@type get_prompt_request() :: %{
  :name => String.t(),
  optional(:arguments) => %{required(String.t()) => String.t()}
}

get_prompt_result()

@type get_prompt_result() :: %{
  optional(:description) => String.t(),
  messages: [prompt_message()]
}

icon()

@type icon() :: %{
  :type => String.t(),
  :uri => String.t(),
  optional(:mediaType) => String.t()
}

image_content()

@type image_content() :: %{
  :type => :image,
  :data => String.t(),
  :mimeType => String.t(),
  optional(:annotations) => annotations()
}

implementation()

@type implementation() :: %{
  :name => String.t(),
  :version => String.t(),
  optional(:title) => String.t(),
  optional(:description) => String.t()
}

include_context()

@type include_context() :: :none | :thisServer | :allServers

initialize_request()

@type initialize_request() :: %{
  protocolVersion: String.t(),
  capabilities: client_capabilities(),
  clientInfo: client_info()
}

initialize_result()

@type initialize_result() :: atom_initialize_result() | wire_initialize_result()

json_schema()

@type json_schema() :: map()

jsonrpc_error()

@type jsonrpc_error() :: %{
  :code => error_code(),
  :message => String.t(),
  optional(:data) => error_data()
}

jsonrpc_error_response()

@type jsonrpc_error_response() :: %{
  jsonrpc: String.t(),
  id: request_id(),
  error: jsonrpc_error()
}

jsonrpc_message()

jsonrpc_notification()

@type jsonrpc_notification() :: %{
  :jsonrpc => String.t(),
  :method => String.t(),
  optional(:params) => map()
}

jsonrpc_request()

@type jsonrpc_request() :: %{
  :jsonrpc => String.t(),
  :id => request_id(),
  :method => String.t(),
  optional(:params) => map()
}

jsonrpc_response()

@type jsonrpc_response() :: %{jsonrpc: String.t(), id: request_id(), result: any()}

list_changed_notification()

@type list_changed_notification() :: %{}

list_prompts_request()

@type list_prompts_request() :: paginated_request()

list_prompts_result()

@type list_prompts_result() :: %{
  :prompts => [prompt()],
  optional(:nextCursor) => cursor()
}

list_resource_templates_request()

@type list_resource_templates_request() :: paginated_request()

list_resource_templates_result()

@type list_resource_templates_result() :: %{
  :resourceTemplates => [resource_template()],
  optional(:nextCursor) => cursor()
}

list_resources_request()

@type list_resources_request() :: paginated_request()

list_resources_result()

@type list_resources_result() :: %{
  :resources => [resource()],
  optional(:nextCursor) => cursor()
}

list_roots_request()

@type list_roots_request() :: %{}

list_roots_result()

@type list_roots_result() :: %{roots: [root()]}

list_tools_request()

@type list_tools_request() :: paginated_request()

list_tools_result()

@type list_tools_result() :: %{:tools => [tool()], optional(:nextCursor) => cursor()}

log_level()

@type log_level() ::
  :debug | :info | :notice | :warning | :error | :critical | :alert | :emergency

log_level_string()

@type log_level_string() :: String.t()

log_notification()

@type log_notification() :: %{
  :level => log_level_string(),
  optional(:logger) => String.t(),
  data: any()
}

model_hint()

@type model_hint() :: %{optional(:name) => String.t()}

model_preferences()

@type model_preferences() :: %{
  optional(:hints) => [model_hint()],
  optional(:costPriority) => float(),
  optional(:speedPriority) => float(),
  optional(:intelligencePriority) => float()
}

paginated_request()

@type paginated_request() :: %{optional(:cursor) => cursor()}

paginated_result()

@type paginated_result() :: %{optional(:nextCursor) => cursor()}

ping_request()

@type ping_request() :: %{}

primitive_schema()

@type primitive_schema() :: %{
  :type => String.t(),
  optional(:title) => String.t(),
  optional(:description) => String.t(),
  optional(:enum) => [String.t()],
  optional(:enumNames) => [String.t()],
  optional(:default) => any(),
  optional(:minLength) => integer(),
  optional(:maxLength) => integer(),
  optional(:minimum) => number(),
  optional(:maximum) => number(),
  optional(:format) => String.t()
}

progress_notification()

@type progress_notification() :: %{
  :progressToken => progress_token(),
  :progress => number(),
  optional(:total) => number(),
  optional(:message) => String.t()
}

progress_token()

@type progress_token() :: String.t() | integer()

prompt()

@type prompt() :: %{
  :name => String.t(),
  optional(:title) => String.t(),
  optional(:description) => String.t(),
  optional(:arguments) => [prompt_argument() | map()],
  optional(:icons) => [icon()],
  optional(:_meta) => map()
}

prompt_argument()

@type prompt_argument() :: %{
  :name => String.t(),
  optional(:description) => String.t(),
  optional(:required) => boolean()
}

prompt_message()

@type prompt_message() :: %{role: role(), content: content()}

prompt_reference()

@type prompt_reference() :: %{type: :"ref/prompt", name: String.t()}

protocol_mode()

@type protocol_mode() :: :legacy_only | :modern_only | :prefer_legacy | :prefer_modern

read_resource_request()

@type read_resource_request() :: %{uri: String.t()}

read_resource_result()

@type read_resource_result() :: %{contents: [resource_contents()]}

request_id()

@type request_id() :: String.t() | integer()

resource()

@type resource() :: %{
  :uri => String.t(),
  :name => String.t(),
  optional(:title) => String.t(),
  optional(:description) => String.t(),
  optional(:mimeType) => String.t(),
  optional(:annotations) => annotations(),
  optional(:size) => integer(),
  optional(:icons) => [icon()],
  optional(:_meta) => map()
}

resource_contents()

@type resource_contents() :: text_resource_contents() | blob_resource_contents()

resource_reference()

@type resource_reference() :: %{type: :"ref/resource", uri: String.t()}

resource_template()

@type resource_template() :: %{
  :uriTemplate => String.t(),
  :name => String.t(),
  optional(:title) => String.t(),
  optional(:description) => String.t(),
  optional(:mimeType) => String.t(),
  optional(:annotations) => annotations(),
  optional(:icons) => [icon()],
  optional(:_meta) => map()
}

resource_updated_notification()

@type resource_updated_notification() :: %{uri: String.t()}

role()

@type role() :: :user | :assistant

role_string()

@type role_string() :: String.t()

root()

@type root() :: %{:uri => String.t(), optional(:name) => String.t()}

sampling_message()

@type sampling_message() :: %{
  role: role(),
  content: text_content() | image_content() | audio_content()
}

server_capabilities()

@type server_capabilities() :: %{
  optional(:experimental) => %{required(String.t()) => map()},
  optional(:logging) => %{},
  optional(:completions) => %{},
  optional(:prompts) => %{optional(:listChanged) => boolean()},
  optional(:resources) => %{
    optional(:subscribe) => boolean(),
    optional(:listChanged) => boolean()
  },
  optional(:tools) => %{optional(:listChanged) => boolean()},
  optional(:extensions) => %{required(String.t()) => map()}
}

server_info()

@type server_info() :: implementation()

server_notification()

server_request()

@type server_request() ::
  ping_request()
  | create_message_params()
  | list_roots_request()
  | elicit_request()

server_result()

set_level_request()

@type set_level_request() :: %{level: log_level_string()}

subscribe_request()

@type subscribe_request() :: %{uri: String.t()}

subscribe_result()

@type subscribe_result() :: %{}

task()

@type task() :: %{
  :id => String.t(),
  :state => task_state(),
  optional(:toolName) => String.t(),
  optional(:arguments) => map(),
  optional(:createdAt) => String.t(),
  optional(:ttl) => integer(),
  optional(:result) => tool_result(),
  optional(:metadata) => map()
}

task_state()

@type task_state() :: :working | :input_required | :completed | :failed | :cancelled

text_content()

@type text_content() :: %{
  :type => :text,
  :text => String.t(),
  optional(:annotations) => annotations()
}

text_resource_contents()

@type text_resource_contents() :: %{
  :uri => String.t(),
  :text => String.t(),
  optional(:mimeType) => String.t()
}

tool()

@type tool() :: %{
  :name => String.t(),
  optional(:description) => String.t(),
  optional(:title) => String.t(),
  :inputSchema => json_schema(),
  optional(:outputSchema) => json_schema(),
  optional(:annotations) => tool_annotations(),
  optional(:icons) => [icon()],
  optional(:execution) => map(),
  optional(:_meta) => map()
}

tool_annotations()

@type tool_annotations() :: %{
  optional(:title) => String.t(),
  optional(:readOnlyHint) => boolean(),
  optional(:destructiveHint) => boolean(),
  optional(:idempotentHint) => boolean(),
  optional(:openWorldHint) => boolean()
}

tool_choice()

@type tool_choice() :: %{type: String.t()}

tool_result()

@type tool_result() :: %{
  :content => [content()],
  optional(:isError) => boolean(),
  optional(:structuredContent) => any()
}

tool_result_content()

@type tool_result_content() :: %{
  :type => String.t(),
  :tool_use_id => String.t(),
  :content => [content()],
  optional(:isError) => boolean()
}

tool_use_content()

@type tool_use_content() :: %{
  type: String.t(),
  id: String.t(),
  name: String.t(),
  input: map()
}

transport()

@type transport() :: :stdio | :http | module()

unsubscribe_request()

@type unsubscribe_request() :: %{uri: String.t()}

unsubscribe_result()

@type unsubscribe_result() :: %{}

wire_initialize_result()

@type wire_initialize_result() :: %{required(String.t()) => any()}

Functions

content_type_to_string(atom)

@spec content_type_to_string(content_type()) :: String.t()

Converts a content type atom to a string.

include_context_to_string(atom)

@spec include_context_to_string(include_context()) :: String.t()

Converts an include context atom to a string.

internal_error()

invalid_params()

invalid_request()

jsonrpc_version()

latest_protocol_version()

@spec latest_protocol_version() :: String.t()

Returns the newest legacy protocol revision used by compatibility helpers.

log_level_to_string(atom)

@spec log_level_to_string(log_level()) :: String.t()

Converts a log level atom to a string.

method_not_found()

parse_error()

role_to_string(atom)

@spec role_to_string(role()) :: String.t()

Converts a role atom to a string.

string_to_content_type(binary)

@spec string_to_content_type(String.t()) :: content_type()

Converts a string content type to an atom.

string_to_include_context(binary)

@spec string_to_include_context(String.t()) :: include_context()

Converts a string include context to an atom.

string_to_log_level(binary)

@spec string_to_log_level(String.t()) :: log_level()

Converts a string log level to an atom.

string_to_role(binary)

@spec string_to_role(String.t()) :: role()

Converts a string role to an atom.