Showing posts with label mcp. Show all posts
Showing posts with label mcp. Show all posts

Saturday

Existing API Services to MCP Conversion - Complete Guide

 

                                                        MCP server from research gate

An MCP server, or Model Context Protocol server, acts as a bridge, enabling AI models to interact with external tools and data sources through a standardized interface. It simplifies the process of connecting AI applications to various services and resources, making it easier for developers to build and deploy AI-powered applications. 

We all have tons of API services and servers already. However now due to AgenticAI and multiple Agent applications with MCP. It is getting difficult if not totally impossible to connect the same API services. So I thought, how can we convert our existing API services into MCP capable.

This guide provides a complete end-to-end solution for converting FastAPI services (both sync and async) into MCP (Model Context Protocol) servers that can be called by LLM agents.

Overview

What is MCP? Model Context Protocol (MCP) is a standardized protocol that enables LLM applications to securely connect to data sources and tools. It provides a way for AI assistants to interact with external services through tools, resources, and prompts.

Why Convert FastAPI to MCP?

  • Standardized interface for LLM agents
  • Better security and access control
  • Structured tool definitions
  • Resource management capabilities
  • Protocol-level error handling

Architecture

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   LLM Agent     │────│   MCP Server    │────│  FastAPI Service│
│   Application   │    │   (Bridge)      │    │  (Your APIs)    │
└─────────────────┘    └─────────────────┘    └─────────────────┘

Step-by-Step Implementation

1. Project Structure

fastapi-mcp-conversion/
├── fastapi_services.py      # Your existing FastAPI services
├── mcp_server.py           # MCP server implementation
├── requirements.txt        # Dependencies
├── pyproject.toml         # Project configuration
├── setup.sh              # Setup script
├── run_fastapi.sh         # FastAPI runner
├── run_mcp_server.sh      # MCP server runner
├── test_integration.sh    # Integration tests
├── test_mcp_client.py     # Test client
├── production_deployment.py # Production setup
└── README.md              # This documentation

2. FastAPI Services (Source)

Your existing FastAPI services should include:

  • Sync endpoints: Traditional REST endpoints
  • Async endpoints: Asynchronous operations
  • Proper error handling: HTTP status codes and error messages
  • Pydantic models: Request/response validation

3. MCP Server Implementation

The MCP server acts as a bridge between your FastAPI services and LLM agents:

Key Components:

  • Tools: Represent callable functions (your API endpoints)
  • Resources: Represent data sources or documentation
  • Server: Handles MCP protocol communication

Tool Definition Example:

Tool(
    name="get_users",
    description="Get all users from the system",
    inputSchema={
        "type": "object",
        "properties": {},
        "required": []
    }
)

4. Conversion Process

Step 1: Analyze FastAPI Endpoints

  1. Identify all endpoints (GET, POST, PUT, DELETE)
  2. Extract parameters and request/response models
  3. Categorize sync vs async operations
  4. Document endpoint purposes and behaviors

Step 2: Create MCP Tools

For each FastAPI endpoint, create an MCP tool:

  • Map endpoint parameters to tool input schema
  • Define clear descriptions
  • Handle both sync and async operations
  • Implement error handling and validation

Step 3: Implement HTTP Client

  • Use httpx.AsyncClient for making requests to FastAPI
  • Handle timeouts and retries
  • Manage connection pooling
  • Convert HTTP errors to MCP-compatible responses

Step 4: Resource Management

Define resources for:

  • API documentation
  • Data schemas
  • Service status
  • Configuration information

5. Configuration and Deployment

Environment Variables

FASTAPI_BASE_URL=http://localhost:8000
MCP_SERVER_NAME=fastapi-mcp-server
LOG_LEVEL=INFO

Claude Desktop Configuration

Add to your Claude Desktop config:

{
  "mcpServers": {
    "fastapi-mcp-server": {
      "command": "python",
      "args": ["mcp_server.py"],
      "env": {
        "FASTAPI_BASE_URL": "http://localhost:8000"
      }
    }
  }
}

6. Running the System

Development Setup

# 1. Setup environment
./setup.sh

# 2. Start FastAPI service
./run_fastapi.sh

# 3. Start MCP server (in another terminal)
./run_mcp_server.sh

# 4. Test integration
./test_integration.sh

Production Deployment

# Using Docker Compose
docker-compose up -d

# Or manual deployment
python production_deployment.py

7. Testing and Validation

Unit Tests

Test individual components:

  • FastAPI endpoints
  • MCP tool implementations
  • HTTP client functionality
  • Error handling

Integration Tests

Test end-to-end functionality:

  • MCP server startup
  • Tool execution
  • Resource access
  • Error scenarios

Load Testing

Test performance:

  • Concurrent requests
  • Memory usage
  • Response times
  • Connection limits

8. LLM Agent Integration

