Files
openai--openai-agents-python/examples/mcp/get_all_mcp_tools_example/main.py
T
2026-07-13 12:39:17 +08:00

138 lines
5.5 KiB
Python

import asyncio
import os
import shutil
from typing import Any
from agents import Agent, Runner, gen_trace_id, trace
from agents.mcp import MCPServer, MCPServerStdio
from agents.mcp.util import MCPUtil, create_static_tool_filter
from agents.run_context import RunContextWrapper
from examples.auto_mode import confirm_with_fallback, is_auto_mode
async def list_tools(server: MCPServer, *, convert_to_strict: bool) -> list[Any]:
"""Fetch all MCP tools from the server."""
run_context: RunContextWrapper[dict[str, str]] = RunContextWrapper(context={})
agent = Agent(name="ToolFetcher", instructions="Prefetch MCP tools.", mcp_servers=[server])
return await MCPUtil.get_all_function_tools(
[server],
convert_schemas_to_strict=convert_to_strict,
run_context=run_context,
agent=agent,
)
def prompt_user_approval(interruption_name: str) -> bool:
"""Ask the user to approve a tool call and return the decision."""
if is_auto_mode():
return confirm_with_fallback(
f"Approve tool call '{interruption_name}'? (y/n): ",
default=True,
)
while True:
user_input = input(f"Approve tool call '{interruption_name}'? (y/n): ").strip().lower()
if user_input == "y":
return True
if user_input == "n":
return False
print("Please enter 'y' or 'n'.")
async def resolve_interruptions(agent: Agent, result: Any) -> Any:
"""Prompt for approvals until no interruptions remain."""
current_result = result
while current_result.interruptions:
state = current_result.to_state()
# Human in the loop: prompt for approval on each tool call.
for interruption in current_result.interruptions:
if prompt_user_approval(interruption.name):
print(f"Approving a tool call... (name: {interruption.name})")
state.approve(interruption)
else:
print(f"Rejecting a tool call... (name: {interruption.name})")
state.reject(interruption)
current_result = await Runner.run(agent, state)
return current_result
async def main():
current_dir = os.path.dirname(os.path.abspath(__file__))
samples_dir = os.path.join(current_dir, "sample_files")
blocked_path = os.path.join(samples_dir, "test.txt")
async with MCPServerStdio(
name="Filesystem Server",
params={
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", samples_dir],
"cwd": samples_dir,
},
require_approval={"always": {"tool_names": ["read_text_file"]}},
) as server:
trace_id = gen_trace_id()
with trace(workflow_name="MCP get_all_mcp_tools Example", trace_id=trace_id):
print(f"View trace: https://platform.openai.com/traces/trace?trace_id={trace_id}\n")
print("=== Fetching all tools with strict schemas ===")
all_tools = await list_tools(server, convert_to_strict=True)
print(f"Found {len(all_tools)} tool(s):")
for tool in all_tools:
description = getattr(tool, "description", "") or ""
print(f"- {tool.name}: {description}")
# Build an agent that uses the prefetched tools instead of mcp_servers.
prefetched_agent = Agent(
name="Prefetched MCP Assistant",
instructions=(
"Use the prefetched tools to help with file questions. "
"When using path arguments, prefer absolute paths in the allowed directory."
),
tools=all_tools,
)
message = (
f"List files in this allowed directory: {samples_dir}. "
"Then read one of those files."
)
print(f"\nRunning: {message}\n")
result = await Runner.run(prefetched_agent, message)
result = await resolve_interruptions(prefetched_agent, result)
print(result.final_output)
# Apply a static tool filter and refetch tools.
server.tool_filter = create_static_tool_filter(
allowed_tool_names=["read_file", "list_directory"]
)
filtered_tools = await list_tools(server, convert_to_strict=False)
print("\n=== After applying tool filter ===")
print(f"Found {len(filtered_tools)} tool(s):")
for tool in filtered_tools:
print(f"- {tool.name}")
filtered_agent = Agent(
name="Filtered MCP Assistant",
instructions=(
"Use the filtered tools to respond. "
"If a request requires a missing tool, explain that the capability is not "
"available."
),
tools=filtered_tools,
)
blocked_message = (
f'Create a file named "{blocked_path}" with the text "hello". '
"If the available tools cannot create files, explain that clearly."
)
print(f"\nRunning: {blocked_message}\n")
filtered_result = await Runner.run(filtered_agent, blocked_message)
filtered_result = await resolve_interruptions(filtered_agent, filtered_result)
print(filtered_result.final_output)
if __name__ == "__main__":
if not shutil.which("npx"):
raise RuntimeError("npx is required. Install it with `npm install -g npx`.")
asyncio.run(main())