MCP Server Architecture¶
!!! info "TL;DR" The MCP server uses plain HTTP + JSON with a tool registry pattern. Deployed on Vercel as Next.js route handlers. Health check at /api/mcp/health.
Transport Layer¶
The MCP server exposes the Model Context Protocol over plain HTTP with JSON request and response bodies. This approach is Vercel-compatible and requires no persistent connection.
Endpoints¶
| Endpoint | Method | Purpose |
|---|---|---|
/api/mcp/tools | POST | Execute tool calls |
/api/mcp/health | GET | Health check and server info |
Request Format¶
Tool calls are plain JSON, not JSON-RPC:
{
"tool": "create_survey",
"arguments": {
"title": "Q1 Product Feedback",
"questions": [
{
"type": "multiple_choice",
"text": "What feature would you like next?",
"options": ["Dark mode", "API access", "Mobile app"]
}
]
}
}
Response Format¶
Successful responses wrap the tool's return value in result, alongside a correlation request_id:
{
"result": {
"survey_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "draft",
"url": "https://acme.canviq.app/en/surveys/550e8400-e29b-41d4-a716-446655440000"
},
"request_id": "mcp_2b1a9c7e-0f3d-4a8e-9b21-6e2c4d8f1a30"
}
Error responses use RFC 7807 Problem Details (Content-Type: application/problem+json). See the MCP Tools API reference for the full request/response contract, error codes, and authentication details.
Tool Registry Pattern¶
The server uses a plugin-style registry for tools. Each tool is a class that implements the McpTool interface:
interface McpTool {
name: string
description: string
requiredScopes: string[]
schema: z.ZodSchema
execute(params: unknown, context: ExecutionContext): Promise<unknown>
}
Tools register themselves at startup:
// lib/mcp/tools/index.ts
export const toolRegistry = new Map<string, McpTool>([
['create_survey', new CreateSurveyTool()],
['update_survey', new UpdateSurveyTool()],
['list_surveys', new ListSurveysTool()],
// ... more tools
])
This pattern makes adding new tools straightforward. Drop a file in lib/mcp/tools/, export the class, and it's automatically available.
Execution Context¶
Every tool execution receives a context object:
interface ExecutionContext {
agentId: string
requestId: string
scopes: string[]
rateLimit: RateLimitInfo
metadata: Record<string, unknown>
}
This context flows through the execution pipeline:
- Authentication — Verify API key, load agent identity
- Authorization — Check scopes against tool's required scopes
- Rate limiting — Decrement quota in Upstash Redis
- Validation — Parse params with tool's Zod schema
- Execution — Call tool's
execute()method - Audit logging — Record action in
agent_audit_logs - Response — Return result or error
Health Check¶
The /api/mcp/health endpoint returns server status:
Use this for monitoring and integration tests.
Deployment¶
The MCP server deploys as part of the main Next.js app on Vercel. No separate service required. Environment variables:
UPSTASH_REDIS_REST_URL— Rate limiting backendUPSTASH_REDIS_REST_TOKEN— Redis authANTHROPIC_API_KEY— Claude for sentiment analysis
Edge runtime is not used. MCP tools often call Supabase which requires Node.js runtime.
What's Next¶
- Authentication — API keys, scopes, IAM tables
- Available Tools — Complete tool reference
- Rate Limits — Tiered rate limits and custom policies