///| High-level MCP host over multiple named client connections.
///|
pub struct MCPHost {
name : String
version : String
connections : Map[String, MCPClient]
}
///|
pub fn MCPHost::MCPHost(name~ : String, version~ : String) -> MCPHost {
{ name, version, connections: {} }
}
///|
pub async fn MCPHost::connect_http(
self : MCPHost,
name~ : String,
url~ : String,
auth_token? : String = "",
) -> Result[Unit, @types.MCPError] {
match
MCPClient::connect_http(
url~,
name=self.name + "/" + name,
version=self.version,
auth_token~,
) {
Ok(client) => {
self.connections[name] = client
Ok(())
}
Err(e) => Err(e)
}
}
///|
pub async fn MCPHost::connect_stdio(
self : MCPHost,
name~ : String,
cmd~ : String,
args? : Array[String] = [],
extra_env? : Map[String, String] = {},
group~ : @async.TaskGroup[Unit],
) -> Result[Unit, @types.MCPError] {
match
MCPClient::connect_stdio(
cmd~,
args~,
name=self.name + "/" + name,
version=self.version,
extra_env~,
group~,
) {
Ok(client) => {
self.connections[name] = client
Ok(())
}
Err(e) => Err(e)
}
}
///|
pub async fn MCPHost::list_tools(
self : MCPHost,
) -> Result[ListToolsResult, @types.MCPError] {
let tools : Array[@types.ToolDefinition] = []
for entry in self.connections {
let (connection_name, client) = entry
match client.list_tools() {
Ok(result) =>
for tool in result.tools {
tools.push({ ..tool, name: connection_name + "." + tool.name })
}
Err(e) => return Err(e)
}
}
Ok({ tools, next_cursor: None })
}
///|
pub async fn MCPHost::call_tool(
self : MCPHost,
qualified_name : String,
arguments? : String = "{}",
) -> Result[CallToolResult, @types.MCPError] {
match qualified_name.split_once(".") {
Some((connection_view, tool_view)) => {
let connection_name = connection_view.to_owned()
let tool_name = tool_view.to_owned()
match self.connections.get(connection_name) {
Some(client) => client.call_tool(tool_name, arguments~)
None =>
Err(@types.MethodNotFound("Connection not found: " + connection_name))
}
}
None =>
Err(
@types.InvalidRequest(
"Tool name must be qualified as '.'",
),
)
}
}
///|
pub async fn MCPHost::close_all(self : MCPHost) -> Unit {
for entry in self.connections {
let (_, client) = entry
client.close()
}
self.connections.clear()
}