MCP SSE DEMO

Creating a seamless integration of the Model Context Protocol (MCP) using the PydanticAI library involves setting up an MCP server that communicates via Server-Sent Events (SSE) and a Streamlit frontend that acts as an MCP client. This architecture enables real-time interactions between AI agents and external tools or resources.

Overview:

  1. MCP Server with SSE: The server provides tools or resources accessible to AI agents through the MCP. It uses SSE to push updates to connected clients.
  2. Streamlit Frontend as MCP Client: The frontend interacts with the MCP server, receiving real-time updates via SSE and providing an interactive user interface.
  3. Docker Compose Setup: Both the server and frontend are containerized using Docker, ensuring consistent environments and simplified deployment.

Step 1: Setting Up the MCP Server with SSE

We'll create a FastAPI application that serves as the MCP server. This server will implement SSE endpoints to stream real-time data to connected clients.

from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse
import asyncio
import json

app = FastAPI()

# Queue to hold messages for SSE
message_queue = asyncio.Queue()

async def event_stream():
    """Generator function to stream messages to clients."""
    while True:
        message = await message_queue.get()
        yield f"data: {message}\n\n"

@app.get("/sse")
async def sse_endpoint():
    """SSE endpoint to stream data to clients."""
    return StreamingResponse(event_stream(), media_type="text/event-stream")

@app.post("/mcp")
async def mcp_endpoint(request: Request):
    """Endpoint to handle MCP requests."""
    data = await request.json()
    # Process the MCP request here
    response = {"status": "processed", "data": data}
    await message_queue.put(json.dumps(response))
    return response

Step 2: Developing the Streamlit Frontend as MCP Client

The Streamlit application will act as an MCP client, connecting to the MCP server's SSE endpoint to receive real-time updates.

import streamlit as st
import requests
import threading

st.title("MCP Client with SSE")

# Container to display messages
messages_container = st.empty()

def listen_to_sse():
    """Function to listen to SSE from the MCP server."""
    url = "http://mcp-server:8000/sse"
    with requests.get(url, stream=True) as response:
        for line in response.iter_lines():
            if line:
                messages_container.text(line.decode())

# Start SSE listener in a separate thread
thread = threading.Thread(target=listen_to_sse, daemon=True)
thread.start()

# Input form to send MCP requests
st.subheader("Send MCP Request")
input_data = st.text_input("Enter data:")
if st.button("Send"):
    response = requests.post("http://mcp-server:8000/mcp", json={"data": input_data})
    st.success(f"Server Response: {response.json()}")

Step 3: Dockerizing the Applications with Docker Compose

We'll use Docker Compose to define and run multi-container Docker applications, ensuring that both the MCP server and the Streamlit frontend operate in isolated environments.

Dockerfile for MCP Server (Dockerfile):

FROM python:3.8-slim

WORKDIR /app

# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Expose port
EXPOSE 8000

# Command to run the application
CMD ["uvicorn", "mcp_server:app", "--host", "0.0.0.0", "--port", "8000"]

Dockerfile for Streamlit Frontend (Dockerfile):

FROM python:3.8-slim

WORKDIR /app

# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Expose port
EXPOSE 8501

# Command to run the application
CMD ["streamlit", "run", "frontend.py", "--server.port=8501", "--server.address=0.0.0.0"]

Docker Compose Configuration (docker-compose.yml):

version: '3.8'

services:
  mcp-server:
    build:
      context: .
      dockerfile: Dockerfile.mcp
    container_name: mcp-server
    ports:
      - "8000:8000"
  streamlit-frontend:
    build:
      context: .
      dockerfile: Dockerfile.streamlit
    container_name: streamlit-frontend
    ports:
      - "8501:8501"
    depends_on:
      - mcp-server

Step 4: Running the Applications

  1. Build and Start the Containers:

    docker-compose up --build

  2. Access the Streamlit Frontend:

    Open your browser and navigate to http://localhost:8501 to interact with the MCP client interface.

Conclusion:

By following this tutorial, you've set up an MCP server using FastAPI with SSE capabilities and a Streamlit frontend acting as an MCP client. This architecture facilitates real-time communication between AI agents and external tools or resources, leveraging the capabilities of the PydanticAI library.

For a deeper understanding and visual walkthrough, consider watching the following tutorial:

videoPydanticAI Tutorial: The AI Agent Tool That Will Blow Your Mindturn0search2