# `Mead.MCP.Hub`
[🔗](https://github.com/albertosca/mead/blob/main/lib/mead/mcp/hub.ex#L1)

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.

# `call_tool`

```elixir
@spec call_tool(term(), term(), keyword(), atom()) ::
  {:ok, %{content: String.t(), is_error: boolean()}} | {:error, term()}
```

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `describe_tool`

```elixir
@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.

# `start_link`

```elixir
@spec start_link(keyword()) :: Supervisor.on_start()
```

# `tools_for`

```elixir
@spec tools_for(keyword(), atom()) :: [
  %{name: String.t(), description: String.t() | nil, input_schema: map()}
]
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
