Skip to content

Reorganize MCP quickstart examples and add SSE implementation #120

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ services:
image: localhost:5001/workflow-llm:latest
build:
context: ../
dockerfile: ./07-k8s-multi-agent-workflow/services/workflow-llm/Dockerfile
dockerfile: ./05-multi-agent-workflow-k8s/services/workflow-llm/Dockerfile
elf:
image: localhost:5001/elf:latest
build:
context: ../
dockerfile: ./07-k8s-multi-agent-workflow/services/elf/Dockerfile
dockerfile: ./05-multi-agent-workflow-k8s/services/elf/Dockerfile
hobbit:
image: localhost:5001/hobbit:latest
build:
context: ../
dockerfile: ./07-k8s-multi-agent-workflow/services/hobbit/Dockerfile
dockerfile: ./05-multi-agent-workflow-k8s/services/hobbit/Dockerfile
wizard:
image: localhost:5001/wizard:latest
build:
context: ../
dockerfile: ./07-k8s-multi-agent-workflow/services/wizard/Dockerfile
dockerfile: ./05-multi-agent-workflow-k8s/services/wizard/Dockerfile
155 changes: 155 additions & 0 deletions quickstarts/07-agent-mcp-client-sse/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# MCP Agent with SSE Transport

This quickstart demonstrates how to build a simple agent that uses tools exposed via the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) over SSE (Server-Sent Events) transport. You'll learn how to create MCP tools in a standalone server and connect to them using SSE communication.

## Prerequisites

- Python 3.10 (recommended)
- pip package manager
- OpenAI API key

## Environment Setup

```bash
# Create a virtual environment
python3.10 -m venv .venv

# Activate the virtual environment
# On Windows:
.venv\Scripts\activate
# On macOS/Linux:
source .venv/bin/activate

# Install dependencies
pip install -r requirements.txt
```

## Configuration

Create a `.env` file in the project root:

```env
OPENAI_API_KEY=your_api_key_here
```

Replace `your_api_key_here` with your actual OpenAI API key.

## Examples

### MCP Tool Creation

First, create MCP tools in `tools.py`:

```python
mcp = FastMCP("TestServer")

@mcp.tool()
async def get_weather(location: str) -> str:
"""Get weather information for a specific location."""
temperature = random.randint(60, 80)
return f"{location}: {temperature}F."
```

### SSE Server Creation

Set up the SSE server for your MCP tools in `server.py`.

### Agent Creation

Create the agent that connects to these tools in `app.py` over MCP with SSE transport:

```python
# Load MCP tools from server using SSE
client = MCPClient()
await client.connect_sse("local", url="http://localhost:8000/sse")
tools = client.get_all_tools()

# Create the Weather Agent using MCP tools
weather_agent = AssistantAgent(
role="Weather Assistant",
name="Stevie",
goal="Help humans get weather and location info using smart tools.",
instructions=["Instrictions go here"],
tools=tools,
message_bus_name="messagepubsub",
state_store_name="workflowstatestore",
state_key="workflow_state",
agents_registry_store_name="agentstatestore",
agents_registry_key="agents_registry",
).as_service(port=8001)

```

### Running the Example

1. Start the MCP server in SSE mode:

```bash
python server.py --server_type sse --port 8000
```

2. In a separate terminal window, start the agent with Dapr:

```bash
dapr run --app-id weatherappmcp --app-port 8001 --dapr-http-port 3500 --resources-path ./components/ -- python app.py
```

3. Send a test request to the agent:

```bash
curl -X POST http://localhost:8001/start-workflow \
-H "Content-Type: application/json" \
-d '{"task": "What is the weather in New York?"}'
```

**Expected output:** The agent will initialize the MCP client, connect to the tools module via SSE transport, and fetch weather information for New York using the MCP tools. The results will be stored in state files.

## Key Concepts

### MCP Tool Definition
- The `@mcp.tool()` decorator registers functions as MCP tools
- Each tool has a docstring that helps the LLM understand its purpose

### SSE Transport
- SSE (Server-Sent Events) transport enables network-based communication
- Perfect for distributed setups where tools run as separate services
- Allows multiple agents to connect to the same tool server

### Dapr Integration
- The `AssistantAgent` class creates a service that runs inside a Dapr workflow
- Dapr components (pubsub, state stores) manage message routing and state persistence
- The agent's conversation history and tool calls are saved in Dapr state stores

### Execution Flow
1. MCP server starts with tools exposed via SSE endpoint
2. Agent connects to the MCP server via SSE
3. The agent receives a user query via HTTP
4. The LLM determines which MCP tool to use
5. The agent sends the tool call to the MCP server
6. The server executes the tool and returns the result
7. The agent formulates a response based on the tool result
8. State is saved in the configured Dapr state store

## Alternative: Using STDIO Transport

