Optimize tools (MCP)
Use this guide when you want to optimize tool signatures (descriptions + parameter descriptions) separately from prompt text or agent logic.
What this covers
Section titled “What this covers”- Optimize MCP tool descriptions without touching prompt content.
- Keep system/assistant/user messages fixed while improving tool calling behavior.
- Target only specific tools when a server exposes many tools.
Quickstart: tool-only optimization
Section titled “Quickstart: tool-only optimization”from opik_optimizer import ChatPrompt, MetaPromptOptimizer
prompt = ChatPrompt(
system="Use tools when needed.",
user="{user_query}",
tools=[
{
"type": "mcp",
"server_label": "context7",
"server_url": "https://mcp.context7.com/mcp",
"allowed_tools": ["resolve-library-id", "query-docs"],
}
],
)
optimizer = MetaPromptOptimizer(model="openai/gpt-4o-mini")
result = optimizer.optimize_prompt(
prompt=prompt,
dataset=my_dataset,
metric=answer_quality,
optimize_prompts=False, # keep prompt text fixed
optimize_tools=True, # optimize tool + parameter descriptions
)Tool optimization is supported by all optimizers except FewShotBayesianOptimizer,
ParameterOptimizer, and GepaOptimizer (for now).
Tool calling + MCP formats
Section titled “Tool calling + MCP formats”You can define tools in one of the supported formats. Tool optimization will normalize them to function-calling tools while preserving the original MCP config for reproducibility.
Supported formats
Section titled “Supported formats”| Format | When to use | Example |
|---|---|---|
| OpenAI MCP tool entry (local) | Run MCP tool servers locally | {"type": "mcp", "server_label": "...", "command": "...", "args": [...]} |
| OpenAI MCP tool entry (remote) | Call remote MCP servers | {"type": "mcp", "server_label": "...", "server_url": "...", "headers": {...}} |
| Cursor MCP config | Convert from a Cursor mcpServers JSON |
cursor_mcp_config_to_tools(cursor_config) |
| Function tools | Non-MCP tools in OpenAI function format | {"type": "function", "function": {...}} |
OpenAI MCP tool entries (local/remote)
Section titled “OpenAI MCP tool entries (local/remote)”prompt = ChatPrompt(
system="Use tools when needed.",
user="{user_query}",
tools=[
{
"type": "mcp",
"server_label": "local_docs",
"command": "npx",
"args": ["-y", "@upstash/context7-mcp"],
"env": {},
"allowed_tools": ["resolve-library-id", "query-docs"],
},
{
"type": "mcp",
"server_label": "remote_docs",
"server_url": "https://mcp.context7.com/mcp",
"headers": {"CONTEXT7_API_KEY": "YOUR_API_KEY"},
"allowed_tools": ["query-docs"],
},
],
)Cursor MCP config (JSON) → tools
Section titled “Cursor MCP config (JSON) → tools”from opik_optimizer.utils.toolcalling import cursor_mcp_config_to_tools
cursor_config = {
"mcpServers": {
"context7": {
"url": "https://mcp.context7.com/mcp",
"headers": {"CONTEXT7_API_KEY": "YOUR_API_KEY"},
}
}
}
prompt = ChatPrompt(
system="Use tools when needed.",
user="{user_query}",
tools=cursor_mcp_config_to_tools(cursor_config),
)Cursor vs OpenAI ChatPrompt styles
Section titled “Cursor vs OpenAI ChatPrompt styles”ChatPrompt.tools accepts OpenAI-style MCP entries directly. Cursor configs use a different
shape (mcpServers) and must be converted first:
# OpenAI-style MCP tool entry (directly supported by ChatPrompt.tools)
openai_tools = [
{
"type": "mcp",
"server_label": "context7",
"server_url": "https://mcp.context7.com/mcp",
"headers": {"CONTEXT7_API_KEY": "YOUR_API_KEY"},
"allowed_tools": ["resolve-library-id", "query-docs"],
}
]
# Cursor-style config (convert before assigning to ChatPrompt.tools)
cursor_config = {
"mcpServers": {
"context7": {
"url": "https://mcp.context7.com/mcp",
"headers": {"CONTEXT7_API_KEY": "YOUR_API_KEY"},
}
}
}After normalization, both styles execute the same way during evaluation and optimization.
Mixed function + MCP tools
Section titled “Mixed function + MCP tools”prompt = ChatPrompt(
system="Use tools when needed.",
user="{user_query}",
tools=[
{
"type": "function",
"function": {
"name": "search_wikipedia",
"description": "Search Wikipedia abstracts.",
"parameters": {
"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"],
},
},
},
{
"type": "mcp",
"server_label": "context7",
"server_url": "https://mcp.context7.com/mcp",
"allowed_tools": ["query-docs"],
},
],
)Target only specific tools
Section titled “Target only specific tools”When a server exposes many tools, pass a dict to select the subset you want:
result = optimizer.optimize_prompt(
prompt=prompt,
dataset=my_dataset,
metric=answer_quality,
optimize_prompts=False,
optimize_tools={
"context7.resolve-library-id": True,
"context7.query-docs": False,
},
)Tool optimization limits
Section titled “Tool optimization limits”To keep runs manageable, optimize_tools=True is limited by
DEFAULT_TOOL_CALL_MAX_TOOLS_TO_OPTIMIZE (default: 3). If you need more, pass a dict
to select a smaller subset of tools.
Disable tool use while optimizing tools
Section titled “Disable tool use while optimizing tools”If you want to optimize tool descriptions without executing tools during evaluation, set
allow_tool_use=False:
result = optimizer.optimize_prompt(
prompt=prompt,
dataset=my_dataset,
metric=answer_quality,
optimize_prompts=False,
optimize_tools=True,
allow_tool_use=False, # do not execute tools during evaluation
)What changes
Section titled “What changes”- Tool descriptions are updated.
- Tool parameter descriptions are updated.
- Prompt text stays unchanged when
optimize_prompts=False.
Where the optimized tool signature is stored
The optimized tools are returned in result.prompt.tools. History entries include both the resolved tools and the original MCP config for reproducibility.
When to use tool optimization
Section titled “When to use tool optimization”| Scenario | Use tool optimization? | Why |
|---|---|---|
| MCP client injects assistant instructions | Yes | Keep assistant text fixed and improve tool usage. |
| Prompt wording needs improvement | No | Use optimize_prompts instead. |
| Multi-agent workflows | Maybe | Optimize tools separately before agent-level changes. |
Limitations
Section titled “Limitations”- Tool optimization only supports single prompts.
- Not supported in
FewShotBayesianOptimizer,ParameterOptimizer, orGepaOptimizer.
Troubleshooting
Section titled “Troubleshooting”See tool-calling debug logs
Section titled “See tool-calling debug logs”Set the optimizer log level to surface tool calls:
export OPIK_OPTIMIZER_LOG_LEVEL=DEBUGYou’ll see tool call lines like:
tool: event=tool_call call=query-docs({...})I get “MCP remote server missing url”
Section titled “I get “MCP remote server missing url””Make sure your tool entry includes server_url (OpenAI MCP format) or url (Cursor config).
Tools are not showing up
Section titled “Tools are not showing up”- Verify the MCP server is reachable.
- If using
allowed_tools, confirm the names match the server’s tool list. - For remote servers, confirm auth headers are correct.
Tool calls are slow or failing during evaluation
Section titled “Tool calls are slow or failing during evaluation”- Set
allow_tool_use=Falseto optimize descriptions without running tools. - Reduce dataset size while iterating on tool descriptions.