Helpers for exercising a registered catalog in host test suites.
Each helper builds a JSON-RPC request, encodes and decodes it as JSON,
dispatches it through the supervised server, and returns the complete
JSON-RPC response map. Requests take the same operation-scope,
definition-scope, definition authorize, schema, handler, cache-hint, and
final wire-output path as transport dispatch. Handlers are never called
directly.
response =
AttestoMCP.Server.Test.call_tool(
MyApp.MCP,
"get_item",
%{"id" => "item-7"},
principal: principal,
scopes: ["items.read"],
host_context: %{account_id: "acct-1"}
)
assert %{"result" => %{"structuredContent" => %{"id" => "item-7"}}} = responseThe same request path is available for the other primitives:
AttestoMCP.Server.Test.read_resource(MyApp.MCP, "file:///docs/item-7")
AttestoMCP.Server.Test.get_prompt(MyApp.MCP, "summarize", %{"topic" => "release"})
AttestoMCP.Server.Test.complete(MyApp.MCP, %{"type" => "ref/prompt", "name" => "summarize"},
%{"name" => "topic", "value" => "rel"})
AttestoMCP.Server.Test.discover(MyApp.MCP)
AttestoMCP.Server.Test.list_tools(MyApp.MCP, cursor: next_cursor)request/4 sends any other method through the same builder.
Boundaries
The helpers start after transport authentication. :principal, :tenant,
:scopes, and :host_context represent an already authenticated request.
They do not verify a token, DPoP proof, mTLS certificate, HTTP header, or
Plug parser order, and they do not establish HTTP header/body mirroring,
legacy session negotiation, stdio framing, or disconnect behaviour. Keep
separate Plug and stdio tests for those boundaries.
Options
Every helper accepts:
:principal(default"test-principal"),:tenant,:scopes(default[]), and:host_context: the authenticated handler context. These are never copied into protocol parameters.:request_id: a stable response ID.:protocol_version: the request revision, default"2026-07-28".:client_capabilities: the modern request's declared capabilities.:meta: application metadata forparams["_meta"], which handlers see ascontext.request_meta. The helper generates the protocol version and client capability keys; supplying either in:metaraises.:request_stateand:input_responses: modern multi-round retry fields forcall_tool/4,read_resource/3,get_prompt/4, andrequest/4.:timeout: a positive request timeout in milliseconds, still capped by the server's:max_request_timeout.
List helpers also accept :cursor, and complete/4 accepts
:completion_context (the request's context member).
Protocol failures, including denied definitions, invalid schemas, missing
prompt arguments, invalid completion references, invalid cursors, handler
failures, and invalid outputs, are returned as the server's "error" or
"result" members. Malformed helper options and values that cannot be
represented as JSON raise ArgumentError because they are test setup
errors.
Summary
Functions
Calls one registered tool and returns its complete JSON-RPC response map.
Requests completions for a prompt or resource-template reference.
Sends modern server/discover.
Retrieves a prompt with string arguments.
Lists one page of prompts.
Lists one page of resource templates.
Lists one page of static resources.
Lists one page of tools. Pass :cursor for a continuation.
Reads a static or templated resource through the production resolver.
Sends any request method through the shared builder.
Types
@type option() :: {:principal, term()} | {:tenant, term()} | {:scopes, [String.t()]} | {:host_context, map()} | {:request_id, String.t() | integer()} | {:protocol_version, String.t()} | {:client_capabilities, map()} | {:meta, map()} | {:request_state, String.t()} | {:input_responses, map()} | {:cursor, String.t()} | {:completion_context, map()} | {:timeout, pos_integer()}
Functions
@spec call_tool(AttestoMCP.Server.API.server(), String.t(), map(), [option()]) :: map()
Calls one registered tool and returns its complete JSON-RPC response map.
The default protocol revision is 2026-07-28, the default principal is
"test-principal", and the default scope list is empty. Use :request_id
when a stable response ID is useful in an assertion. :client_capabilities
supplies the modern request's declared capabilities, including capabilities
needed by a tool that returns an interactive request.
@spec complete(AttestoMCP.Server.API.server(), map(), map(), [option()]) :: map()
Requests completions for a prompt or resource-template reference.
ref is the wire reference, for example
%{"type" => "ref/prompt", "name" => "summarize"}, and argument is
%{"name" => name, "value" => partial_value}.
@spec discover(AttestoMCP.Server.API.server(), [option()]) :: map()
Sends modern server/discover.
@spec get_prompt(AttestoMCP.Server.API.server(), String.t(), map(), [option()]) :: map()
Retrieves a prompt with string arguments.
@spec list_prompts(AttestoMCP.Server.API.server(), [option()]) :: map()
Lists one page of prompts.
@spec list_resource_templates(AttestoMCP.Server.API.server(), [option()]) :: map()
Lists one page of resource templates.
@spec list_resources(AttestoMCP.Server.API.server(), [option()]) :: map()
Lists one page of static resources.
@spec list_tools(AttestoMCP.Server.API.server(), [option()]) :: map()
Lists one page of tools. Pass :cursor for a continuation.
@spec read_resource(AttestoMCP.Server.API.server(), String.t(), [option()]) :: map()
Reads a static or templated resource through the production resolver.
@spec request(AttestoMCP.Server.API.server(), String.t(), map(), [option()]) :: map()
Sends any request method through the shared builder.
params must not contain _meta, requestState, or inputResponses; use
the :meta, :request_state, and :input_responses options so the helper
can keep protocol fields separate from application metadata.