Skip to main content

Model Context Protocol (MCP)

Extend your assistants with custom functions and external integrations using Plati’s Model Context Protocol.
What is MCP?: The Model Context Protocol allows your assistants to call external functions, query databases, integrate with APIs, and perform custom business logic in real-time during conversations.

Understanding MCP

MCP bridges the gap between your AI assistants and the external world:

What MCP Enables

  • Query external databases
  • Call third-party APIs
  • Send notifications or emails
  • Perform custom business logic
  • Access real-time data
  • Integrate with any system

How It Works

  • You create HTTP server with MCP protocol
  • Register functions in your Plati workspace
  • Connect functions to specific assistants
  • Functions become available in prompts

MCP Architecture Flow

Building Your First MCP Server

1. Basic HTTP Server

Create an HTTP server that implements the MCP protocol:
from flask import Flask, request, jsonify
import requests

app = Flask(__name__)

@app.route('/tools', methods=['GET'])
def list_tools():
    """Return available functions for this MCP"""
    return jsonify({
        "tools": [
            {
                "name": "check_order_status",
                "description": "Check the status of a customer order",
                "input_schema": {
                    "type": "object",
                    "properties": {
                        "order_id": {
                            "type": "string",
                            "description": "The order ID to check"
                        }
                    },
                    "required": ["order_id"]
                }
            },
            {
                "name": "send_email",
                "description": "Send an email to a customer",
                "input_schema": {
                    "type": "object", 
                    "properties": {
                        "to": {"type": "string"},
                        "subject": {"type": "string"},
                        "body": {"type": "string"}
                    },
                    "required": ["to", "subject", "body"]
                }
            }
        ]
    })

@app.route('/call', methods=['POST'])
def call_function():
    """Execute a function call"""
    data = request.get_json()
    function_name = data.get('name')
    arguments = data.get('arguments', {})
    
    if function_name == 'check_order_status':
        return check_order_status(arguments)
    elif function_name == 'send_email':
        return send_email(arguments)
    else:
        return jsonify({"error": "Function not found"}), 404

def check_order_status(args):
    order_id = args.get('order_id')
    # Mock implementation - replace with your actual logic
    orders_db = {
        "ORD-001": {"status": "shipped", "tracking": "1Z999AA1234567890"},
        "ORD-002": {"status": "processing", "estimated_ship": "2024-01-15"}
    }
    
    order = orders_db.get(order_id)
    if order:
        return jsonify({"success": True, "data": order})
    else:
        return jsonify({"success": False, "error": "Order not found"})

def send_email(args):
    # Mock implementation - integrate with your email service
    print(f"Sending email to {args['to']}: {args['subject']}")
    return jsonify({"success": True, "message": "Email sent successfully"})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

2. Register Your MCP in Plati

Once your server is running, register it with Plati:
curl -X POST https://api.plati.ai/workspace/mcps \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Order Management System",
    "transport": "http",
    "url": "https://your-domain.com/mcp",
    "headers": [
      {
        "key": "Authorization",
        "value": "Bearer YOUR_MCP_API_KEY"
      }
    ]
  }'

3. Connect MCP to Assistant

Link your MCP functions to a specific assistant:
curl -X PUT https://api.plati.ai/assistant/ASSISTANT_ID/mcp/MCP_ID \
  -H "Authorization: Bearer YOUR_API_KEY"

Real-World MCP Examples

E-commerce Integration

from flask import Flask, request, jsonify
import sqlite3
from datetime import datetime

app = Flask(__name__)