Example Agent Usage

# In your LLM agent application
async def process_user_request(user_input: str):
    if "create user" in user_input.lower():
        # Extract user data from natural language
        user_data = extract_user_data(user_input)
        
        # Call MCP tool
        result = await mcp_session.call_tool("create_user", user_data)
        
        # Process result and respond
        return format_response(result)

9. Benefits of This Approach

For Developers

  • Reuse existing APIs: No need to rewrite FastAPI services
  • Standardized interface: Consistent way to expose APIs to LLMs
  • Better error handling: Protocol-level error management
  • Documentation: Auto-generated tool descriptions

For LLM Agents

  • Type safety: Structured input/output schemas
  • Discovery: Automatic tool and resource discovery
  • Reliability: Robust error handling and retries
  • Security: Controlled access to backend services

10. Advanced Features

Authentication and Authorization

# Add authentication to MCP server
async def authenticate_request(request_data):
    # Implement your auth logic
    pass

Rate Limiting

# Implement rate limiting
from asyncio import Semaphore

class RateLimitedMCPServer:
    def __init__(self, max_concurrent=10):
        self.semaphore = Semaphore(max_concurrent)

Caching

# Add caching for frequently accessed data
from functools import lru_cache

@lru_cache(maxsize=100)
async def cached_get_users():
    # Implementation
    pass

Monitoring and Metrics

# Track usage metrics
class MCPServerMetrics:
    def record_request(self, tool_name, response_time, success):
        # Implementation
        pass

11. Troubleshooting

Common Issues

  1. Connection refused: FastAPI service not running
  2. Tool not found: Incorrect tool name mapping
  3. Schema validation: Mismatched input parameters
  4. Timeout errors: Network or processing delays

Debug Mode

# Enable debug logging
logging.basicConfig(level=logging.DEBUG)

Health Checks

# Implement health check endpoint
@app.get("/health")
async def health_check():
    return {"status": "healthy", "timestamp": datetime.utcnow()}

12. Performance Optimization

Connection Pooling

# Configure HTTP client for optimal performance
client = httpx.AsyncClient(
    timeout=30.0,
    limits=httpx.Limits(max_connections=100, max_keepalive_connections=20)
)

Async Processing

# Use asyncio for concurrent operations
async def process_multiple_requests(requests):
    tasks = [process_request(req) for req in requests]
    return await asyncio.gather(*tasks)

13. Security Considerations

Input Validation

  • Validate all input parameters
  • Sanitize user data
  • Implement parameter bounds checking

Access Control

  • Implement authentication for sensitive operations
  • Use API keys or tokens
  • Log all access attempts

Error Information

  • Don't expose internal system details in errors
  • Use generic error messages for security
  • Log detailed errors internally

14. Scaling and Production

Horizontal Scaling

  • Deploy multiple MCP server instances
  • Use load balancer for FastAPI services
  • Implement health checks

Monitoring

  • Track request/response metrics
  • Monitor error rates
  • Set up alerting

Backup and Recovery

  • Implement graceful shutdown
  • Handle service restarts
  • Maintain service availability

Full example

MCP Server Architecture

from mcp import Server, Tool, Resource
from mcp.types import TextContent, ImageContent

class CustomMCPServer(Server):
    def __init__(self):
        super().__init__("custom-server", "1.0.0")
        self.register_handlers()
    
    def register_handlers(self):
        # Register tools and resources
        self.add_tool(self.search_tool)
        self.add_resource(self.database_resource)
    
    async def search_tool(self, query: str) -> str:
        # Implement search functionality
        results = await self.search_service.search(query)
        return json.dumps(results)
    
    async def database_resource(self, table: str) -> dict:
        # Implement database access
        data = await self.db.query(table)
        return {"data": data, "schema": self.db.get_schema(table)}

2. Protocol Implementation:

Message Types:

  • Tool calls: Request tool execution with parameters
  • Resource requests: Access to structured data
  • Capability discovery: Query available tools and resources
  • Authentication: Secure access control

Communication Flow:

  1. Client discovers server capabilities
  2. Client authenticates with server
  3. Client requests tools/resources
  4. Server processes requests and returns results
  5. Error handling and retry mechanisms

3. Security Considerations:

  • Authentication: OAuth2, API keys, or custom auth
  • Authorization: Role-based access control
  • Input validation: Sanitize all inputs
  • Rate limiting: Prevent abuse and overload
  • Audit logging: Track all interactions

Development Best Practices:

Server Implementation:

  • Async programming: Use asyncio for concurrent handling
  • Error handling: Comprehensive error responses
  • Documentation: OpenAPI specs for tool definitions
  • Versioning: Support multiple protocol versions

Testing Framework:

import pytest

from mcp.testing import MCPTestClient


@pytest.mark.asyncio

