The client side of MCP for the runtime: a supervisor that keeps one Mead.MCP.Connection per
configured server, and the two functions the router uses, tools_for/2 and call_tool/4.
The hub is not a process every call goes through. It starts a Registry and a
Mead.MCP.Catalog, then the connections, under :rest_for_one; a call looks up the connection
and talks to it directly, so sessions never queue behind each other. It comes after the
session pool in Mead.Supervisor, so a crash here restarts the hub and the MCP server after it,
and nothing before it.
Configuration is read from config :mead, :mcp, servers: [...] (see
Mead.MCP.Configuration) and validated when the hub starts: an invalid one stops the
application at boot with a message instead of silently granting or denying the wrong tools.
tools_for/2 shows the model what the policy allows for the turn. call_tool/4 authorizes the
name again before any server is contacted, so a tool the model was not shown can never run.
Both answer safely when the hub is not running: no tools, and {:error, :hub_unavailable}.
The :transports, :reconnect_delays, and :handshake_timeout options exist for tests.
Summary
Functions
Returns a specification to start this module under a supervisor.
What call_tool/4 would run for name, without running it: the server, the tool and its class.
The router needs the class to ask permission before the call. Fails like call_tool/4 does for a
name that is unknown or not allowed in this turn.
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec describe_tool(term(), keyword(), atom()) :: {:ok, %{server: atom(), tool: String.t(), class: Mead.MCP.Policy.class()}} | {:error, term()}
What call_tool/4 would run for name, without running it: the server, the tool and its class.
The router needs the class to ask permission before the call. Fails like call_tool/4 does for a
name that is unknown or not allowed in this turn.
@spec start_link(keyword()) :: Supervisor.on_start()