Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions examples/basic/mcp_server_aggregator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
62 changes: 44 additions & 18 deletions examples/basic/mcp_server_aggregator/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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
Expand All @@ -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
Expand Down
Loading