async def test_search_tool():

    server = CustomMCPServer()

    client = MCPTestClient(server)

    

    response = await client.call_tool("search", {"query": "test"})

    assert response.status == "success"

    assert "results" in response.data



import pytest

from mcp.testing import MCPTestClient


@pytest.mark.asyncio

async def test_search_tool():

    server = CustomMCPServer()

    client = MCPTestClient(server)

    

    response = await client.call_tool("search", {"query": "test"})

    assert response.status == "success"

    assert "results" in response.data

Conclusion

This complete guide provides everything needed to convert FastAPI services into MCP servers that can be used by LLM agents. The approach maintains the benefits of your existing FastAPI implementation while providing a standardized interface for AI applications.

The conversion process is straightforward and allows for gradual migration of services. Start with a few key endpoints and expand coverage as needed.


Thursday

MCP with RAG and Agent

 

                                                                image from Google next

To break down "MCP" and "MCP tools":

  • Model Context Protocol (MCP):

    • This is an open standard that aims to standardize how Large Language Models (LLMs) communicate with external applications, data sources, and tools.
    • Essentially, it provides a structured way for LLMs to interact with the "outside world" in a consistent manner.
    • It follows a client-server architecture, where:
      • MCP clients (like LLM applications) request actions.
      • MCP servers provide access to tools and data.
  • MCP Tools:

    • These are the specific functions or capabilities that MCP servers expose.
    • They allow LLMs to perform actions, such as:
      • Accessing files.
      • Interacting with databases.
      • Using web services.
    • MCP tools enable LLMs to go beyond their internal knowledge and perform real-world tasks.3
    • Essentially, the tools are the functions that the server provides, that the client can call.
    • There is also a tool called "MCP tools" that is a command line interface that helps with interacting with MCP servers.

In simpler terms, MCP is like a set of rules, and MCP tools are the actions that LLMs can take by following those rules.

It's accurate that building sophisticated AI applications often involves combining multi-agent systems with Retrieval Augmented Generation (RAG). Here's a breakdown of how you can connect multi-agent frameworks like LangGraph or ADK with an agent that utilizes RAG:

Understanding the Components:

  • Multi-Agent Systems (LangGraph, ADK):
    • These frameworks allow you to create workflows where multiple AI agents collaborate to achieve a complex goal.1
    • They handle the orchestration, communication, and state management between these agents.
    • LangGraph, in particular, excels at defining agent interactions as a graph, providing fine-grained control over the workflow.3
  • Retrieval Augmented Generation (RAG):
    • RAG enhances LLMs by grounding their responses in external knowledge.
    • It involves retrieving relevant information from a database or knowledge base and providing it to the LLM as context.
    • This enables the LLM to generate more accurate and informed responses.

Connecting Multi-Agents with RAG:

Here's a general approach:

  1. Define Agent Roles:

    • Determine the specific roles of each agent in your multi-agent system.
    • One agent might be responsible for handling user queries, another for retrieving information, and another for generating the final response.
    • For example, you could have:
      • A "Query Agent" that receives user input.
      • A "Retrieval Agent" that uses RAG to fetch relevant information.
      • A "Response Agent" that formulates a response based on the retrieved information.
  2. Integrate RAG into a Specific Agent:

    • The "Retrieval Agent" or the "Response Agent" is the logical place to integrate your RAG pipeline.
    • This agent would:
      • Receive the user query.
      • Use a vector database or other retrieval mechanism to find relevant documents.
      • Pass the retrieved documents to the LLM along with the query.
  3. Orchestrate the Workflow with LangGraph or ADK:

    • Use LangGraph or ADK to define the flow of information between the agents.
    • For example:
      • The "Query Agent" receives a user query and passes it to the "Retrieval Agent."
      • The "Retrieval Agent" performs RAG and passes the retrieved information to the "Response Agent."
      • The "Response Agent" generates a response and returns it to the user.
  4. State Management:

    • LangGraph's state management capabilities are crucial for maintaining context across agent interactions.
    • This ensures that the agents can effectively collaborate and build upon previous information.

Key Considerations:

  • Tooling: Langchain is a very useful tool for creating the RAG elements of the agents.
  • Vector Databases: Vector databases are essential for efficient retrieval in RAG.
  • Agent Communication: Ensure that your agents can communicate effectively by defining clear data structures and protocols.

By following these steps, you can create powerful AI applications that combine the strengths of multi-agent systems and RAG.

Lets do some programming with Vertex ai

import vertexai

from vertexai.language_models import TextGenerationModel

from vertexai.generative_models import GenerativeModel, Part

from google.cloud import aiplatform

import google_auth_httplib2

import google.auth

import requests

import json

from google.cloud import storage

import os


# Initialize Vertex AI

PROJECT_ID = "YOUR_PROJECT_ID"  # Replace with your project ID

