Architecture Overview
Technical documentation for developers working with or contributing to BlokMCP.
System Architecture
BlokMCP is a SaaS MCP server that bridges AI assistants (Claude, Cursor, etc.) with the Storyblok Management API through the Model Context Protocol.
High-Level Architecture
┌─────────────────┐
│ MCP Clients │ (Claude Desktop, Cursor IDE)
│ (User's Device)│
└────────┬────────┘
│ MCP Protocol (HTTPS)
│ Headers: X-Api-Key, X-Storyblok-Space-Id
▼
┌─────────────────────────────────────────────┐
│ BlokMCP Server │
│ (Cloud-hosted SaaS) │
│ ┌────────────────────────────────────────┐ │
│ │ Authentication Middleware │ │
│ │ - Validate API key │ │
│ │ - Load organization context │ │
│ │ - Rate limiting │ │
│ │ - Usage tracking │ │
│ └────────────┬───────────────────────────┘ │
│ ▼ │
│ ┌────────────────────────────────────────┐ │
│ │ Tool Router (130+ tools) │ │
│ │ - Stories, Components, Assets │ │
│ │ - Workflows, Approvals, Tasks │ │
│ │ - Datasources, Tags, Webhooks │ │
│ │ - And 20+ more modules │ │
│ └────────────┬───────────────────────────┘ │
│ ▼ │
│ ┌────────────────────────────────────────┐ │
│ │ Storyblok API Client │ │
│ │ - Resolve encrypted tokens │ │
│ │ - Make authenticated requests │ │
│ │ - Handle pagination & errors │ │
│ └────────────┬───────────────────────────┘ │
└───────────────┼─────────────────────────────┘
│ HTTPS (Management API)
▼
┌─────────────────┐
│ Storyblok API │
└─────────────────┘
┌──────────────┐
│ Database │ (Relational DB with multi-tenant isolation)
│ - Organizations
│ - Users
│ - Subscriptions
│ - API Keys (hashed)
│ - Storyblok Spaces (encrypted tokens)
│ - Usage Records
│ - Audit Logs
└──────────────┘
Core Components
1. MCP Server
Location: src/
The MCP server runs as a cloud-hosted service at https://mcp.blokmcp.com.
Entry points:
src/worker.ts- Production SaaS entrysrc/index.ts- CLI/stdio entry (development/testing only)
Key responsibilities:
- Implement MCP protocol (list tools, call tools)
- Authenticate requests via API keys
- Route tool calls to appropriate handlers
- Interface with Storyblok Management API
- Track usage and enforce rate limits
Technology:
- TypeScript with strict type checking
- MCP protocol implementation
- Runtime schema validation
- Modern cloud-hosted serverless architecture
2. Authentication Middleware
Location: src/middleware/auth.ts
Handles multi-tenant authentication and authorization.
Flow:
- Extract API key from request header
- Validate key format and integrity
- Verify against secure storage
- Load organization context and permissions
- Resolve Storyblok space selection
- Decrypt Storyblok tokens from encrypted storage
- Return authentication context for request
Security features:
- API keys are securely hashed using industry-standard algorithms
- Storyblok tokens are encrypted at rest using authenticated encryption
- Rate limiting per organization
- Usage tracking per request
3. Tool Registration System
Location: src/tools/
Each module exports a register*Tools(server) function.
Pattern:
// src/tools/stories.ts
export function registerStoriesTools(server: McpServer) {
server.addTool({
name: "fetch_stories",
description: "...",
inputSchema: storiesInputSchema,
handler: async (params) => {
// Implementation
}
});
server.addTool({
name: "get_story",
// ...
});
// 18 tools total
}
Aggregation:
// src/tools/index.ts
import { registerStoriesTools } from './stories.js';
import { registerComponentsTools } from './components.js';
// ... 30+ imports
export function registerAllTools(server: McpServer) {
registerStoriesTools(server);
registerComponentsTools(server);
// ... 30+ registrations
}
Tool naming conventions:
fetch_*- List/search multiple itemsget_*- Retrieve single item by IDcreate_*- Create new itemupdate_*- Modify existing itemdelete_*- Remove itempublish_*/unpublish_*- Publication operations
4. Storyblok API Client
Location: src/utils/api.ts
Wrapper around Storyblok Management API with common patterns.
Features:
- Authenticated requests with management token
- Error handling and retries
- Pagination helpers
- Response validation
- Rate limit respect
Example:
async function fetchStories(
token: string,
spaceId: string,
params: FetchStoriesParams
) {
const url = `https://mapi.storyblok.com/v1/spaces/${spaceId}/stories`;
const response = await fetch(url, {
headers: {
'Authorization': token,
'Content-Type': 'application/json'
},
params: buildQueryParams(params)
});
return await response.json();
}
5. Database Layer
Location: database/migrations/
Relational database with row-level security for multi-tenant isolation.
Database Architecture:
Multi-tenant relational database. Key entities:
- Organizations and user management
- Subscription and billing tracking
- API key registry
- Storyblok workspace connections (encrypted tokens)
- Usage and audit logging
Security Features:
- Database-level security for tenant isolation
- Encrypted credential storage using industry-standard authenticated encryption
- API keys securely hashed (one-way, not reversible)
- Audit logging for compliance
6. Dashboard
Location: dashboard/
User-facing dashboard for managing BlokMCP.
Pages:
/- Landing page/dashboard- Overview/dashboard/spaces- Storyblok space connections/dashboard/api-keys- API key management/dashboard/billing- Subscription management/dashboard/usage- Usage analytics/dashboard/settings- Account settings
Tech Stack:
- Modern web framework with TypeScript
- Managed authentication and database services
- Third-party billing integration
- Component library and CSS framework
See: dashboard/CLAUDE.md for detailed dashboard documentation.
Request Flow
Typical Tool Call Flow
1. User sends message in Claude Desktop
"Show me my recent blog posts"
2. Claude determines which tool to use
Tool: fetch_stories
3. Claude Desktop makes MCP request
POST https://mcp.blokmcp.com
Headers:
X-Api-Key: sb_mcp_abc123...
Content-Type: application/json
Body: {
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "fetch_stories",
"arguments": {
"starts_with": "blog/",
"per_page": 10,
"sort_by": "created_at:desc"
}
}
}
4. BlokMCP Worker receives request
- Parses MCP message
- Extracts X-Api-Key header
5. Authentication Middleware
- Hash API key
- Query database for key validation
- Load organization, subscription, usage
- Resolve space (default or from X-Storyblok-Space-Id)
- Decrypt Storyblok management token
- Check rate limits
- Create tenant context
6. Tool Router
- Find "fetch_stories" handler
- Validate input with Zod schema
- Call handler with tenant context
7. Tool Handler (fetch_stories)
- Build Storyblok API request
- Call Storyblok Management API
GET https://mapi.storyblok.com/v1/spaces/123456/stories
?starts_with=blog/&per_page=10&sort_by=created_at:desc
Authorization: {decrypted_management_token}
- Parse response
- Format for MCP
8. Record Usage
- Insert usage record to database
- Increment monthly usage counter
- Update key last_used timestamp
9. Return MCP Response
{
"jsonrpc": "2.0",
"result": {
"content": [
{
"type": "text",
"text": "Found 10 blog posts:\n1. Post Title..."
}
]
}
}
10. Claude Desktop receives response
- Displays results to user
- User can continue conversation
Security Model
Multi-Tenant Isolation
- Each organization is isolated via database-level security
- API keys scoped to single organization
- No cross-organization data access
Token Encryption
Storyblok tokens:
- Encrypted at rest with industry-standard authenticated encryption
ENCRYPTION_KEYstored as platform secret- Decrypted only when needed for API calls
- Never exposed in responses or logs
API keys:
- Securely hashed using industry-standard algorithms (one-way)
- Original key shown only once at creation
- Hashed value stored in database
- Compared via hash during authentication
Rate Limiting
Per-minute limits:
- Tracked using efficient in-memory mechanisms
- Scoped by organization
- Automatic reset and cleanup
- Returns 429 if exceeded
Monthly limits:
- Tracked in database
- Aggregated by billing period
- Checked on each request
- Enforced based on subscription tier
Multi-Tenant Isolation
Row-level security policies ensure data isolation between organizations. Users can only access data within their organization context.
Development Setup
Prerequisites
- Node.js 18+
- npm or pnpm
- Database service account
- Cloud platform account
Local Development
# MCP Server
npm install
npm run dev # Hot reload with tsx watch
npm run worker:dev # Run serverless locally
# Dashboard
cd dashboard
pnpm install
pnpm dev # Dashboard dev server on :3000
Environment Variables
MCP Server:
- Database connection credentials
- Encryption keys for token storage
- Environment and configuration settings
- Rate limiting parameters
Dashboard:
- Database connection credentials
- Billing provider API credentials
- Webhook secrets
- Application URLs and endpoints
- Shared encryption configuration
Deployment
MCP Server:
npm run worker:deploy
Dashboard:
cd dashboard
pnpm build
# Deploy to cloud hosting platform
See Local Development Guide for complete setup.
Adding New Tools
1. Create Tool Module
// src/tools/my-new-module.ts
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
const myToolInputSchema = z.object({
param1: z.string(),
param2: z.number().optional()
});
export function registerMyNewModuleTools(server: McpServer) {
server.addTool({
name: "my_new_tool",
description: "Does something useful",
inputSchema: myToolInputSchema,
handler: async (params, context) => {
// Validate input
const input = myToolInputSchema.parse(params);
// Get tenant context
const { organization, space, token } = context;
// Call Storyblok API
const result = await fetch(
`https://mapi.storyblok.com/v1/spaces/${space.space_id}/...`,
{
headers: { 'Authorization': token }
}
);
// Return MCP-formatted response
return {
content: [{
type: "text",
text: JSON.stringify(result, null, 2)
}]
};
}
});
}
2. Register in Index
// src/tools/index.ts
import { registerMyNewModuleTools } from './my-new-module.js';
export function registerAllTools(server: McpServer) {
// ... existing registrations
registerMyNewModuleTools(server);
}
3. Add Types (optional)
// src/types/my-new-module.ts
export interface MyNewToolParams {
param1: string;
param2?: number;
}
4. Test
npm run dev
# Test via Claude Desktop or curl
Architecture Design Principles
Serverless & Edge Computing
- Global distribution - Low latency worldwide
- Auto-scaling - Handles traffic spikes automatically
- Cost efficiency - Pay-per-use pricing model
- Zero infrastructure - Fully managed platform
Database Strategy
- Relational model - Structured data with ACID guarantees
- Multi-tenant security - Database-level isolation
- Managed service - High availability and backups
- Real-time capabilities - Live data synchronization
Type Safety
- Compile-time checks - Prevent runtime errors
- Enhanced tooling - Better developer experience
- Self-documenting - Types as documentation
- Safe refactoring - Confident code changes
Input Validation
- Runtime safety - Validate all external inputs
- Type inference - Automatic type derivation
- Clear feedback - Descriptive error messages
- Composable schemas - Reusable validation logic
Performance Considerations
Platform Constraints
The serverless architecture provides fast response times while maintaining resource efficiency. Most operations complete in single-digit milliseconds.
Caching Strategy
- Static data - Long-term caching for rarely-changing resources
- Metadata - Short-term caching with TTL
- Dynamic content - No caching for frequently updated data
Database Optimization
- Strategic indexing on frequently queried columns
- Query optimization for filtered and aggregated queries
- Connection management through pooling
- Read scaling for analytics and reporting
Monitoring & Observability
Metrics Tracked
- Request count per organization
- Response times (p50, p95, p99)
- Error rates by tool
- Rate limit hits
- Monthly usage per tier
Logging
- Application logs from serverless platform
- Database audit trail
- Error tracking and monitoring
Alerts
- Rate limit exceeded
- High error rates
- Database connection issues
- Payment failures
Related Resources
- Local Development Guide
- Contributing Guide
- CLAUDE.md - AI assistant guidance
- Dashboard Architecture
- Storyblok Management API
- Model Context Protocol
Questions about the architecture? Open an issue or check out the contributing guide.