While this quickstart uses SSE transport, MCP also supports STDIO for process-based communication. This approach is useful when:

- Tools need to run in the same process as the agent
- Simplicity is preferred over network distribution
- You're developing locally and don't need separate services

To explore STDIO transport, check out the related [MCP with STDIO Transport quickstart](../07-agent-mcp-client-stdio).

## Troubleshooting

1. **OpenAI API Key**: Ensure your key is correctly set in the `.env` file
2. **Server Connection**: If you see SSE connection errors, make sure the server is running on the correct port
3. **Dapr Setup**: Verify that Dapr is installed and that Redis is running for state stores
4. **Module Import Errors**: Verify that all dependencies are installed correctly

## Next Steps

After completing this quickstart, you might want to explore:
- Creating more complex MCP tools with actual API integrations
- Deploying your agent as a Dapr microservice in Kubernetes
- Exploring the [MCP specification](https://modelcontextprotocol.io/) for advanced usage
46 changes: 46 additions & 0 deletions quickstarts/07-agent-mcp-client-sse/Stevie_state.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"instances": {
"5d29bf0f6b90420fb4fbda02ea8f3abd": {
"input": "What is the weather in New York",
"output": "The current temperature in New York is 63\u00b0F. If you need any more information or have other questions, feel free to ask!",
"start_time": "2025-05-02T20:30:21.825508",
"end_time": "2025-05-02T20:30:23.623042",
"messages": [
{
"id": "d908b272-55bd-4374-b7ab-f6c69e394709",
"role": "user",
"content": "What is the weather in New York",
"timestamp": "2025-05-02T20:30:21.831930",
"name": null
},
{
"id": "53da56c6-f149-45c5-a712-d2f8f9e4ec90",
"role": "assistant",
"content": "The current temperature in New York is 63\u00b0F. If you need any more information or have other questions, feel free to ask!",
"timestamp": "2025-05-02T20:30:23.620126",
"name": null
}
],
"last_message": {
"id": "53da56c6-f149-45c5-a712-d2f8f9e4ec90",
"role": "assistant",
"content": "The current temperature in New York is 63\u00b0F. If you need any more information or have other questions, feel free to ask!",
"timestamp": "2025-05-02T20:30:23.620126",
"name": null
},
"tool_history": [
{
"content": "New York: 63F.",
"role": "tool",
"tool_call_id": "call_qc2s8yGF5clDeEEmwzwIXVvG",
"id": "aebc3147-4ca6-4747-9ef8-03c1eb526f70",
"function_name": "LocalGetWeather",
"function_args": "{\"location\":\"New York\"}",
"timestamp": "2025-05-02T20:30:22.632999"
}
],
"source": null,
"source_workflow_instance_id": null
}
}
}
46 changes: 46 additions & 0 deletions quickstarts/07-agent-mcp-client-sse/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import asyncio
import logging
from dotenv import load_dotenv

from dapr_agents import AssistantAgent
from dapr_agents.tool.mcp import MCPClient


async def main():
try:
# Load MCP tools from server (stdio or sse)
client = MCPClient()
await client.connect_sse("local", url="http://localhost:8000/sse")

# Convert MCP tools to AgentTool list
tools = client.get_all_tools()

# Create the Weather Agent using those tools
weather_agent = AssistantAgent(
role="Weather Assistant",
name="Stevie",
goal="Help humans get weather and location info using smart tools.",
instructions=[
"Respond clearly and helpfully to weather-related questions.",
"Use tools when appropriate to fetch or simulate weather data.",
"You may sometimes jump after answering the weather question.",
],
tools=tools,
message_bus_name="messagepubsub",
state_store_name="workflowstatestore",
state_key="workflow_state",
agents_registry_store_name="agentstatestore",
agents_registry_key="agents_registry",
).as_service(port=8001)

# Start the FastAPI agent service
await weather_agent.start()

except Exception as e:
logging.exception("Error starting weather agent service", exc_info=e)


if __name__ == "__main__":
load_dotenv()
logging.basicConfig(level=logging.INFO)
asyncio.run(main())
12 changes: 12 additions & 0 deletions quickstarts/07-agent-mcp-client-sse/components/pubsub.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: messagepubsub
spec:
type: pubsub.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""
16 changes: 16 additions & 0 deletions quickstarts/07-agent-mcp-client-sse/components/statestore.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: agentstatestore
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""
- name: keyPrefix
value: none
- name: actorStateStore
value: "true"
12 changes: 12 additions & 0 deletions quickstarts/07-agent-mcp-client-sse/components/workflowstate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: workflowstatestore
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""
6 changes: 6 additions & 0 deletions quickstarts/07-agent-mcp-client-sse/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
dapr-agents>=0.5.0
python-dotenv
mcp
starlette
uvicorn
requests
Loading