Assay.MCP (assay v0.3.0)

View Source

Minimal Model Context Protocol (MCP) server built on top of the Assay daemon.

The server speaks JSON-RPC over stdio and exposes a single tool:

  • assay.analyze — runs incremental Dialyzer and returns structured diagnostics.

MCP clients (e.g. IDE agents) can initialize, list tools, and invoke the tool using tools/call.

Summary

Functions

Handles a JSON-RPC request map and returns {reply | nil, state, action}.

Initializes MCP state. Accepts :daemon (for tests) or :config overrides.

Starts the MCP server and blocks, reading JSON-RPC over stdio.

Types

t()

@type t() :: %Assay.MCP{
  client_info: map(),
  daemon: Assay.Daemon.t(),
  halt_on_stop?: boolean(),
  initialized?: boolean(),
  server_info: map()
}

Functions

handle_rpc(request, state)

@spec handle_rpc(map(), t()) :: {map() | nil, t(), :continue | :stop}

Handles a JSON-RPC request map and returns {reply | nil, state, action}.

action is either :continue or :stop. Primarily used in tests.

Examples

# Initialize request
request = %{
  "jsonrpc" => "2.0",
  "id" => 1,
  "method" => "initialize",
  "params" => %{"clientInfo" => %{"name" => "test-client"}}
}
state = Assay.MCP.new()
{reply, new_state, action} = Assay.MCP.handle_rpc(request, state)
# reply contains protocol version and server info
# new_state.initialized? is true
# action is :continue

# List tools request
request = %{
  "jsonrpc" => "2.0",
  "id" => 2,
  "method" => "tools/list"
}
{reply, new_state, action} = Assay.MCP.handle_rpc(request, initialized_state)
# reply contains list of available tools (assay.analyze)
# action is :continue

# Call tool request
request = %{
  "jsonrpc" => "2.0",
  "id" => 3,
  "method" => "tools/call",
  "params" => %{
    "name" => "assay.analyze",
    "arguments" => %{"formats" => ["json"]}
  }
}
{reply, new_state, action} = Assay.MCP.handle_rpc(request, initialized_state)
# reply contains tool result with diagnostics
# action is :continue

new(opts \\ [])

@spec new(keyword()) :: t()

Initializes MCP state. Accepts :daemon (for tests) or :config overrides.

serve(opts \\ [])

@spec serve(keyword()) :: no_return()

Starts the MCP server and blocks, reading JSON-RPC over stdio.