Skip to main content
Opik Documentation

Search documentation

Type to search this documentation.

On this pageOverview

Optimize tools (MCP)

Use this guide when you want to optimize tool signatures (descriptions + parameter descriptions) separately from prompt text or agent logic.

  • 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.
Python
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).

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.

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": {...}}
Python
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"],
        },
    ],
)
Python
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),
)

ChatPrompt.tools accepts OpenAI-style MCP entries directly. Cursor configs use a different shape (mcpServers) and must be converted first:

Python
# 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.

Python
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"],
        },
    ],
)

When a server exposes many tools, pass a dict to select the subset you want:

Python
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,
    },
)

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.

If you want to optimize tool descriptions without executing tools during evaluation, set allow_tool_use=False:

Python
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
)
  • 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.

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.
  • Tool optimization only supports single prompts.
  • Not supported in FewShotBayesianOptimizer, ParameterOptimizer, or GepaOptimizer.

Set the optimizer log level to surface tool calls:

Bash
export OPIK_OPTIMIZER_LOG_LEVEL=DEBUG

You’ll see tool call lines like:

tool: event=tool_call call=query-docs({...})

Make sure your tool entry includes server_url (OpenAI MCP format) or url (Cursor config).

  • 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=False to optimize descriptions without running tools.
  • Reduce dataset size while iterating on tool descriptions.
Suggest an edit

Propose a replacement for this page. The site team reviews it before applying any changes.

Export
Documentation menu