# `ExMCP.Response`
[🔗](https://github.com/azmaveth/ex_mcp/blob/v1.0.0/lib/ex_mcp/response.ex#L1)

Structured response types for MCP operations.

This module provides structured response handling for MCP tool calls,
resource reads, and other operations, giving callers 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

# `content_item`

```elixir
@type content_item() :: %{
  type: String.t(),
  text: String.t() | nil,
  data: any() | nil,
  annotations: map() | nil
}
```

# `t`

```elixir
@type t() :: %ExMCP.Response{
  cacheScope: String.t() | nil,
  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,
  resultType: String.t() | nil,
  roots: [map()] | nil,
  server_info: map() | nil,
  structuredOutput: any() | nil,
  tool_name: String.t() | nil,
  tools: [map()] | nil,
  ttlMs: non_neg_integer() | nil
}
```

# `all_text_content`

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

Gets all text content from the response as a concatenated string.

# `completion`

```elixir
@spec completion(t()) :: map() | nil
```

Gets completion data from response.

Handles both direct completion field and structuredOutput.completion.

# `data_content`

```elixir
@spec data_content(t()) :: any()
```

Gets the data content from the response.

Returns the first data content item, or nil if none exists.

# `error`

```elixir
@spec error(String.t(), String.t() | nil, keyword()) :: t()
```

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
    }

# `error?`

```elixir
@spec error?(t()) :: boolean()
```

Checks if the response represents an error.

# `from_map`

```elixir
@spec from_map(map() | t()) :: t()
```

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"

# `from_raw_response`

```elixir
@spec from_raw_response(
  map(),
  keyword()
) :: t()
```

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
    }

# `json`

```elixir
@spec json(any(), String.t() | nil, keyword()) :: t()
```

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
    }

# `resource_content`

```elixir
@spec resource_content(t()) :: String.t() | nil
```

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.

# `schema_property`

Gets a property from a schema properties map.

## Examples

    iex> schema = %{"properties" => %{"name" => %{"type" => "string"}}}
    iex> ExMCP.Response.schema_property(schema, "name")
    %{"type" => "string"}

# `text`

```elixir
@spec text(String.t(), String.t() | nil, keyword()) :: t()
```

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
    }

# `text_content`

```elixir
@spec text_content(t()) :: String.t() | nil
```

Gets the text content from the response.

Returns the first text content item, or nil if none exists.

# `to_raw`

```elixir
@spec to_raw(t()) :: map()
```

Converts the response back to raw MCP format.

# `to_test_map`

```elixir
@spec to_test_map(t()) :: map()
```

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.

# `tool_description`

Gets the tool description from a tool definition.

## Examples

    iex> tool = %{"name" => "hello", "description" => "Says hello"}
    iex> ExMCP.Response.tool_description(tool)
    "Says hello"

# `tool_input_schema`

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"}

# `tool_name`

Gets the tool name from a tool definition.

## Examples

    iex> tool = %{"name" => "hello", "description" => "Says hello"}
    iex> ExMCP.Response.tool_name(tool)
    "hello"

---

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