dapr-agents/cookbook/mcp/workflow
Casper Nielsen f129754486
Fix/30 add linter action (#95)
* Fix: Fix Setup lint GitHub action #30

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Remove branch filter on PR and remove on push

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Remove on mergequeue

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: Add tox.ini file

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Return on push

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Chore: tox -e ruff

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Ignore .ruff_cache

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Chore: Update tox file

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Chore: Add mypy.ini

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Ignore if line is too long

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: Set the ignore in command instead

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: W503

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: F541

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: 541

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: W503

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: F541

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Chore: Ignore F401, unused imports as __init__ files has them

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Return linebreak as tox -e ruff yields that

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Ignore W503 as ruff introduces it

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: F841

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: E203

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: W293

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: W291

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: F541

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: E203

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: E203

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: W291

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: F541

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: F811

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: F841

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: F811

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: F541

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: F541

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: F841

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: F811

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: W291

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: F811

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: F541

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: F541

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Ruff want's the space before :

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Ignore space before :

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: E291

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: Add dev-requirements.txt

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: Correct python version

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: Ref dev-requirements.txt

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: Add mypy cache dir

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Chore: Update mypy version

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Fix: Exclude cookbook and quicstarts

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Remove unused import

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Chore: Add specific sub module ignore on error for future smaller fixing

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Reintroduce branches filter on push and pull_request

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* chore: Ruff

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Chore: ruff formatting

* Chore: F541

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Chore: E401

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Chore: Ruff

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Chore: F811

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Chore: F841

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Chore: Ruff

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Chore: E711

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

* Chore: ruff

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>

---------

Signed-off-by: Casper Guldbech Nielsen <scni@novonordisk.com>
2025-04-23 22:58:48 -07:00
..
components Integrate MCP Client + Enable Async Tool Execution for Agent Framework (#72) 2025-04-10 14:31:03 -07:00
README.md Integrate MCP Client + Enable Async Tool Execution for Agent Framework (#72) 2025-04-10 14:31:03 -07:00
app.py Fix/30 add linter action (#95) 2025-04-23 22:58:48 -07:00
client.py Fix/30 add linter action (#95) 2025-04-23 22:58:48 -07:00
requirements.txt Integrate MCP Client + Enable Async Tool Execution for Agent Framework (#72) 2025-04-10 14:31:03 -07:00
server.py Fix/30 add linter action (#95) 2025-04-23 22:58:48 -07:00
tools.py Fix/30 add linter action (#95) 2025-04-23 22:58:48 -07:00

README.md

MCP Agent with Dapr Workflows

This demo shows how to run an AI agent inside a Dapr Workflow, calling tools exposed via the Model Context Protoco (MCP).

Unlike the lightweight notebook-based examples, this setup runs a full Dapr agent using:

Durable task orchestration with Dapr Workflows Tools served via MCP (stdio or SSE) Full integration with the Dapr ecosystem

🛠️ Project Structure

.
├── app.py           # Main entrypoint: runs a Dapr Agent and workflow on port 8001
├── tools.py         # MCP tool definitions (get_weather, jump)
├── server.py        # Starlette-based SSE server
|-- client.py        # Script to send an HTTP request to the Agent over port 8001
├── components/      # Dapr pubsub + state components (Redis, etc.)
├── requirements.txt
└── README.md

📦 Installation

Install dependencies:

pip install -r requirements.txt

Make sure you have Dapr installed and initialized:

dapr init

🧰 MCP Tool Server

Your agent will call tools defined in tools.py, served via FastMCP:

@mcp.tool()
async def get_weather(location: str) -> str:
    ...

@mcp.tool()
async def jump(distance: str) -> str:
    ...

These tools can be served in one of two modes:

STDIO Mode (local execution)

No external server needed — the agent runs the MCP server in-process.

Best for internal experiments or testing 🚫 Not supported for agents that rely on external workflows (e.g., Dapr orchestration)

In this demo, we run the MCP server as a separate Starlette + Uvicorn app:

python server.py --server_type sse --host 127.0.0.1 --port 8000

This exposes:

  • /sse for the SSE stream
  • /messages/ for tool execution

Used by the Dapr agent in this repo.

🚀 Running the Dapr Agent

Start the MCP server in SSE mode:

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

Then in a separate terminal, run the agent workflow:

dapr run --app-id weatherappmcp --resources-path components/ -- python app.py

Once agent is ready, run the client.py script to send a message to it.

python3 client.py

You will see the state of the agent in a json file in the same directory.

{
    "instances": {
        "e098e5b85d544c84a26250be80316152": {
            "input": "What is the weather in New York?",
            "output": "The current temperature in New York, USA, is 66\u00b0F.",
            "start_time": "2025-04-05T05:37:50.496005",
            "end_time": "2025-04-05T05:37:52.501630",
            "messages": [
                {
                    "id": "e8ccc9d2-1674-47cc-afd2-8e68b91ff791",
                    "role": "user",
                    "content": "What is the weather in New York?",
                    "timestamp": "2025-04-05T05:37:50.516572",
                    "name": null
                },
                {
                    "id": "47b8db93-558c-46ed-80bb-8cb599c4272b",
                    "role": "assistant",
                    "content": "The current temperature in New York, USA, is 66\u00b0F.",
                    "timestamp": "2025-04-05T05:37:52.499945",
                    "name": null
                }
            ],
            "last_message": {
                "id": "47b8db93-558c-46ed-80bb-8cb599c4272b",
                "role": "assistant",
                "content": "The current temperature in New York, USA, is 66\u00b0F.",
                "timestamp": "2025-04-05T05:37:52.499945",
                "name": null
            },
            "tool_history": [
                {
                    "content": "New York, USA: 66F.",
                    "role": "tool",
                    "tool_call_id": "call_LTDMHvt05e1tvbWBe0kVvnUM",
                    "id": "2c1535fe-c43a-42c1-be7e-25c71b43c32e",
                    "function_name": "LocalGetWeather",
                    "function_args": "{\"location\":\"New York, USA\"}",
                    "timestamp": "2025-04-05T05:37:51.609087"
                }
            ],
            "source": null,
            "source_workflow_instance_id": null
        }
    }
}