@app.route('/tools', methods=['GET'])
def list_tools():
    return jsonify({
        "tools": [
            {
                "name": "check_order_status",
                "description": "Get current order status and tracking info",
                "input_schema": {
                    "type": "object",
                    "properties": {
                        "order_id": {"type": "string"}
                    },
                    "required": ["order_id"]
                }
            },
            {
                "name": "process_return",
                "description": "Initiate a return for an order",
                "input_schema": {
                    "type": "object",
                    "properties": {
                        "order_id": {"type": "string"},
                        "reason": {"type": "string"},
                        "items": {"type": "array"}
                    },
                    "required": ["order_id", "reason"]
                }
            },
            {
                "name": "apply_discount",
                "description": "Apply a discount code to customer account",
                "input_schema": {
                    "type": "object",
                    "properties": {
                        "customer_id": {"type": "string"},
                        "discount_code": {"type": "string"}
                    },
                    "required": ["customer_id", "discount_code"]
                }
            },
            {
                "name": "get_product_recommendations",
                "description": "Get personalized product recommendations",
                "input_schema": {
                    "type": "object",
                    "properties": {
                        "customer_id": {"type": "string"},
                        "category": {"type": "string"},
                        "limit": {"type": "integer", "default": 5}
                    },
                    "required": ["customer_id"]
                }
            }
        ]
    })

@app.route('/call', methods=['POST'])
def call_function():
    data = request.get_json()
    function_name = data.get('name')
    arguments = data.get('arguments', {})
    
    function_map = {
        'check_order_status': check_order_status,
        'process_return': process_return,
        'apply_discount': apply_discount,
        'get_product_recommendations': get_product_recommendations
    }
    
    if function_name in function_map:
        return function_map[function_name](arguments)
    else:
        return jsonify({"error": "Function not found"}), 404

def check_order_status(args):
    order_id = args.get('order_id')
    
    # Query your database
    conn = sqlite3.connect('orders.db')
    cursor = conn.cursor()
    
    cursor.execute("""
        SELECT status, tracking_number, estimated_delivery, total_amount
        FROM orders WHERE order_id = ?
    """, (order_id,))
    
    result = cursor.fetchone()
    conn.close()
    
    if result:
        return jsonify({
            "success": True,
            "data": {
                "order_id": order_id,
                "status": result[0],
                "tracking_number": result[1],
                "estimated_delivery": result[2],
                "total_amount": result[3]
            }
        })
    else:
        return jsonify({
            "success": False,
            "error": f"Order {order_id} not found"
        })

def process_return(args):
    order_id = args.get('order_id')
    reason = args.get('reason')
    
    # Process return logic
    return_id = f"RET-{datetime.now().strftime('%Y%m%d%H%M%S')}"
    
    # Insert into returns table
    conn = sqlite3.connect('orders.db')
    cursor = conn.cursor()
    
    cursor.execute("""
        INSERT INTO returns (return_id, order_id, reason, status, created_at)
        VALUES (?, ?, ?, 'pending', ?)
    """, (return_id, order_id, reason, datetime.now()))
    
    conn.commit()
    conn.close()
    
    return jsonify({
        "success": True,
        "data": {
            "return_id": return_id,
            "status": "Return initiated successfully",
            "next_steps": "You'll receive return instructions via email within 24 hours"
        }
    })

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

CRM Integration

import requests
from flask import Flask, request, jsonify

app = Flask(__name__)

# Your CRM API credentials
CRM_API_KEY = "your_crm_api_key"
CRM_BASE_URL = "https://api.yourcrm.com/v1"

@app.route('/tools', methods=['GET'])
def list_tools():
    return jsonify({
        "tools": [
            {
                "name": "get_customer_profile",
                "description": "Retrieve complete customer profile from CRM",
                "input_schema": {
                    "type": "object",
                    "properties": {
                        "customer_id": {"type": "string"},
                        "email": {"type": "string"}
                    }
                }
            },
            {
                "name": "create_support_ticket",
                "description": "Create a new support ticket in CRM",
                "input_schema": {
                    "type": "object",
                    "properties": {
                        "customer_id": {"type": "string"},
                        "title": {"type": "string"},
                        "description": {"type": "string"},
                        "priority": {"type": "string", "enum": ["low", "medium", "high", "urgent"]}
                    },
                    "required": ["customer_id", "title", "description"]
                }
            },
            {
                "name": "update_customer_notes",
                "description": "Add notes to customer profile",
                "input_schema": {
                    "type": "object",
                    "properties": {
                        "customer_id": {"type": "string"},
                        "note": {"type": "string"},
                        "note_type": {"type": "string", "enum": ["general", "support", "sales"]}
                    },
                    "required": ["customer_id", "note"]
                }
            },
            {
                "name": "schedule_callback",
                "description": "Schedule a callback for the customer",
                "input_schema": {
                    "type": "object",
                    "properties": {
                        "customer_id": {"type": "string"},
                        "preferred_time": {"type": "string"},
                        "reason": {"type": "string"}
                    },
                    "required": ["customer_id", "preferred_time"]
                }
            }
        ]
    })