LOCATION = "us-central1"  # Replace with your location

vertexai.init(project=PROJECT_ID, location=LOCATION)


# Initialize Generative and Text Models

gen_model = GenerativeModel("gemini-pro")

text_model = TextGenerationModel.from_pretrained("text-bison")


# Initialize AI Platform for embeddings (if needed for RAG)

aiplatform.init(project=PROJECT_ID, location=LOCATION)


# Initialize Cloud storage client for RAG data

storage_client = storage.Client(project=PROJECT_ID)


# --- RAG Function (Simplified) ---

def rag_retrieve(query, bucket_name="YOUR_BUCKET_NAME", file_prefix="rag_data/"): #replace with your bucket name

    """

    Simplified retrieval from Cloud Storage. In a real application, you'd use a vector database.

    """

    bucket = storage_client.bucket(bucket_name)

    blobs = bucket.list_blobs(prefix=file_prefix)


    retrieved_content = ""

    for blob in blobs:

        if query.lower() in blob.name.lower():  # Basic keyword search

            retrieved_content += blob.download_as_text() + "\n"

    return retrieved_content


# --- Agent Functions ---

def query_agent(user_input):

    """

    Agent to handle user queries.

    """

    return user_input


def retrieval_agent(query):

    """

    Agent to retrieve information using RAG.

    """

    retrieved_info = rag_retrieve(query)

    return retrieved_info


def response_agent(query, retrieved_info):

    """

    Agent to generate a response.

    """

    prompt = f"""

    Based on the following information: {retrieved_info}


    Answer the user's query: {query}

    """

    response = gen_model.generate_content(prompt) #using gemini-pro for better response quality.

    return response.text


# --- LangGraph-like Orchestration (Simplified) ---

def multi_agent_workflow(user_query):

    """

    Simulated multi-agent workflow.

    """

    query = query_agent(user_query)

    retrieved_info = retrieval_agent(query)

    response = response_agent(query, retrieved_info)

    return response


# --- Example Usage ---

user_input = "What are the main benefits?"

final_response = multi_agent_workflow(user_input)

print(final_response)


# example of using the text model.

text_response = text_model.predict(

    f"""

    Based on the following information: {rag_retrieve(user_input)}


    Answer the user's query: {user_input}

    """

)

print(text_response.text)


With ADK

import vertexai

from vertexai.language_models import TextGenerationModel

from vertexai.generative_models import GenerativeModel

from google.cloud import aiplatform

from google_cloud_aiplatform.experimental.generative_ai import foundation_model_adapter as adk

from google.cloud import storage


# Initialize Vertex AI

PROJECT_ID = "YOUR_PROJECT_ID"  # Replace with your project ID

LOCATION = "us-central1"  # Replace with your location

vertexai.init(project=PROJECT_ID, location=LOCATION)


# Initialize Models

gen_model = GenerativeModel("gemini-pro")

text_model = TextGenerationModel.from_pretrained("text-bison")


# Initialize AI Platform

aiplatform.init(project=PROJECT_ID, location=LOCATION)


# Initialize Cloud Storage client

storage_client = storage.Client(project=PROJECT_ID)


# --- RAG Function (Simplified) ---

def rag_retrieve(query, bucket_name="YOUR_BUCKET_NAME", file_prefix="rag_data/"): #replace with your bucket name

    """

    Simplified retrieval from Cloud Storage. In a real application, you'd use a vector database.

    """

    bucket = storage_client.bucket(bucket_name)

    blobs = bucket.list_blobs(prefix=file_prefix)


    retrieved_content = ""

    for blob in blobs:

        if query.lower() in blob.name.lower():  # Basic keyword search

            retrieved_content += blob.download_as_text() + "\n"

    return retrieved_content


# --- ADK Agent Function ---

def adk_agent(user_input):

    """

    Agent using ADK for response generation.

    """


    rag_data = rag_retrieve(user_input)


    prompt = f"""

    Based on the following information: {rag_data}


    Answer the user's query: {user_input}

    """


    model = adk.FoundationModelAdapter(

        model_name="gemini-pro",

        project=PROJECT_ID,

        location=LOCATION,

    )


    response = model.predict(

        prompt,

    )


    return response.text


# --- Example Usage ---

user_input = "What are the key features?"

response = adk_agent(user_input)

print(response)


# Example using the text model.

text_response = text_model.predict(

    f"""

    Based on the following information: {rag_retrieve(user_input)}


    Answer the user's query: {user_input}

    """

)

print(text_response.text)


Will update you with some latest ADK framework and code soon. You can follow Google ADK tutorial here https://google.github.io/adk-docs/get-started/quickstart/

 

House Based Manufacturing Micro Clustering

                                 image generated by meta ai House-based manufacturing micro-clustering in China refers to the hyper-local, v...