Direct Tool Calls
MCP-Use allows you to call MCP server tools directly without needing an LLM or agent. This is useful when you want to use MCP servers as a simple interface to various tools and APIs, or when you need programmatic control over tool execution.
Direct tool calls are appropriate when:
- You know exactly which tool to call and with what parameters
- You don’t need an LLM to make decisions about tool selection
- You want to integrate MCP tools into existing Python applications
- You need deterministic, programmatic control over tool execution
Direct tool calls will not work for tools that require sampling/completion, as
these need an LLM to generate responses.
Basic Example
Here’s how to call tools directly using the MCPClient:
import { MCPClient } from 'mcp-use'
async function callToolExample() {
// Configure the MCP server
const config = {
mcpServers: {
everything: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-everything']
}
}
}
// Create client from configuration
const client = new MCPClient(config)
try {
// Initialize all configured sessions
await client.createAllSessions()
// Get the session for a specific server
const session = client.getSession('everything')
// List available tools
const tools = await session.listTools()
const toolNames = tools.map(t => t.name)
console.log(`Available tools: ${toolNames}`)
// Call a specific tool with arguments
const result = await session.callTool(
'add',
{ a: 1, b: 2 }
)
// Handle the result
if (result.isError) {
console.error(`Error: ${result.content}`)
} else {
console.log(`Tool result: ${result.content}`)
console.log(`Text result: ${result.content[0].text}`)
}
} finally {
// Clean up resources
await client.closeAllSessions()
}
}
callToolExample().catch(console.error)
The call_tool method returns a CallToolResult object with the following attributes:
content: A list of ContentBlock objects containing the tool’s output
structuredContent: A dictionary with the structured result (for non-sampling tools)
isError: Boolean indicating if the tool call encountered an error
Accessing Results
// Call a tool
const result = await session.callTool(
'get_weather',
{ location: 'San Francisco' }
)
// Check for errors
if (result.isError) {
console.error(`Tool error: ${result.content}`)
} else {
// Access text content
const textResult = result.content[0].text
console.log(`Weather: ${textResult}`)
// Access structured content if available
if (result.structuredContent) {
const structured = result.structuredContent
console.log(`Temperature: ${structured.temperature}`)
}
}
Timeout Configuration
For long-running tools, especially those that trigger sampling or LLM operations, you may need to configure custom timeout settings:
// Extended timeout for long-running operations
const result = await session.callTool(
'process_large_dataset',
{ dataset: 'large-data.json' },
{
timeout: 300000, // 5 minutes
}
)
Available timeout options:
timeout: Request timeout in milliseconds (default: 60000 / 60 seconds)
maxTotalTimeout: Maximum total time in milliseconds, even with progress resets
resetTimeoutOnProgress: If true, resets the timeout counter when a progress notification is received (default: false)
signal: An AbortSignal to programmatically cancel the request
Note: When resetTimeoutOnProgress is enabled and the server sends progress notifications (like ctx.sample() does automatically), the operation can run indefinitely as long as progress is reported regularly.
Multiple Server Example
You can work with multiple MCP servers and call tools from each:
import { MCPClient } from 'mcp-use'
async function multiServerExample() {
const config = {
mcpServers: {
filesystem: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem'],
env: { FILE_PATH: '/tmp' }
},
time: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-time']
}
}
}
const client = new MCPClient(config)
try {
await client.createAllSessions()
// Call tool from filesystem server
const fsSession = client.getSession('filesystem')
const files = await fsSession.callTool(
'list_files',
{ path: '/tmp' }
)
console.log(`Files: ${files.content[0].text}`)
// Call tool from time server
const timeSession = client.getSession('time')
const currentTime = await timeSession.callTool(
'get_current_time',
{}
)
console.log(`Current time: ${currentTime.content[0].text}`)
} finally {
await client.closeAllSessions()
}
}
multiServerExample().catch(console.error)
Before calling tools, you may want to discover what’s available:
async function discoverTools() {
const client = new MCPClient(config)
await client.createAllSessions()
try {
const session = client.getSession('my_server')
// Get all tools
const tools = await session.listTools()
for (const tool of tools) {
console.log(`Tool: ${tool.name}`)
console.log(` Description: ${tool.description}`)
// Print input schema if available
if (tool.inputSchema) {
console.log(` Parameters: ${JSON.stringify(tool.inputSchema)}`)
}
console.log()
}
} finally {
await client.closeAllSessions()
}
}
Error Handling
Always handle potential errors when making direct tool calls:
async function safeToolCall() {
try {
const result = await session.callTool(
'some_tool',
{ param: 'value' }
)
if (result.isError) {
// Handle tool-specific errors
const errorMsg = result.content?.[0]?.text || 'Unknown error'
console.error(`Tool returned error: ${errorMsg}`)
return null
}
return result.content[0].text
} catch (error) {
// Handle connection or other errors
console.error(`Failed to call tool: ${error}`)
return null
}
}
Limitations
When using direct tool calls, be aware of these limitations:
- No Sampling Support: Tools that require sampling/completion (like text generation) won’t work without an LLM
- Manual Tool Selection: You need to know which tool to call - there’s no automatic selection
- No Context Management: Unlike agents, direct calls don’t maintain conversation context
- Parameter Validation: You’re responsible for providing correct parameters
Complete Example
View the complete working example in the repository:
examples/direct_tool_call.py
Next Steps