@app.route('/call', methods=['POST'])
def call_function():
    data = request.get_json()
    function_name = data.get('name')
    arguments = data.get('arguments', {})
    
    try:
        if function_name == 'get_customer_profile':
            return get_customer_profile(arguments)
        elif function_name == 'create_support_ticket':
            return create_support_ticket(arguments)
        elif function_name == 'update_customer_notes':
            return update_customer_notes(arguments)
        elif function_name == 'schedule_callback':
            return schedule_callback(arguments)
        else:
            return jsonify({"error": "Function not found"}), 404
    except Exception as e:
        return jsonify({"error": str(e)}), 500

def get_customer_profile(args):
    customer_id = args.get('customer_id')
    email = args.get('email')
    
    # Query CRM API
    if customer_id:
        url = f"{CRM_BASE_URL}/customers/{customer_id}"
    elif email:
        url = f"{CRM_BASE_URL}/customers/search?email={email}"
    else:
        return jsonify({"error": "customer_id or email required"})
    
    response = requests.get(url, headers={
        "Authorization": f"Bearer {CRM_API_KEY}"
    })
    
    if response.status_code == 200:
        customer_data = response.json()
        return jsonify({
            "success": True,
            "data": {
                "customer_id": customer_data.get('id'),
                "name": customer_data.get('name'),
                "email": customer_data.get('email'),
                "phone": customer_data.get('phone'),
                "tier": customer_data.get('tier'),
                "total_spent": customer_data.get('total_spent'),
                "last_purchase": customer_data.get('last_purchase_date'),
                "open_tickets": customer_data.get('open_tickets_count', 0)
            }
        })
    else:
        return jsonify({
            "success": False,
            "error": "Customer not found in CRM"
        })

def create_support_ticket(args):
    ticket_data = {
        "customer_id": args.get('customer_id'),
        "title": args.get('title'),
        "description": args.get('description'),
        "priority": args.get('priority', 'medium'),
        "source": "ai_assistant"
    }
    
    response = requests.post(
        f"{CRM_BASE_URL}/tickets",
        json=ticket_data,
        headers={"Authorization": f"Bearer {CRM_API_KEY}"}
    )
    
    if response.status_code == 201:
        ticket = response.json()
        return jsonify({
            "success": True,
            "data": {
                "ticket_id": ticket.get('id'),
                "ticket_number": ticket.get('number'),
                "status": ticket.get('status'),
                "assigned_to": ticket.get('assigned_agent'),
                "message": "Support ticket created successfully"
            }
        })
    else:
        return jsonify({
            "success": False,
            "error": "Failed to create ticket"
        })

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Using MCP Functions in Prompts

Once your MCP is connected, reference functions in your assistant prompts:
You are a customer service specialist with access to our order management system.

Available functions:
- {{function.check_order_status(order_id)}} - Get order status and tracking
- {{function.process_return(order_id, reason)}} - Initiate returns
- {{function.apply_discount(customer_id, code)}} - Apply discount codes
- {{function.get_customer_profile(customer_id)}} - Get customer details

When customer asks about their order:
1. Ask for order number if not provided
2. Call {{function.check_order_status(order_id)}}
3. Provide helpful summary of the results

For return requests:
1. Get order details first
2. Confirm return eligibility
3. Call {{function.process_return(order_id, reason)}}
4. Explain next steps to customer

