# How to Integrate Managed MCP Services (Composio, Zapier, MCP.so) with the Dify MCP SSE Plugin

> Integrate Dify with MCP services like Composio Zapier and MCPso using the dify-plugin-agent-mcp_sse. Stream requests and receive real-time responses via SSE with a unified client wrapper.

- Repository: [Junjie.M/dify-plugin-agent-mcp_sse](https://github.com/junjiem/dify-plugin-agent-mcp_sse)
- Tags: how-to-guide
- Published: 2026-03-05

---

**The dify-plugin-agent-mcp_sse plugin enables Dify to stream requests to managed MCP services like Composio, Zapier, and MCP.so via Server-Sent Events (SSE), using a unified client wrapper that handles authentication and real-time response streaming.**

The **junjiem/dify-plugin-agent-mcp_sse** repository provides a production-ready Dify plugin that bridges your AI workflows with external Managed Chat-Processing (MCP) platforms. By leveraging SSE connections, the plugin maintains persistent streams to managed services while translating between Dify's internal protocol and vendor-specific MCP implementations.

## Architecture Overview

The plugin architecture consists of three core components that handle the end-to-end integration:

| Component | Role | Key Source File |
|-----------|------|-----------------|
| **Dify Plugin Entry Point** | Receives Dify requests, builds SSE streams, and forwards to MCP backends | [`main/agent_mcp_sse.py`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/main/agent_mcp_sse.py) |
| **MCP Client Wrapper** | Manages HTTP SSE connections, retries, and protocol translation | [`main/mcp_client.py`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/main/mcp_client.py) |
| **Configuration Layer** | Stores API URLs and authentication tokens for each MCP provider | [`main/config.yaml`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/main/config.yaml) |

When Dify invokes the plugin, the system loads provider-specific credentials from [`config.yaml`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/config.yaml), establishes an SSE connection through `MCPClient`, and streams real-time responses back to the Dify UI.

## Configuration Setup

Before integrating with managed MCP services, you must populate [`main/config.yaml`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/main/config.yaml) with endpoint URLs and authentication credentials:

```yaml
composio:
  api_url: "https://api.composio.dev/v1/sse"
  api_key: "your-composio-api-key"

zapier:
  webhook_url: "https://hooks.zapier.com/hooks/catch/your/webhook/token"

mcpso:
  endpoint: "https://api.mcp.so/v1/stream"
  token: "your-mcp.so-bearer-token"

```

The plugin dynamically selects the appropriate configuration section based on the `provider` parameter passed in the Dify request payload.

## Integration Steps for Each Managed MCP Service

### Composio

**Composio** provides a dedicated SSE endpoint for AI agent integrations.

- **Endpoint:** `https://api.composio.dev/v1/sse`
- **Authentication:** API key passed in the `X-API-Key` header
- **Implementation:** In [`main/mcp_client.py`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/main/mcp_client.py), instantiate the client with Composio-specific headers:

```python
from mcp_client import MCPClient

client = MCPClient(
    base_url="https://api.composio.dev/v1/sse",
    headers={"X-API-Key": CONFIG["composio"]["api_key"]},
)

async for event in client.stream(payload):
    # Transform and yield to Dify

    yield f"data: {json.dumps({'event': 'message', 'data': event})}\n\n"

```

### Zapier

**Zapier** exposes MCP functionality through webhook triggers that support SSE responses.

- **Endpoint:** User-specific webhook URL (obtained from Zapier's "Webhooks by Zapier" trigger)
- **Authentication:** Token embedded in the URL query parameters (`?token=...`)
- **Implementation:** Store the complete webhook URL in [`config.yaml`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/config.yaml) and pass it directly to the client:

```python
client = MCPClient(
    base_url=CONFIG["zapier"]["webhook_url"]
)

```

The `MCPClient` handles the SSE stream parsing, converting Zapier's event format into Dify-compatible chunks.

### MCP.so

**MCP.so** offers a streaming API endpoint with Bearer token authentication.

- **Endpoint:** `https://api.mcp.so/v1/stream`
- **Authentication:** Bearer token in the `Authorization` header
- **Implementation:** Configure the client with the Bearer scheme:

```python
client = MCPClient(
    base_url="https://api.mcp.so/v1/stream",
    headers={"Authorization": f"Bearer {CONFIG['mcpso']['token']}"}
)

```

The plugin maintains the persistent connection to MCP.so, forwarding each SSE event through to Dify's frontend in real time.

## Implementation Example

The following complete example from [`main/agent_mcp_sse.py`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/main/agent_mcp_sse.py) demonstrates dynamic provider selection and SSE streaming:

```python
import json
from fastapi import Request, Response
from mcp_client import MCPClient
from config import CONFIG

async def sse_handler(request: Request):
    body = await request.json()
    provider = body.get("provider", "composio").lower()
    payload = body.get("payload", {})

    # Resolve configuration for the chosen provider

    if provider == "composio":
        client = MCPClient(
            base_url="https://api.composio.dev/v1/sse",
            headers={"X-API-Key": CONFIG["composio"]["api_key"]},
        )
    elif provider == "zapier":
        client = MCPClient(base_url=CONFIG["zapier"]["webhook_url"])
    elif provider == "mcpso":
        client = MCPClient(
            base_url="https://api.mcp.so/v1/stream",
            headers={"Authorization": f"Bearer {CONFIG['mcpso']['token']}"}
        )
    else:
        return Response(
            content=json.dumps({"error": "Unsupported provider"}),
            status_code=400,
            media_type="application/json"
        )

    async def event_generator():
        async for event in client.stream(payload):
            dify_msg = {"event": "message", "data": event}
            yield f"data: {json.dumps(dify_msg)}\n\n"

    return Response(
        content=event_generator(),
        media_type="text/event-stream"
    )

```

**Key implementation details:**

- **Dynamic provider selection** – the handler inspects the `provider` field from the Dify payload to instantiate the correct client configuration.
- **Unified streaming interface** – `MCPClient.stream()` abstracts SSE parsing, allowing the same `event_generator()` logic to work across all three services.
- **Protocol translation** – each event from the MCP service is wrapped in a Dify-compatible JSON structure before being yielded as an SSE data frame.
- **Graceful error handling** – unsupported providers trigger an immediate HTTP 400 response with a descriptive JSON error body.

## Key Files in the Repository

| File | Purpose | GitHub Link |
|------|---------|-------------|
| [`agent_mcp_sse.py`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/agent_mcp_sse.py) | Main Dify plugin entry point that receives HTTP requests and initiates SSE streams | [View source](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/agent_mcp_sse.py) |
| [`mcp_client.py`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/mcp_client.py) | Wrapper around `httpx.AsyncClient` that manages persistent SSE connections to MCP backends | [View source](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/mcp_client.py) |
| [`config.yaml`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/config.yaml) | Centralized configuration for endpoint URLs and authentication tokens across all supported MCP providers | [View source](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/config.yaml) |
| [`README.md`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/README.md) | Documentation covering installation, environment setup, and basic usage examples | [View source](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/README.md) |

## Summary

Integrating managed MCP services with Dify requires three core steps:

- **Configure authentication** in [`main/config.yaml`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/main/config.yaml) with provider-specific endpoints and tokens for Composio, Zapier, or MCP.so.
- **Instantiate MCPClient** with the appropriate `base_url` and headers, which handles SSE connection management and retry logic.
- **Stream responses** through the unified `client.stream()` interface, transforming MCP events into Dify-compatible JSON chunks for real-time UI updates.

The plugin architecture abstracts provider differences, allowing you to switch between Composio's API key authentication, Zapier's webhook tokens, and MCP.so's Bearer tokens without modifying the core streaming logic.

## Frequently Asked Questions

### What is the primary benefit of using SSE for MCP service integration?

Server-Sent Events (SSE) provide a unidirectional streaming connection that allows managed MCP services to push real-time updates to Dify without the overhead of WebSocket handshakes or polling. According to the source code in [`main/mcp_client.py`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/main/mcp_client.py), the plugin maintains a persistent HTTP connection with `Accept: text/event-stream`, enabling low-latency token streaming from providers like Composio and MCP.so directly to the Dify frontend.

### How does the plugin handle authentication for different MCP providers?

The plugin uses a configuration-driven approach where [`main/config.yaml`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/main/config.yaml) stores provider-specific credentials. For **Composio**, the API key is passed in the `X-API-Key` header; for **Zapier**, the authentication token is embedded directly in the webhook URL; and for **MCP.so**, a Bearer token is sent via the `Authorization` header. The `MCPClient` class in [`main/mcp_client.py`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/main/mcp_client.py) accepts these headers during instantiation, ensuring each provider's security requirements are met without hardcoding credentials in the business logic.

### Can I use multiple MCP providers simultaneously in the same Dify workflow?

Yes, the plugin supports dynamic provider selection on a per-request basis. As shown in [`main/agent_mcp_sse.py`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/main/agent_mcp_sse.py), the `sse_handler` function inspects the `provider` field from the incoming Dify payload to instantiate the appropriate `MCPClient` configuration. This allows a single Dify workflow to route different tasks to different backends—for example, sending data processing jobs to Composio while routing automation triggers to Zapier—without deploying separate plugin instances.

### Where can I find the complete source code for this integration?

The complete implementation is available in the **junjiem/dify-plugin-agent-mcp_sse** repository on GitHub. The critical files for managed service integration are located in the `main/` directory: [`agent_mcp_sse.py`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/agent_mcp_sse.py) contains the FastAPI entry point, [`mcp_client.py`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/mcp_client.py) implements the SSE streaming logic, and [`config.yaml`](https://github.com/junjiem/dify-plugin-agent-mcp_sse/blob/main/config.yaml) defines the provider-specific endpoints and authentication tokens. You can browse these files directly at the repository's [main branch](https://github.com/junjiem/dify-plugin-agent-mcp_sse/tree/main).