329 lines
No EOL
7.8 KiB
Text
329 lines
No EOL
7.8 KiB
Text
---
|
|
title: "Tool invocation"
|
|
description: "Learn how to invoke tools through the MCP client API"
|
|
---
|
|
|
|
MCP allows clients to invoke tools exposed by servers. Tools are discrete operations that servers can perform on behalf of clients, similar to function calls.
|
|
|
|
## Getting available tools
|
|
|
|
Before invoking tools, you'll need to get a list of available tools from the server.
|
|
|
|
<CodeGroup>
|
|
```typescript TypeScript
|
|
import { Client } from "@modelcontextprotocol/sdk/client";
|
|
import { ListToolsResultSchema } from "@modelcontextprotocol/sdk/types";
|
|
|
|
// Assuming client is already connected
|
|
const result = await client.request(
|
|
{
|
|
method: "tools/list"
|
|
},
|
|
ListToolsResultSchema
|
|
);
|
|
|
|
// Tools are now available in result.tools
|
|
for (const tool of result.tools) {
|
|
console.log(`Found tool: ${tool.name}`);
|
|
console.log(`Description: ${tool.description}`);
|
|
}
|
|
```
|
|
|
|
```python Python
|
|
from mcp.client import Client
|
|
from mcp.types import ListToolsRequest
|
|
|
|
# Assuming client is already connected
|
|
result = await client.request(
|
|
ListToolsRequest(method="tools/list"),
|
|
ListToolsResultSchema
|
|
)
|
|
|
|
# Tools are now available in result.tools
|
|
for tool in result.tools:
|
|
print(f"Found tool: {tool.name}")
|
|
print(f"Description: {tool.description}")
|
|
```
|
|
</CodeGroup>
|
|
|
|
## Tool invocation
|
|
|
|
To invoke a tool, you'll use the `tools/call` method with the tool name and any required arguments.
|
|
|
|
<CodeGroup>
|
|
```typescript TypeScript
|
|
import { CallToolRequest, CallToolResultSchema } from "@modelcontextprotocol/sdk/types";
|
|
|
|
const result = await client.request(
|
|
{
|
|
method: "tools/call",
|
|
params: {
|
|
name: "example_tool",
|
|
arguments: {
|
|
param1: "value1",
|
|
param2: 42
|
|
}
|
|
}
|
|
},
|
|
CallToolResultSchema
|
|
);
|
|
|
|
// Tool result is available in result.toolResult
|
|
console.log("Tool result:", result.toolResult);
|
|
```
|
|
|
|
```python Python
|
|
from mcp.types import CallToolRequest, CallToolResult
|
|
|
|
result = await client.request(
|
|
CallToolRequest(
|
|
method="tools/call",
|
|
params={
|
|
"name": "example_tool",
|
|
"arguments": {
|
|
"param1": "value1",
|
|
"param2": 42
|
|
}
|
|
}
|
|
),
|
|
CallToolResult
|
|
)
|
|
|
|
# Tool result is available in result.tool_result
|
|
print("Tool result:", result.tool_result)
|
|
```
|
|
</CodeGroup>
|
|
|
|
## Progress tracking
|
|
|
|
For long-running tools, you can track progress using progress notifications.
|
|
|
|
<CodeGroup>
|
|
```typescript TypeScript
|
|
const result = await client.request(
|
|
{
|
|
method: "tools/call",
|
|
params: {
|
|
name: "long_running_tool",
|
|
arguments: {
|
|
duration: 10
|
|
}
|
|
}
|
|
},
|
|
CallToolResultSchema,
|
|
(progress) => {
|
|
console.log(`Progress: ${progress.progress}/${progress.total ?? '?'}`);
|
|
}
|
|
);
|
|
```
|
|
|
|
```python Python
|
|
def progress_callback(progress):
|
|
print(f"Progress: {progress.progress}/{progress.total or '?'}")
|
|
|
|
result = await client.request(
|
|
CallToolRequest(
|
|
method="tools/call",
|
|
params={
|
|
"name": "long_running_tool",
|
|
"arguments": {
|
|
"duration": 10
|
|
}
|
|
}
|
|
),
|
|
CallToolResult,
|
|
on_progress=progress_callback
|
|
)
|
|
```
|
|
</CodeGroup>
|
|
|
|
## Error handling
|
|
|
|
Tool invocations may fail for various reasons. Always handle potential errors appropriately.
|
|
|
|
<CodeGroup>
|
|
```typescript TypeScript
|
|
try {
|
|
const result = await client.request(
|
|
{
|
|
method: "tools/call",
|
|
params: {
|
|
name: "risky_tool",
|
|
arguments: {
|
|
important_param: "value"
|
|
}
|
|
}
|
|
},
|
|
CallToolResultSchema
|
|
);
|
|
} catch (error) {
|
|
if (error instanceof McpError) {
|
|
console.error(`Tool error (${error.code}): ${error.message}`);
|
|
if (error.data) {
|
|
console.error("Additional error data:", error.data);
|
|
}
|
|
} else {
|
|
console.error("Unexpected error:", error);
|
|
}
|
|
}
|
|
```
|
|
|
|
```python Python
|
|
from mcp.errors import McpError
|
|
|
|
try:
|
|
result = await client.request(
|
|
CallToolRequest(
|
|
method="tools/call",
|
|
params={
|
|
"name": "risky_tool",
|
|
"arguments": {
|
|
"important_param": "value"
|
|
}
|
|
}
|
|
),
|
|
CallToolResult
|
|
)
|
|
except McpError as e:
|
|
print(f"Tool error ({e.code}): {e.message}")
|
|
if e.data:
|
|
print("Additional error data:", e.data)
|
|
except Exception as e:
|
|
print("Unexpected error:", e)
|
|
```
|
|
</CodeGroup>
|
|
|
|
## Complete example
|
|
|
|
Here's a complete example showing how to discover and use tools with proper error handling.
|
|
|
|
<CodeGroup>
|
|
```typescript TypeScript
|
|
import { Client } from "@modelcontextprotocol/sdk/client";
|
|
import {
|
|
ListToolsResultSchema,
|
|
CallToolResultSchema,
|
|
McpError
|
|
} from "@modelcontextprotocol/sdk/types";
|
|
|
|
async function invokeTools(client: Client) {
|
|
try {
|
|
// Get available tools
|
|
const toolsList = await client.request(
|
|
{ method: "tools/list" },
|
|
ListToolsResultSchema
|
|
);
|
|
|
|
// Find a specific tool
|
|
const tool = toolsList.tools.find(t => t.name === "example_tool");
|
|
if (!tool) {
|
|
console.error("Tool not found");
|
|
return;
|
|
}
|
|
|
|
// Invoke the tool with progress tracking
|
|
const result = await client.request(
|
|
{
|
|
method: "tools/call",
|
|
params: {
|
|
name: tool.name,
|
|
arguments: {
|
|
// Tool-specific arguments
|
|
param1: "value1"
|
|
}
|
|
}
|
|
},
|
|
CallToolResultSchema,
|
|
(progress) => {
|
|
console.log(
|
|
`Progress: ${progress.progress}/${progress.total ?? '?'}`
|
|
);
|
|
}
|
|
);
|
|
|
|
console.log("Tool result:", result.toolResult);
|
|
} catch (error) {
|
|
if (error instanceof McpError) {
|
|
console.error(`Tool error (${error.code}): ${error.message}`);
|
|
} else {
|
|
console.error("Unexpected error:", error);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
```python Python
|
|
from mcp.client import Client
|
|
from mcp.types import ListToolsRequest, CallToolRequest
|
|
from mcp.errors import McpError
|
|
|
|
async def invoke_tools(client: Client):
|
|
try:
|
|
# Get available tools
|
|
tools_list = await client.request(
|
|
ListToolsRequest(method="tools/list"),
|
|
ListToolsResultSchema
|
|
)
|
|
|
|
# Find a specific tool
|
|
tool = next(
|
|
(t for t in tools_list.tools if t.name == "example_tool"),
|
|
None
|
|
)
|
|
if not tool:
|
|
print("Tool not found")
|
|
return
|
|
|
|
# Invoke the tool with progress tracking
|
|
result = await client.request(
|
|
CallToolRequest(
|
|
method="tools/call",
|
|
params={
|
|
"name": tool.name,
|
|
"arguments": {
|
|
# Tool-specific arguments
|
|
"param1": "value1"
|
|
}
|
|
}
|
|
),
|
|
CallToolResult,
|
|
on_progress=lambda p: print(
|
|
f"Progress: {p.progress}/{p.total or '?'}"
|
|
)
|
|
)
|
|
|
|
print("Tool result:", result.tool_result)
|
|
except McpError as e:
|
|
print(f"Tool error ({e.code}): {e.message}")
|
|
except Exception as e:
|
|
print("Unexpected error:", e)
|
|
```
|
|
</CodeGroup>
|
|
|
|
## Best practices
|
|
|
|
When working with tools:
|
|
|
|
<CardGroup cols={2}>
|
|
<Card title="Validation" icon="check-circle">
|
|
Always check tool availability before invoking
|
|
</Card>
|
|
<Card title="Error handling" icon="shield-check">
|
|
Implement comprehensive error handling
|
|
</Card>
|
|
<Card title="Progress" icon="bars-progress">
|
|
Use progress callbacks for long-running operations
|
|
</Card>
|
|
<Card title="Arguments" icon="input-text">
|
|
Validate arguments against the tool's input schema
|
|
</Card>
|
|
</CardGroup>
|
|
|
|
## Common errors
|
|
|
|
| Error Code | Description | Resolution |
|
|
|------------|-------------|------------|
|
|
| -32601 | Method not found | Verify the tool name exists |
|
|
| -32602 | Invalid params | Check the tool's input schema |
|
|
| -32603 | Internal error | Server-side error, check server logs |
|
|
| -1 | Connection closed | Check connection status | |