Always validate order numbers and handle errors gracefully.

Testing Your MCP

1

Test Server Locally

Verify your MCP server responds correctly:
# Test tools endpoint
curl http://localhost:5000/tools

# Test function call
curl -X POST http://localhost:5000/call \
  -H "Content-Type: application/json" \
  -d '{
    "name": "check_order_status",
    "arguments": {"order_id": "ORD-001"}
  }'
2

Deploy to Production

Deploy your MCP server to a public URL:
  • Use platforms like Heroku, Railway, or AWS
  • Ensure HTTPS is enabled
  • Set up proper authentication
3

Test with Plati

Send test messages to verify integration:
curl -X POST https://api.plati.ai/conversation/test_user/chat/{channel_id} \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"text": "Check my order ORD-001"}'

Security Best Practices

Always authenticate MCP requests:
@app.before_request
def authenticate():
    if request.endpoint in ['call', 'tools']:
        auth_header = request.headers.get('Authorization')
        if not auth_header or not verify_token(auth_header):
            return jsonify({"error": "Unauthorized"}), 401
Validate all function inputs:
def validate_order_id(order_id):
    if not order_id or not re.match(r'^ORD-\d+$', order_id):
        raise ValueError("Invalid order ID format")
Implement rate limiting:
from flask_limiter import Limiter

limiter = Limiter(
    app,
    key_func=lambda: request.headers.get('Authorization'),
    default_limits=["100 per minute"]
)
Handle errors gracefully:
try:
    result = external_api_call()
    return jsonify({"success": True, "data": result})
except ExternalAPIError as e:
    return jsonify({
        "success": False, 
        "error": "Service temporarily unavailable"
    })

Advanced MCP Patterns

Stateful Functions

Maintain state across function calls:
# Store conversation context
conversation_context = {}

def get_order_history(args):
    customer_id = args.get('customer_id')
    
    # Store context for follow-up questions
    conversation_context[customer_id] = {
        'last_query': 'order_history',
        'orders': fetch_orders(customer_id)
    }
    
    return jsonify({
        "success": True,
        "data": conversation_context[customer_id]['orders']
    })

Async Functions

Handle long-running operations:
import asyncio
from threading import Thread

@app.route('/call', methods=['POST'])
def call_function():
    data = request.get_json()
    
    if data.get('name') == 'generate_report':
        # Start async task
        task_id = start_report_generation(data.get('arguments'))
        return jsonify({
            "success": True,
            "task_id": task_id,
            "message": "Report generation started. You'll be notified when complete."
        })

Function Chaining

Chain multiple functions together:
def process_order_issue(args):
    order_id = args.get('order_id')
    
    # Step 1: Get order details
    order = get_order_details(order_id)
    
    # Step 2: Check if refund eligible
    if order['status'] in ['delivered', 'completed']:
        # Step 3: Process refund
        refund_result = process_refund(order_id)
        return jsonify({
            "success": True,
            "actions_taken": [
                "Retrieved order details",
                "Verified refund eligibility", 
                "Processed refund"
            ],
            "refund_id": refund_result['refund_id']
        })

MCP SDK (Coming Soon)

We’re developing an official SDK to simplify MCP development:
from plati_mcp import MCP, Function

mcp = MCP(name="Order Management")

@mcp.function(
    name="check_order_status",
    description="Check order status and tracking",
    parameters={
        "order_id": {"type": "string", "required": True}
    }
)
def check_order_status(order_id: str):
    # Your implementation
    return {"status": "shipped", "tracking": "123456"}

@mcp.function(
    name="process_return", 
    description="Process a return request",
    parameters={
        "order_id": {"type": "string", "required": True},
        "reason": {"type": "string", "required": True}
    }
)
def process_return(order_id: str, reason: str):
    # Your implementation
    return {"return_id": "RET-123", "status": "approved"}

if __name__ == '__main__':
    mcp.run(host='0.0.0.0', port=5000)

Next Steps