ExMCP.Testing.MockServer (ex_mcp v0.9.2)

View Source

Mock MCP server implementation for testing.

This module provides a comprehensive mock server that can simulate various MCP server behaviors for testing client implementations. It supports all MCP protocol features including tools, resources, prompts, and streaming.

Features

  • Full Protocol Support: All MCP methods and notifications
  • Configurable Responses: Customize server behavior for testing
  • State Management: Stateful behavior for complex scenarios
  • Error Simulation: Test error handling and edge cases
  • Performance Testing: Latency and throughput simulation
  • Transport Agnostic: Works with all transport implementations

Usage

# Simple mock server
MockServer.with_server([], fn client ->
  {:ok, result} = ExMCP.Client.list_tools(client)
  assert length(result["tools"]) == 0
end)

# Server with predefined tools
MockServer.with_server([
  tools: [MockServer.sample_tool()],
  resources: [MockServer.sample_resource()]
], fn client ->
  # Test with mock data
end)

# Server with custom behavior
MockServer.with_server([
  handler: MyCustomHandler,
  state: %{custom_data: "test"}
], fn client ->
  # Test with custom handler
end)

Summary

Types

Mock server configuration

Mock server state

Functions

Returns a specification to start this module under a supervisor.

Gets the current call count for a mock server.

Gets the current state of a mock server.

Resets the call count for a mock server.

Creates a sample prompt definition for testing.

Creates a sample resource definition for testing.

Creates a sample tool definition for testing.

Updates the custom state of a mock server.

Starts a mock server and runs a test function with a connected client.

Types

mock_config()

@type mock_config() :: [
  tools: [map()],
  resources: [map()],
  prompts: [map()],
  handler: module() | nil,
  state: map(),
  latency: pos_integer(),
  error_rate: float(),
  capabilities: map()
]

Mock server configuration

server_state()

@type server_state() :: %{
  tools: [map()],
  resources: [map()],
  prompts: [map()],
  handler: module() | nil,
  custom_state: map(),
  latency: pos_integer(),
  error_rate: float(),
  capabilities: map(),
  call_count: map(),
  last_calls: [map()]
}

Mock server state

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

get_call_count(server_pid)

@spec get_call_count(pid()) :: map()

Gets the current call count for a mock server.

Examples

with_server([], fn client ->
  ExMCP.Client.list_tools(client)
  ExMCP.Client.list_tools(client)

  count = MockServer.get_call_count(server_pid)
  assert count["tools/list"] == 2
end)

get_server_state(server_pid)

@spec get_server_state(pid()) :: server_state()

Gets the current state of a mock server.

reset_call_count(server_pid)

@spec reset_call_count(pid()) :: :ok

Resets the call count for a mock server.

sample_prompt(opts \\ [])

@spec sample_prompt(keyword()) :: map()

Creates a sample prompt definition for testing.

Examples

prompt = sample_prompt()
# %{"name" => "sample_prompt", "description" => "...", "arguments" => [...]}

prompt = sample_prompt(name: "custom_prompt")

sample_resource(opts \\ [])

@spec sample_resource(keyword()) :: map()

Creates a sample resource definition for testing.

Examples

resource = sample_resource()
# %{"uri" => "file://sample.txt", "name" => "Sample", ...}

resource = sample_resource(uri: "https://api.example.com", name: "API")

sample_tool(opts \\ [])

@spec sample_tool(keyword()) :: map()

Creates a sample tool definition for testing.

Examples

tool = sample_tool()
# %{"name" => "sample_tool", "description" => "...", "inputSchema" => %{...}}

tool = sample_tool(name: "custom_tool", description: "Custom tool")

set_custom_state(server_pid, new_state)

@spec set_custom_state(pid(), map()) :: :ok

Updates the custom state of a mock server.

start_link(config \\ [])

@spec start_link(mock_config()) :: GenServer.on_start()

with_server(config \\ [], test_fun)

@spec with_server(mock_config(), (pid() -> any())) :: any()

Starts a mock server and runs a test function with a connected client.

Options

  • :tools - List of tool definitions to serve
  • :resources - List of resource definitions to serve
  • :prompts - List of prompt definitions to serve
  • :handler - Custom handler module for advanced behavior
  • :state - Initial custom state for the handler
  • :latency - Simulated response latency in milliseconds
  • :error_rate - Probability (0.0-1.0) of returning errors
  • :capabilities - Custom server capabilities

Examples

with_server([], fn client ->
  result = ExMCP.Client.list_tools(client)
  assert {:ok, %{"tools" => []}} = result
end)

with_server([
  tools: [sample_tool()],
  latency: 100
], fn client ->
  # Test with 100ms latency
end)