Advanced Topics
MCP Integration

Model Context Protocol (MCP) Integration

ActiveQL supports the Model Context Protocol (MCP) (opens in a new tab), enabling integration with AI assistants like Claude. MCP allows you to expose your domain as tools and resources that AI assistants can interact with.

Overview

The Model Context Protocol integration in ActiveQL allows you to:

  • Expose Tools: Make domain operations available as callable tools for AI assistants
  • Provide Resources: Expose read-only data sources for context
  • Custom System Prompts: Define how the AI should interact with your domain
  • Streamable HTTP Transport: Use HTTP transport as an alternative to stdio

Basic MCP Configuration

Add MCP configuration to your domain configuration:

mcp:
  systemPrompt: |
    You are an AI assistant with access to a business domain API.
    Use the available tools to help users manage their data.
 
  tool:
    createUser:
      description: Create a new user in the system
      inputSchema:
        type: object
        properties:
          email:
            type: string
            description: User email address
          name:
            type: string
            description: User full name
        required: [email, name]

Tool Configuration

Tools are callable operations that AI assistants can invoke. You can define tools in several ways:

Simple Tool (Function)

import { DomainConfiguration } from 'activeql-foundation';
 
const domainConfiguration: DomainConfiguration = {
  mcp: {
    tool: {
      getWeather: async (args, runtime) => {
        const { city } = args;
        // Implementation
        return {
          content: [{
            type: 'text',
            text: `Weather in ${city}: Sunny, 22°C`
          }]
        };
      }
    }
  }
};

Advanced Tool Configuration

const domainConfiguration: DomainConfiguration = {
  mcp: {
    tool: {
      searchProducts: {
        description: 'Search for products in the catalog',
        inputSchema: {
          type: 'object',
          properties: {
            query: {
              type: 'string',
              description: 'Search query'
            },
            category: {
              type: 'string',
              description: 'Product category filter',
              enum: ['electronics', 'clothing', 'food']
            },
            maxResults: {
              type: 'number',
              description: 'Maximum number of results',
              default: 10
            }
          },
          required: ['query']
        },
        resolve: async (args, runtime) => {
          const products = await runtime
            .entity('Product')
            .findByFilter({
              name: { contains: args.query },
              category: args.category
            });
 
          return {
            content: [{
              type: 'text',
              text: JSON.stringify(products.slice(0, args.maxResults))
            }]
          };
        }
      }
    }
  }
};

Resource Configuration

Resources provide read-only data for AI context:

const domainConfiguration: DomainConfiguration = {
  mcp: {
    resource: {
      'schema://entities': {
        description: 'List of all entity definitions',
        mimeType: 'application/json',
        resolve: async (runtime) => {
          const entities = Object.keys(runtime.entities);
          return {
            content: [{
              type: 'text',
              text: JSON.stringify(entities)
            }]
          };
        }
      },
      'data://users/stats': {
        description: 'User statistics',
        mimeType: 'application/json',
        resolve: async (runtime) => {
          const stats = await runtime.entity('User').stats();
          return {
            content: [{
              type: 'text',
              text: JSON.stringify(stats)
            }]
          };
        }
      }
    }
  }
};

Custom MCP Server

For advanced use cases, you can provide a custom MCP server:

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { DomainConfiguration } from 'activeql-foundation';
 
const domainConfiguration: DomainConfiguration = {
  mcp: {
    server: (runtime) => {
      const server = new McpServer({
        name: 'my-domain-server',
        version: '1.0.0'
      });
 
      // Custom server configuration
      server.tool('customTool', {
        description: 'A custom tool',
        inputSchema: {/* ... */}
      }, async (args) => {
        // Implementation
      });
 
      return server;
    }
  }
};

Streamable HTTP Transport

By default, MCP uses stdio transport. For HTTP-based clients, enable streamable HTTP:

const domainConfiguration: DomainConfiguration = {
  mcp: {
    asStreamableHttp: true,
    systemPrompt: 'Your system prompt',
    tool: {
      // Your tools
    }
  }
};

When enabled, the MCP server is accessible via HTTP endpoints instead of stdio.

System Prompts

Define how AI assistants should interact with your domain:

