Skip to Content

Problem: Your System Has No AI Access

Your Business System is Disconnected from AI

Bridging the gap between Claude and your live systems

You have an Odoo instance with thousands of customer records. Or a Shopify store with product catalogs. Or an internal PostgreSQL database with sales reports. Claude cannot see any of it — unless you build an MCP server to bridge the gap.

Example 1: MCP Server for REST API (Odoo)

If you followed the Claude Plugins course, you know that VaryShop uses Odoo as its CRM. The CRM Toolkit plugin used Python scripts to call the Odoo XML-RPC API. Now let us turn that into an MCP server.

Odoo MCP Server (Python)
import os, json, xmlrpc.client
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("odoo-connector")

ODOO_URL = os.environ.get("ODOO_URL")
ODOO_DB = os.environ.get("ODOO_DB")
ODOO_KEY = os.environ.get("ODOO_API_KEY")

common = xmlrpc.client.ServerProxy(
    f"{ODOO_URL}/xmlrpc/2/common")
models = xmlrpc.client.ServerProxy(
    f"{ODOO_URL}/xmlrpc/2/object")
UID = common.authenticate(ODOO_DB, "", ODOO_KEY, {})

def call(model, method, args, kw=None):
    return models.execute_kw(
        ODOO_DB, UID, ODOO_KEY,
        model, method, args, kw or {})

@mcp.tool()
def search_contacts(query: str,
                    limit: int = 10) -> str:
    """Search contacts in Odoo CRM."""
    results = call("res.partner", "search_read", [
        ["|", ["name", "ilike", query],
              ["email", "ilike", query]]
    ], {"fields": ["name", "email", "phone",
                   "city"], "limit": limit})
    return json.dumps(results, indent=2,
                      ensure_ascii=False)

@mcp.tool()
def create_contact(name: str, email: str,
                   phone: str = "",
                   city: str = "") -> str:
    """Create a new contact in Odoo CRM."""
    pid = call("res.partner", "create",
               [{"name": name, "email": email,
                 "phone": phone, "city": city}])
    return json.dumps({"id": pid, "status": "created"})

Interactive Access

Now Claude can directly ask: "Search for contacts named John" or "Show me orders from the last week" — no scripts needed.

Example 2: Database Access

Database MCP Server (excerpt)
@mcp.tool()
def query_data(sql: str) -> str:
    """Execute a read-only SQL query.
    Only SELECT statements are allowed."""
    if not sql.strip().upper().startswith("SELECT"):
        return json.dumps(
            {"error": "Only SELECT queries allowed"})
    conn = psycopg2.connect(DB_URL)
    try:
        cur = conn.cursor()
        cur.execute(sql)
        columns = [d[0] for d in cur.description]
        rows = [dict(zip(columns, row))
                for row in cur.fetchall()]
        return json.dumps(rows[:100], indent=2,
                          default=str)
    finally:
        conn.close()

Security Warning

Always restrict database MCP servers to read-only queries. Use a database user with only SELECT permissions. Never expose write access unless absolutely necessary.

Authentication and Security Best Practices

Environment Variables

Never hardcode API keys or passwords in server code. Always use env in .mcp.json to pass secrets securely.

Least Privilege

Create API keys with minimum required permissions. Use read-only database users when possible. Limit accessible endpoints.

Input Validation

Always validate and sanitize inputs from Claude. Use parameterized queries for SQL. Set reasonable limits on result sizes.

Error Handling

Always return structured error messages. Claude can then explain the issue to the user and suggest solutions.

Error Handling Pattern

Error Handling
@mcp.tool()
def safe_search(query: str) -> str:
    """Search with proper error handling."""
    try:
        results = call_external_api(query)
        return json.dumps(results)
    except ConnectionError:
        return json.dumps(
            {"error": "Cannot connect to the API."})
    except TimeoutError:
        return json.dumps(
            {"error": "API request timed out."})
    except Exception as e:
        return json.dumps(
            {"error": f"Unexpected error: {str(e)}"})

Key Takeaway

Connecting to real business systems follows the same pattern as our JSON reader — define tools, implement handlers, configure the server. The difference is adding authentication, error handling, and security. Always start with read-only access and add write operations only when needed.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.