From e120146277220bccb0cb19d088be90fb2502b562 Mon Sep 17 00:00:00 2001 From: George Pickett Date: Fri, 4 Sep 2026 19:00:51 -0700 Subject: [PATCH 1/2] Python: Document anonymous Parallel Search MCP usage --- python/samples/02-agents/mcp/README.md | 53 ++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/python/samples/02-agents/mcp/README.md b/python/samples/02-agents/mcp/README.md index e3fce52794b..bcdd868be50 100644 --- a/python/samples/02-agents/mcp/README.md +++ b/python/samples/02-agents/mcp/README.md @@ -17,6 +17,59 @@ The Model Context Protocol (MCP) is an open standard for connecting AI agents to | **Progressive Disclosure** | [`mcp_progressive_disclosure.py`](mcp_progressive_disclosure.py) | Demonstrates `use_progressive_disclosure`, `always_load`, `allowed_tools`, and prefixed `list_mcp_tools` / `load_tool` / `unload_tool` names. `load_tool` and `unload_tool` can accept one tool name or multiple names. Self-spawns a stdio MCP child server | | **Sampling Approval** | [`mcp_sampling_approval.py`](mcp_sampling_approval.py) | Demonstrates gating server-initiated `sampling/createMessage` requests with a `sampling_approval_callback`, plus the `sampling_max_tokens` and `sampling_max_requests` guardrails. MCP sampling is denied by default | +## Anonymous web search and fetch + +Use `MCPStreamableHTTPTool` with [Parallel Search MCP](https://docs.parallel.ai/integrations/mcp/search-mcp) to search the public web and extract page content. This example calls the tools directly, so it needs neither a Parallel API key nor a model provider account. Free access is rate limited. + +Install the client dependencies in a Python 3.10+ environment: + +```bash +pip install agent-framework-core "mcp>=1.24,<2" +``` + +Save this as `parallel_search.py` and run `python parallel_search.py`: + +```python +import asyncio +from uuid import uuid4 + +from agent_framework import MCPStreamableHTTPTool + + +async def main() -> None: + session_id = str(uuid4()) # Reuse for related search and fetch calls. + async with MCPStreamableHTTPTool( + name="parallel-search", + url="https://search.parallel.ai/mcp", + load_prompts=False, + request_timeout=30, + ) as mcp: + print("Tools:", [tool.name for tool in mcp.functions]) + search_result = await mcp.call_tool( + "web_search", + objective="Find Microsoft Agent Framework MCP documentation", + search_queries=["Microsoft Agent Framework MCP tools"], + session_id=session_id, + ) + fetch_result = await mcp.call_tool( + "web_fetch", + urls=["https://github.com/microsoft/agent-framework"], + objective="Describe the framework's MCP support", + session_id=session_id, + ) + for result in (search_result, fetch_result): + for content in result: + if content.type == "text": + print(content.text) + + +asyncio.run(main()) +``` + +The output lists `web_search` and `web_fetch`, followed by their results, including source URLs and excerpts. Queries, requested URLs, objectives, and the session identifier are sent to Parallel when the calls run. The context manager closes the connection afterward. + +To make these tools available to an existing agent, pass the MCP tool as `tools` when constructing `Agent`. The agent can then choose to invoke them during a run; remove that tool to disable access. This example does not change any configured providers or defaults. + ## Prerequisites Most samples in this folder use OpenAI: From ea61d66c7f3c02db72153364276f57ba951c0c6a Mon Sep 17 00:00:00 2001 From: George Pickett Date: Fri, 4 Sep 2026 19:43:31 -0700 Subject: [PATCH 2/2] Python: Avoid duplicate MCP sample output and guard entry point --- python/samples/02-agents/mcp/README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/python/samples/02-agents/mcp/README.md b/python/samples/02-agents/mcp/README.md index bcdd868be50..83013a0e896 100644 --- a/python/samples/02-agents/mcp/README.md +++ b/python/samples/02-agents/mcp/README.md @@ -43,6 +43,8 @@ async def main() -> None: url="https://search.parallel.ai/mcp", load_prompts=False, request_timeout=30, + # Use the text payload once; Parallel also returns it as structured content. + parse_tool_results=lambda result: "\n".join(c.text for c in result.content if c.type == "text"), ) as mcp: print("Tools:", [tool.name for tool in mcp.functions]) search_result = await mcp.call_tool( @@ -58,12 +60,11 @@ async def main() -> None: session_id=session_id, ) for result in (search_result, fetch_result): - for content in result: - if content.type == "text": - print(content.text) + print(result) -asyncio.run(main()) +if __name__ == "__main__": + asyncio.run(main()) ``` The output lists `web_search` and `web_fetch`, followed by their results, including source URLs and excerpts. Queries, requested URLs, objectives, and the session identifier are sent to Parallel when the calls run. The context manager closes the connection afterward.