use std::collections::HashMap;
use std::sync::atomic::Ordering;
use turbomcp_protocol::types::{
CallToolRequest, CallToolResult, Cursor, ListToolsRequest, ListToolsResult, Tool,
};
use turbomcp_protocol::{Error, Result};
const MAX_PAGINATION_PAGES: usize = 1000;
impl<T: turbomcp_transport::Transport + 'static> super::super::core::Client<T> {
pub async fn list_tools(&self) -> Result<Vec<Tool>> {
if !self.inner.initialized.load(Ordering::Relaxed) {
return Err(Error::invalid_request("Client not initialized"));
}
let mut all_tools = Vec::new();
let mut cursor = None;
for _ in 0..MAX_PAGINATION_PAGES {
let result = self.list_tools_paginated(cursor).await?;
let page_empty = result.tools.is_empty();
all_tools.extend(result.tools);
match result.next_cursor {
Some(c) if !page_empty => cursor = Some(c),
_ => break,
}
}
Ok(all_tools)
}
pub async fn list_tools_paginated(&self, cursor: Option<Cursor>) -> Result<ListToolsResult> {
if !self.inner.initialized.load(Ordering::Relaxed) {
return Err(Error::invalid_request("Client not initialized"));
}
let request = ListToolsRequest {
cursor,
_meta: None,
};
let params = if request.cursor.is_some() {
Some(serde_json::to_value(&request)?)
} else {
None
};
self.inner.protocol.request("tools/list", params).await
}
pub async fn list_tool_names(&self) -> Result<Vec<String>> {
let tools = self.list_tools().await?;
Ok(tools.into_iter().map(|tool| tool.name).collect())
}
pub async fn call_tool(
&self,
name: &str,
arguments: Option<HashMap<String, serde_json::Value>>,
task: Option<turbomcp_protocol::types::tasks::TaskMetadata>,
) -> Result<CallToolResult> {
if !self.inner.initialized.load(Ordering::Relaxed) {
return Err(Error::invalid_request("Client not initialized"));
}
let request_data = CallToolRequest {
name: name.to_string(),
arguments: Some(arguments.unwrap_or_default()),
task,
_meta: None,
};
let result: CallToolResult = self
.inner
.protocol
.request("tools/call", Some(serde_json::to_value(&request_data)?))
.await?;
Ok(result) }
}