diff --git a/examples/basic/mcp_server_aggregator/README.md b/examples/basic/mcp_server_aggregator/README.md index 82eb4231a..49368635a 100644 --- a/examples/basic/mcp_server_aggregator/README.md +++ b/examples/basic/mcp_server_aggregator/README.md @@ -57,3 +57,57 @@ Run your MCP Agent app: ```bash uv run main.py ``` + +## `4` [Beta] Deploy to the cloud + +### `a.` Log in to [MCP Agent Cloud](https://docs.mcp-agent.com/cloud/overview) + +```bash +uv run mcp-agent login +``` + +### `b.` Deploy your agent with a single command +```bash +uv run mcp-agent deploy mcp-server-aggregator +``` + +### `c.` Connect to your deployed agent as an MCP server through any MCP client + +#### Claude Desktop Integration + +Configure Claude Desktop to access your agent servers by updating your `~/.claude-desktop/config.json`: + +```json +"my-agent-server": { + "command": "/path/to/npx", + "args": [ + "mcp-remote", + "https://[your-agent-server-id].deployments.mcp-agent-cloud.lastmileai.dev/sse", + "--header", + "Authorization: Bearer ${BEARER_TOKEN}" + ], + "env": { + "BEARER_TOKEN": "your-mcp-agent-cloud-api-token" + } +} +``` + +#### MCP Inspector + +Use MCP Inspector to explore and test your agent servers: + +```bash +npx @modelcontextprotocol/inspector +``` + +Make sure to fill out the following settings: + +| Setting | Value | +|---|---| +| *Transport Type* | *SSE* | +| *SSE* | *https://[your-agent-server-id].deployments.mcp-agent-cloud.lastmileai.dev/sse* | +| *Header Name* | *Authorization* | +| *Bearer Token* | *your-mcp-agent-cloud-api-token* | + +> [!TIP] +> In the Configuration, change the request timeout to a longer time period. Since your agents are making LLM calls, it is expected that it should take longer than simple API calls. diff --git a/examples/basic/mcp_server_aggregator/main.py b/examples/basic/mcp_server_aggregator/main.py index 911504dc9..8ee87e4d0 100644 --- a/examples/basic/mcp_server_aggregator/main.py +++ b/examples/basic/mcp_server_aggregator/main.py @@ -8,8 +8,16 @@ app = MCPApp(name="mcp_server_aggregator") - -async def example_usage_persistent(): +@app.tool +async def example_usage_persistent()->str: + ''' + this example function/tool call will use an MCP aggregator + to connect to both the file and filesystem servers and + aggregate them together, so you can list all tool calls from + both servers at once. The connections to the servers will + be persistent. + ''' + result="" context = app.context logger = get_logger("mcp_server_aggregator.example_usage_persistent") @@ -26,31 +34,43 @@ async def example_usage_persistent(): ) # Call list_tools on the aggregator, which will search all servers for the tool logger.info("Aggregator: Calling list_tools...") - result = await aggregator.list_tools() - logger.info("Tools available:", data=result) + output = await aggregator.list_tools() + logger.info("Tools available:", data=output) + result+="Tools available:"+str(output) # Call read_file on the aggregator, which will search all servers for the tool - result = await aggregator.call_tool( - name="read_file", + output = await aggregator.call_tool( + name="read_text_file", arguments={"path": str(Path.cwd() / "README.md")}, ) - logger.info("read_file result:", data=result) + logger.info("read_text_file result:", data=output) + result+="\n\nread_text_file result:" + str(output) # Call fetch.fetch on the aggregator # (i.e. server-namespacing -- fetch is the servername, which exposes fetch tool) - result = await aggregator.call_tool( + output = await aggregator.call_tool( name="fetch_fetch", arguments={"url": "https://jsonplaceholder.typicode.com/todos/1"}, ) - logger.info("fetch result:", data=result) + logger.info("fetch result:", data=output) + result+=f"\n\nfetch result: {str(output)}" except Exception as e: logger.error("Error in example_usage_persistent:", data=e) finally: logger.info("Closing all server connections on aggregator...") await aggregator.close() - -async def example_usage(): + return result + +@app.tool +async def example_usage()->str: + ''' + this example function/tool call will use an MCP aggregator + to connect to both the file and filesystem servers and + aggregate them together, so you can list all tool calls from + both servers at once. + ''' + result="" logger = get_logger("mcp_server_aggregator.example_usage") context = app.context @@ -67,29 +87,35 @@ async def example_usage(): ) # Call list_tools on the aggregator, which will search all servers for the tool logger.info("Aggregator: Calling list_tools...") - result = await aggregator.list_tools() - logger.info("Tools available:", data=result) + output = await aggregator.list_tools() + logger.info("Tools available:", data=output) + result+="Tools available:"+str(output) # Call read_file on the aggregator, which will search all servers for the tool - result = await aggregator.call_tool( - name="read_file", + output = await aggregator.call_tool( + name="read_text_file", arguments={"path": str(Path.cwd() / "README.md")}, ) - logger.info("read_file result:", data=result) + logger.info("read_text_file result:", data=output) + result+="\n\nread_text_file result:" + str(output) # Call fetch.fetch on the aggregator # (i.e. server-namespacing -- fetch is the servername, which exposes fetch tool) - result = await aggregator.call_tool( + output = await aggregator.call_tool( name="fetch_fetch", arguments={"url": "https://jsonplaceholder.typicode.com/todos/1"}, ) - logger.info(f"fetch result: {str(result)}") + logger.info(f"fetch result: {str(output)}") + result+=f"\n\nfetch result: {str(output)}" except Exception as e: logger.error("Error in example_usage:", data=e) finally: logger.info("Closing all server connections on aggregator...") await aggregator.close() + print(result) + + return result if __name__ == "__main__": import time