const domainConfiguration: DomainConfiguration = {
  mcp: {
    systemPrompt: `
      You are an AI assistant for a product management system.
 
      Available Operations:
      - Create, update, and delete products
      - Search products by name, category, or price range
      - Manage inventory levels
 
      Guidelines:
      - Always validate product data before creation
      - Check inventory before suggesting product purchases
      - Use the searchProducts tool for product queries
      - Format prices in USD with 2 decimal places
    `
  }
};

Integration with ActiveQL Entities

MCP tools can directly interact with ActiveQL entities:

const domainConfiguration: DomainConfiguration = {
  mcp: {
    tool: {
      createOrder: async (args, runtime) => {
        const { userId, productIds, quantities } = args;
 
        // Use ActiveQL entity operations
        const user = await runtime.entity('User').findById(userId);
        const products = await runtime.entity('Product').findByIds(productIds);
 
        // Create order using ActiveQL mutation
        const order = await runtime.entity('Order').create({
          user: userId,
          items: productIds.map((id, idx) => ({
            product: id,
            quantity: quantities[idx]
          })),
          total: calculateTotal(products, quantities)
        });
 
        return {
          content: [{
            type: 'text',
            text: `Order created successfully! Order ID: ${order.id}`
          }]
        };
      }
    }
  }
};

Complete Example

Here's a complete example combining tools, resources, and system prompts:

import { DomainConfiguration } from 'activeql-foundation';
 
export const domainConfiguration: DomainConfiguration = {
  mcp: {
    systemPrompt: `
      You are a helpful AI assistant for an e-commerce platform.
      Use the available tools to help users browse products and place orders.
    `,
 
    tool: {
      searchProducts: {
        description: 'Search for products',
        inputSchema: {
          type: 'object',
          properties: {
            query: { type: 'string' },
            category: { type: 'string' }
          }
        },
        resolve: async (args, runtime) => {
          const products = await runtime.entity('Product')
            .findByFilter({ name: { contains: args.query } });
          return {
            content: [{ type: 'text', text: JSON.stringify(products) }]
          };
        }
      },
 
      placeOrder: {
        description: 'Place a new order',
        inputSchema: {
          type: 'object',
          properties: {
            userId: { type: 'string' },
            productId: { type: 'string' },
            quantity: { type: 'number' }
          },
          required: ['userId', 'productId', 'quantity']
        },
        resolve: async (args, runtime) => {
          const order = await runtime.entity('Order').create(args);
          return {
            content: [{
              type: 'text',
              text: `Order placed! Order ID: ${order.id}`
            }]
          };
        }
      }
    },
 
    resource: {
      'data://categories': {
        description: 'Available product categories',
        mimeType: 'application/json',
        resolve: async (runtime) => {
          const categories = await runtime.entity('Category').findAll();
          return {
            content: [{
              type: 'text',
              text: JSON.stringify(categories.map(c => c.name))
            }]
          };
        }
      }
    }
  }
};

TypeScript Types

MCPServerConfig

interface MCPServerConfig {
  server?: (runtime: Runtime) => McpServer;
  asStreamableHttp?: boolean;
  tool?: {
    [name: string]: MCPResolveFn | MCPToolConfig;
  };
  resource?: {
    [name: string]: MCPResourceConfig;
  };
  systemPrompt?: string;
}

MCPToolConfig

interface MCPToolConfig {
  description?: string;
  inputSchema?: {
    type: 'object';
    properties?: Record<string, any>;
    required?: string[];
  };
  resolve: MCPResolveFn;
}

MCPResourceConfig

interface MCPResourceConfig {
  description?: string;
  mimeType?: string;
  resolve: (runtime: Runtime) => Promise<{
    content: Array<{
      type: 'text' | 'image' | 'resource';
      text?: string;
      data?: string;
      mimeType?: string;
    }>;
  }>;
}

Best Practices

  1. Clear Tool Descriptions: Provide detailed descriptions for AI to understand tool purpose
  2. Input Validation: Validate all input parameters in tool implementations
  3. Error Handling: Return user-friendly error messages in tool responses
  4. Resource Efficiency: Cache resource data when appropriate
  5. Security: Apply permission checks before exposing sensitive operations
  6. Documentation: Keep system prompts updated with available capabilities

See Also