Toolnexus.McpServe (toolnexus v0.9.4)

Copy Markdown View Source

MCP — INBOUND: serve a toolkit as an MCP server (SPEC §7C).

The inbound mirror of the A2A serve (§7B). Where A2A advertises the toolkit's skills and fulfils a Task through the whole client loop, MCP advertises the toolkit's unified tools (every source) and dispatches each tools/call straight to Tool.execute. The calling MCP client is the LLM host, so there is no client, no Task, and no TaskStore — just tools/list + tools/call over the toolkit registry.

Transport: streamable-HTTP, mounted at POST /mcp on the Toolnexus.Serve server alongside the A2A routes (stateless — no session). Deferred per §7C: stdio, resources, prompts, sampling.

Summary

Functions

The tools the MCP profile exposes: every toolkit tool, filtered to the profile's tools list when set (unknown names in the filter are ignored, never an error).

Handle one streamable-HTTP MCP request (/mcp). Stateless: each POST is a self-contained JSON-RPC exchange; notifications are accepted with 202. Non-POST methods answer 405 (like the JS SDK's stateless transport).

Functions

exposed_tools(tools, cfg)

@spec exposed_tools([Toolnexus.Tool.t()], map() | nil) :: [Toolnexus.Tool.t()]

The tools the MCP profile exposes: every toolkit tool, filtered to the profile's tools list when set (unknown names in the filter are ignored, never an error).

handle_http(conn, tools, cfg, on_call)

@spec handle_http(
  Plug.Conn.t(),
  [Toolnexus.Tool.t()],
  map() | nil,
  (map() -> any()) | nil
) ::
  Plug.Conn.t()

Handle one streamable-HTTP MCP request (/mcp). Stateless: each POST is a self-contained JSON-RPC exchange; notifications are accepted with 202. Non-POST methods answer 405 (like the JS SDK's stateless transport).