ExMCP.Response (ex_mcp v0.9.0)
View SourceStructured response types for MCP operations.
This module provides structured response handling for MCP tool calls, resource reads, and other operations. It represents a key improvement in v2, providing type-safe responses instead of raw maps.
Response Types
:text- Simple text responses:json- Structured JSON data:error- Error responses with detailed information:tools- Tool listing responses:resources- Resource listing responses:prompts- Prompt listing responses:server_info- Server information responses:mixed- Responses with multiple content types
Usage
# Create a text response
response = ExMCP.Response.text("Hello, world!", "greeting_tool")
# Create a JSON response
response = ExMCP.Response.json(%{result: 42}, "calculator")
# Create an error response
response = ExMCP.Response.error("Invalid input", "validation_tool")
# Extract content
text = ExMCP.Response.text_content(response)
json = ExMCP.Response.json_content(response)Protocol Data Handling
Protocol data from MCP servers is kept as string-keyed maps to maintain compatibility with the MCP JSON-RPC protocol and avoid atom exhaustion issues.
# Tools, resources, and prompts use string keys
response.tools
#=> [%{"name" => "hello", "description" => "Says hello", "inputSchema" => %{...}}]
# Use accessor functions for convenience
tool = hd(response.tools)
ExMCP.Response.tool_name(tool) #=> "hello"
ExMCP.Response.tool_description(tool) #=> "Says hello"
ExMCP.Response.tool_input_schema(tool) #=> %{"type" => "object", ...}Design Rationale
The structured response type provides:
- Type safety and consistency across all MCP operations
- Clear extraction functions for different content types
- Metadata support for tracing and debugging
- Unified error handling
- Protocol fidelity by keeping MCP data as strings
- Protection against atom exhaustion attacks
Summary
Functions
Gets all text content from the response as a concatenated string.
Gets completion data from response.
Gets the data content from the response.
Creates an error response.
Checks if the response represents an error.
Creates a Response struct from a plain map (backward compatibility).
Creates a response from a raw MCP response.
Creates a response with JSON data content.
Gets the resource content from the response.
Gets a property from a schema properties map.
Creates a success response with text content.
Gets the text content from the response.
Converts the response back to raw MCP format.
Converts the response to a map that excludes nil pagination fields.
Gets the tool description from a tool definition.
Gets the input schema from a tool definition.
Gets the tool name from a tool definition.
Types
@type t() :: %ExMCP.Response{ completion: map() | nil, content: [content_item()], contents: [map()] | nil, description: String.t() | nil, is_error: boolean(), messages: [map()] | nil, meta: map() | nil, nextCursor: String.t() | nil, prompts: [map()] | nil, request_id: String.t() | nil, resourceLinks: [map()] | nil, resourceTemplates: [map()] | nil, resources: [map()] | nil, roots: [map()] | nil, server_info: map() | nil, structuredOutput: any() | nil, tool_name: String.t() | nil, tools: [map()] | nil }
Functions
Gets all text content from the response as a concatenated string.
Gets completion data from response.
Handles both direct completion field and structuredOutput.completion.
Gets the data content from the response.
Returns the first data content item, or nil if none exists.
Creates an error response.
Examples
iex> ExMCP.Response.error("Tool execution failed", "calculate_sum")
%ExMCP.Response{
content: [%{type: "text", text: "Error: Tool execution failed", data: nil, annotations: nil}],
meta: nil,
tool_name: "calculate_sum",
request_id: nil,
server_info: nil,
is_error: true
}
Checks if the response represents an error.
Creates a Response struct from a plain map (backward compatibility).
This is useful for tests that expect to work with plain maps. If the input is already a Response struct, returns it unchanged.
Examples
iex> map = %{"tools" => [%{"name" => "test"}], "nextCursor" => "abc"}
iex> response = ExMCP.Response.from_map(map)
iex> response.tools
[%{"name" => "test"}]
iex> response.nextCursor
"abc"
Creates a response from a raw MCP response.
Examples
iex> raw = %{"content" => [%{"type" => "text", "text" => "Hello"}]}
iex> ExMCP.Response.from_raw_response(raw)
%ExMCP.Response{
content: [%{type: "text", text: "Hello", data: nil, annotations: nil}],
meta: nil,
tool_name: nil,
request_id: nil,
server_info: nil,
is_error: false
}
Creates a response with JSON data content.
Examples
iex> data = %{"result" => 42}
iex> ExMCP.Response.json(data, "calculate")
%ExMCP.Response{
content: [%{type: "text", text: nil, data: %{"result" => 42}, annotations: nil}],
meta: nil,
tool_name: "calculate",
request_id: nil,
server_info: nil,
is_error: false
}
Gets the resource content from the response.
Returns the text from the first resource content item, or nil if none exists.
This is used for resource read responses that have a contents field.
Gets a property from a schema properties map.
Examples
iex> schema = %{"properties" => %{"name" => %{"type" => "string"}}}
iex> ExMCP.Response.schema_property(schema, "name")
%{"type" => "string"}
Creates a success response with text content.
Examples
iex> ExMCP.Response.text("Hello, World!", "say_hello")
%ExMCP.Response{
content: [%{type: "text", text: "Hello, World!", data: nil, annotations: nil}],
meta: nil,
tool_name: "say_hello",
request_id: nil,
server_info: nil,
is_error: false
}
Gets the text content from the response.
Returns the first text content item, or nil if none exists.
Converts the response back to raw MCP format.
Converts the response to a map that excludes nil pagination fields.
This is useful for tests that expect Map.has_key?/2 to return false
for pagination fields when they are not present in the original response.
Gets the tool description from a tool definition.
Examples
iex> tool = %{"name" => "hello", "description" => "Says hello"}
iex> ExMCP.Response.tool_description(tool)
"Says hello"
Gets the input schema from a tool definition.
Examples
iex> tool = %{"name" => "hello", "inputSchema" => %{"type" => "object"}}
iex> ExMCP.Response.tool_input_schema(tool)
%{"type" => "object"}
Gets the tool name from a tool definition.
Examples
iex> tool = %{"name" => "hello", "description" => "Says hello"}
iex> ExMCP.Response.tool_name(tool)
"hello"