RFC-044: Prism MCP Agent Integration
Status: Proposed Author: Platform Team Created: 2025-10-22 Updated: 2025-10-22
Abstract
This RFC specifies prism-mcp, a Model Context Protocol (MCP) server that enables AI agents (like Claude) to interact with Prism as first-class data access clients. The tool provides agent-oriented APIs for publishing/subscribing to messages, using the mailbox pattern as a subscribable entity for agent-to-agent messaging, and managing namespace-scoped data access with full authentication and authorization support.
Motivation
Problem Statement
AI agents require reliable, persistent communication channels to:
- Coordinate work: Multi-agent systems need message queues for task distribution
- Store state: Agents need persistent key-value storage for context/memory
- Subscribe to events: Agents should react to events from other systems/agents
- Query history: Agents need searchable message history for context retrieval
- Maintain identity: Each agent needs authenticated identity with proper access control
Currently, agents must:
- Use ad-hoc file systems or external services for state
- Implement custom messaging infrastructure
- Handle authentication/authorization manually
- Build query interfaces from scratch
Goals
- Agent-Native Data Access: Provide MCP tools that feel natural for agent workflows
- Mailbox Pattern Integration: Enable agents to subscribe to personal mailboxes for async messaging
- Namespace Isolation: Each agent/project gets isolated namespaces with proper authorization
- TypeScript + STDIO: Leverage MCP's TypeScript ecosystem with STDIO transport
- Full Prism Integration: Expose Prism's patterns (Producer, Consumer, KeyValue, Mailbox) via MCP
- Authentication: Support OAuth2, API keys, and developer identity for local testing
- Query Capabilities: Enable agents to search mailbox history by headers (principal, topic, correlation_id)
Non-Goals
- Admin Operations: MCP tool focuses on data plane, not control plane management
- Schema Registry: Schema evolution/validation deferred to separate RFC
- Multi-Region Failover: DNS-based discovery sufficient for initial version
- Custom Serialization: JSON and protobuf only (no custom formats)
Architecture Overview
MCP Server Architecture
┌────────────────────────────────────────────────────────────┐
│ AI Agent (Claude) │
│ │
│ "Publish order-123 to orders topic" │
│ "Subscribe to my mailbox" │
│ "Query messages from user-123" │
└────────────────────────┬───────────────────────────────────┘
│ MCP Protocol (STDIO)
│
┌────────────────────────▼───────────────────────────────────┐
│ Prism MCP Server │
│ (TypeScript + STDIO) │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ MCP Tool Handlers │ │
│ │ │ │
│ │ - prism_create_namespace │ │
│ │ - prism_publish │ │
│ │ - prism_subscribe_mailbox │ │
│ │ - prism_query_mailbox │ │
│ │ - prism_keyvalue_set / get / delete │ │
│ │ - prism_get_identity │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Prism Client SDK (TypeScript) │ │
│ │ │ │
│ │ - Pattern APIs (Producer, Consumer, KeyValue) │ │
│ │ - OAuth2 Authentication │ │
│ │ - Namespace Management │ │
│ │ - gRPC Client Transport │ │
│ └──────────────────────────────────────────────────────┘ │
└────────────────────────┬───────────────────────────────────┘
│ gRPC + OAuth2/mTLS
│
┌────────────────────────▼───────────────────────────────────┐
│ Prism Proxy │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Producer │ │ Consumer │ │ KeyValue │ │
│ │ Pattern │ │ Pattern │ │ Pattern │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Mailbox Pattern (RFC-037) │ │
│ │ │ │
│ │ Message Source → Storage → Query Interface │ │
│ │ (NATS Queue) (SQLite) (TableReader) │ │
│ └─────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────┘
Agent Identity and Authentication
Each agent gets a unique identity (principal) for access control:
┌────────────────────────────────────────────────────────────┐
│ Agent Identity │
│ │
│ Principal: agent://claude-code/session-abc-123 │
│ Namespace: agent-workspace │
│ Permissions: [producer, consumer, keyvalue, mailbox] │
│ Mailbox: agent-workspace/mailbox/claude-code │
└────────────────────────────────────────────────────────────┘
Authentication Flow:
- MCP server loads credentials from config or environment
- OAuth2 token acquired on first request (or API key used)
- Token attached to all gRPC requests via Authorization header
- Prism proxy validates token and extracts principal
- Principal used for namespace authorization and mailbox routing
MCP Tools Specification
Tool 1: prism_create_namespace
Create or configure a Prism namespace for agent use.
Input Schema:
{
name: "prism_create_namespace",
description: "Create or configure a Prism namespace",
inputSchema: {
type: "object",
properties: {
namespace: {
type: "string",
description: "Namespace name (e.g., 'agent-workspace', 'order-processing')"
},
pattern: {
type: "string",
enum: ["producer", "consumer", "keyvalue", "mailbox"],
description: "Primary access pattern"
},
needs: {
type: "object",
properties: {
durability: { type: "string", enum: ["strong", "eventual", "best-effort"] },
max_message_size: { type: "string", description: "e.g., '10MB', '1GB'" },
retention: { type: "string", description: "e.g., '30days', '90days'" },
write_rps: { type: "number" },
read_rps: { type: "number" }
}
}
},
required: ["namespace", "pattern"]
}
}
Output:
{
"namespace": "agent-workspace",
"status": "active",
"endpoints": ["prism-proxy:8980"],
"mailbox_topic": "agent-workspace/mailbox/claude-code",
"created_at": "2025-10-22T10:00:00Z"
}
Example Usage:
Agent: Create a namespace called "agent-workspace" for mailbox pattern with strong durability
Tool 2: prism_publish
Publish a message to a topic or queue.
Input Schema:
{
name: "prism_publish",
description: "Publish message to Prism topic/queue",
inputSchema: {
type: "object",
properties: {
namespace: { type: "string" },
topic: { type: "string", description: "Topic name (e.g., 'orders', 'events')" },
payload: { type: "string", description: "Message payload (JSON string)" },
metadata: {
type: "object",
additionalProperties: { type: "string" },
description: "Message metadata/headers"
},
target_agent: {
type: "string",
description: "Optional: Target agent principal for mailbox delivery"
}
},
required: ["namespace", "topic", "payload"]
}
}
Output:
{
"message_id": "msg-abc-123",
"offset": 12345,
"timestamp": "2025-10-22T10:01:00Z"
}
Example Usage:
Agent: Publish order-123 details to orders topic in agent-workspace namespace
Agent: Send message to agent-bob's mailbox
Tool 3: prism_subscribe_mailbox
Subscribe to agent's personal mailbox for incoming messages.
Input Schema:
{
name: "prism_subscribe_mailbox",
description: "Subscribe to agent mailbox for incoming messages",
inputSchema: {
type: "object",
properties: {
namespace: { type: "string" },
max_messages: { type: "number", default: 10 },
timeout_seconds: { type: "number", default: 5 },
auto_ack: { type: "boolean", default: true }
},
required: ["namespace"]
}
}
Output:
{
"messages": [
{
"message_id": "msg-def-456",
"topic": "agent-workspace/mailbox/claude-code",
"payload": "{\"task\": \"process order\", \"order_id\": 123}",
"metadata": {
"from_principal": "agent://coordinator/session-xyz",
"correlation_id": "task-789",
"timestamp": "2025-10-22T10:02:00Z"
}
}
],
"has_more": false
}
Example Usage:
Agent: Check my mailbox for new messages
Agent: Subscribe to mailbox and wait for tasks
Tool 4: prism_query_mailbox
Query mailbox history by headers (principal, topic, correlation_id).
Input Schema:
{
name: "prism_query_mailbox",
description: "Query mailbox history by filters",
inputSchema: {
type: "object",
properties: {
namespace: { type: "string" },
filter: {
type: "object",
properties: {
from_principal: { type: "string" },
correlation_id: { type: "string" },
start_time: { type: "string", format: "date-time" },
end_time: { type: "string", format: "date-time" },
topic: { type: "string" }
}
},
limit: { type: "number", default: 100 }
},
required: ["namespace"]
}
}
Output:
{
"events": [
{
"message_id": "msg-ghi-789",
"timestamp": "2025-10-22T09:30:00Z",
"topic": "agent-workspace/mailbox/claude-code",
"from_principal": "agent://user-api/session-123",
"correlation_id": "trace-abc",
"payload": "{\"status\": \"order completed\"}"
}
],
"total_count": 45
}
Example Usage:
Agent: Query all messages from user-api in the last hour
Agent: Find all messages with correlation_id trace-abc
Tool 5: prism_keyvalue_set
Store key-value data in namespace.
Input Schema:
{
name: "prism_keyvalue_set",
description: "Store key-value data",
inputSchema: {
type: "object",
properties: {
namespace: { type: "string" },
key: { type: "string" },
value: { type: "string" },
ttl_seconds: { type: "number", description: "Optional TTL" }
},
required: ["namespace", "key", "value"]
}
}
Output:
{
"success": true,
"key": "session:context",
"expires_at": "2025-10-22T11:00:00Z"
}
Tool 6: prism_keyvalue_get
Retrieve key-value data from namespace.
Input Schema:
{
name: "prism_keyvalue_get",
description: "Retrieve key-value data",
inputSchema: {
type: "object",
properties: {
namespace: { type: "string" },
key: { type: "string" }
},
required: ["namespace", "key"]
}
}
Output:
{
"key": "session:context",
"value": "{\"user_id\": 123, \"preferences\": {...}}",
"exists": true
}
Tool 7: prism_get_identity
Get current agent's identity and permissions.
Input Schema:
{
name: "prism_get_identity",
description: "Get current agent identity and permissions",
inputSchema: { type: "object", properties: {} }
}
Output:
{
"principal": "agent://claude-code/session-abc-123",
"namespaces": ["agent-workspace", "shared-data"],
"permissions": ["producer", "consumer", "keyvalue", "mailbox"],
"mailbox_topic": "agent-workspace/mailbox/claude-code"
}
Mailbox Pattern Integration
Agent-to-Agent Messaging
The mailbox pattern (RFC-037) is ideal for agent communication:
┌─────────────────────────────────────────────────────────────┐
│ Agent Alice (Coordinator) │
│ │
│ Task: Process orders │
│ Action: Publish task to Agent Bob's mailbox │
└──────────────────────┬── ────────────────────────────────────┘
│
│ prism_publish(
│ namespace: "agent-workspace",
│ topic: "mailbox/bob",
│ target_agent: "agent://bob/session-xyz",
│ payload: {"task": "process order", "order_id": 123}
│ )
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Prism Mailbox Pattern │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ NATS │────>│ SQLite │────>│ Query │ │
│ │ Queue │ │ Storage │ │ Interface │ │
│ └──────────────┘ └──────────────┘ └────────────┘ │
│ │
│ Indexed Headers: [from_principal, correlation_id, topic] │
│ Body: {"task": "process order", "order_id": 123} │
└─────────────────────────┬───────────────────────────────────┘
│
│ Agent Bob subscribes to mailbox
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Agent Bob (Worker) │
│ │
│ Action: prism_subscribe_mailbox() │
│ Receives: {"task": "process order", "order_id": 123} │
│ Processes: Order processing logic │
│ Response: prism_publish() result to Alice's mailbox │
└─────────────────────────────────────────────────────────────┘
Mailbox Subscription Model
Each agent gets a personal mailbox topic: {namespace}/mailbox/{agent_id}
Subscription Flow:
- Agent calls
prism_subscribe_mailbox(namespace: "agent-workspace") - MCP server determines agent principal from auth context
- Subscribes to topic:
agent-workspace/mailbox/claude-code - Mailbox pattern queries SQLite for new messages with principal filter
- Returns array of
MailboxEventobjects with headers + payload - Agent processes messages and optionally ACKs them
Query Flow:
- Agent calls
prism_query_mailbox(filter: {from_principal: "agent://coordinator"}) - MCP server translates to mailbox query using
TableReaderInterface - SQLite executes indexed query on headers
- Returns matching events sorted by timestamp
- Agent uses context for decision-making
Configuration Schema
MCP Server Configuration
# prism-mcp-config.yaml
# Prism proxy endpoints
prism:
endpoints:
- localhost:8980
discovery: dns # dns | api | static
# Authentication (choose one)
auth:
# Option 1: OAuth2 (production)
type: oauth2
client_id: prism-mcp-agent
client_secret: ${PRISM_CLIENT_SECRET}
token_endpoint: https://auth.example.com/oauth/token
scopes: [prism.producer, prism.consumer, prism.keyvalue, prism.mailbox]
# Option 2: API Key (development)
# type: api_key
# api_key: ${PRISM_API_KEY}
# Option 3: Developer Identity (local testing)
# type: dev_identity
# principal: agent://dev@local.prism
# Agent identity
agent:
name: claude-code
principal: agent://claude-code/${SESSION_ID}
# Default namespace settings
defaults:
namespace: agent-workspace
durability: strong
retention: 30days
# MCP server settings
mcp:
transport: stdio
log_level: info
log_file: ~/.prism/mcp-server.log
Namespace Configuration for Agents
# Auto-created namespace for agents
namespaces:
- name: agent-workspace
pattern: mailbox
pattern_version: 0.1.0
# Mailbox pattern configuration
slots:
message_source:
backend: nats
interfaces: [QueueInterface]
config:
url: nats://localhost:4222
subject: agent.mailbox.>
consumer_group: agent-consumers
storage:
backend: sqlite
interfaces: [TableWriterInterface]
config:
database_path: ~/.prism/agent-mailbox.db
table_name: mailbox
indexed_headers:
- prism-message-id
- prism-timestamp
- prism-principal
- prism-correlation-id
- prism-topic
retention_days: 30
query:
backend: sqlite
interfaces: [TableReaderInterface]
config:
database_path: ~/.prism/agent-mailbox.db
table_name: mailbox
# Access control
access:
owners:
- team: platform-team
consumers:
- service: agent://* # All agents can access
behavior:
batch_size: 10
auto_commit: true
Implementation Plan
Phase 1: Core MCP Server (Week 1-2)
Deliverables:
- TypeScript MCP server scaffolding
- STDIO transport integration
- Configuration loading (YAML + env vars)
- OAuth2 authentication client
- Basic tool registration
Success Criteria:
- MCP server starts and responds to
tools/list - OAuth2 token acquisition works
- Configuration loaded correctly
Phase 2: Pattern Integration (Week 2-3)
Deliverables:
- Integrate Prism TypeScript client SDK (RFC-040)
- Implement
prism_create_namespacetool - Implement
prism_publishtool - Implement
prism_keyvalue_set/gettools - Error handling and retry logic
Success Criteria:
- Agent can create namespace
- Agent can publish messages
- Agent can store/retrieve key-value data
Phase 3: Mailbox Pattern Support (Week 3-4)
Deliverables:
- Implement
prism_subscribe_mailboxtool - Implement
prism_query_mailboxtool - Mailbox topic routing (agent principal → topic mapping)
- Message filtering by headers
Success Criteria:
- Agent can subscribe to personal mailbox
- Agent can query mailbox history
- Agent-to-agent messaging works
Phase 4: Testing & Documentation (Week 4-5)
Deliverables:
- Unit tests for all tools
- Integration tests with local Prism
- End-to-end agent scenarios
- User documentation and examples
- Performance benchmarks
Success Criteria:
- 85%+ test coverage
- Integration tests pass
- Example workflows documented
Usage Examples
Example 1: Agent Creates Workspace and Publishes Task
// Agent prompt:
// "Create a workspace namespace and publish a task to process order-123"
// Tool call 1: Create namespace
{
"tool": "prism_create_namespace",
"arguments": {
"namespace": "agent-workspace",
"pattern": "mailbox",
"needs": {
"durability": "strong",
"retention": "30days"
}
}
}
// Response:
{
"namespace": "agent-workspace",
"status": "active",
"mailbox_topic": "agent-workspace/mailbox/claude-code"
}
// Tool call 2: Publish task
{
"tool": "prism_publish",
"arguments": {
"namespace": "agent-workspace",
"topic": "tasks",
"payload": "{\"type\": \"process_order\", \"order_id\": 123, \"priority\": \"high\"}",
"metadata": {
"from_principal": "agent://coordinator/session-abc",
"correlation_id": "task-123"
}
}
}
// Response:
{
"message_id": "msg-xyz-789",
"offset": 1,
"timestamp": "2025-10-22T10:05:00Z"
}
Example 2: Agent Subscribes to Mailbox
// Agent prompt:
// "Check my mailbox for new tasks"
// Tool call:
{
"tool": "prism_subscribe_mailbox",
"arguments": {
"namespace": "agent-workspace",
"max_messages": 5,
"timeout_seconds": 10
}
}
// Response:
{
"messages": [
{
"message_id": "msg-abc-456",
"topic": "agent-workspace/mailbox/claude-code",
"payload": "{\"task\": \"analyze data\", \"dataset_id\": 789}",
"metadata": {
"from_principal": "agent://coordinator/session-xyz",
"correlation_id": "trace-def",
"timestamp": "2025-10-22T10:03:00Z"
}
}
],
"has_more": false
}
// Agent processes task and responds
{
"tool": "prism_publish",
"arguments": {
"namespace": "agent-workspace",
"topic": "mailbox/coordinator",
"target_agent": "agent://coordinator/session-xyz",
"payload": "{\"status\": \"completed\", \"result\": {...}}",
"metadata": {
"correlation_id": "trace-def",
"reply_to": "msg-abc-456"
}
}
}
Example 3: Agent Queries Message History
// Agent prompt:
// "Show me all messages from the coordinator in the last hour"
// Tool call:
{
"tool": "prism_query_mailbox",
"arguments": {
"namespace": "agent-workspace",
"filter": {
"from_principal": "agent://coordinator/session-xyz",
"start_time": "2025-10-22T09:00:00Z",
"end_time": "2025-10-22T10:00:00Z"
},
"limit": 50
}
}
// Response:
{
"events": [
{
"message_id": "msg-001",
"timestamp": "2025-10-22T09:15:00Z",
"topic": "agent-workspace/mailbox/claude-code",
"from_principal": "agent://coordinator/session-xyz",
"correlation_id": "task-batch-1",
"payload": "{\"task\": \"process batch 1\"}"
},
{
"message_id": "msg-002",
"timestamp": "2025-10-22T09:45:00Z",
"topic": "agent-workspace/mailbox/claude-code",
"from_principal": "agent://coordinator/session-xyz",
"correlation_id": "task-batch-2",
"payload": "{\"task\": \"process batch 2\"}"
}
],
"total_count": 2
}
Example 4: Agent Uses KeyValue for State
// Agent prompt:
// "Store the current user context for later retrieval"
// Tool call 1: Store context
{
"tool": "prism_keyvalue_set",
"arguments": {
"namespace": "agent-workspace",
"key": "session:context:abc-123",
"value": "{\"user_id\": 456, \"preferences\": {\"theme\": \"dark\"}, \"last_action\": \"order_created\"}",
"ttl_seconds": 3600
}
}
// Response:
{
"success": true,
"key": "session:context:abc-123",
"expires_at": "2025-10-22T11:05:00Z"
}
// Later: Retrieve context
{
"tool": "prism_keyvalue_get",
"arguments": {
"namespace": "agent-workspace",
"key": "session:context:abc-123"
}
}
// Response:
{
"key": "session:context:abc-123",
"value": "{\"user_id\": 456, \"preferences\": {\"theme\": \"dark\"}, \"last_action\": \"order_created\"}",
"exists": true
}
Security Considerations
Agent Authentication
-
OAuth2 Client Credentials: MCP server acts as OAuth2 client
- Client ID and secret stored in config or environment
- Token acquired on server startup or first request
- Token refresh handled automatically
-
API Key: Simpler authentication for development
- Single API key per agent or team
- Passed via
prism-api-keyheader
-
Developer Identity: Local testing without OAuth2
- Auto-provisioned identity:
agent://dev@local.prism - No actual authentication required
- Only for local dev environments
- Auto-provisioned identity:
Namespace Authorization
- Each namespace has access control policies (RFC-027)
- Agent principal must be in namespace
consumerslist - Mailbox topics scoped to agent principal
- Cross-agent messaging requires explicit permission
Data Privacy
- Mailbox messages stored with encrypted bodies (optional)
- Headers remain searchable (not encrypted)
- PII should not be in headers (by convention)
- Agent identity logged for audit trail
Error Handling
Common Error Scenarios
- Authentication Failure:
{
"error": "AUTHENTICATION_FAILED",
"message": "OAuth2 token invalid or expired",
"details": {
"token_endpoint": "https://auth.example.com/oauth/token",
"retry_after": 60
}
}
- Namespace Not Found:
{
"error": "NAMESPACE_NOT_FOUND",
"message": "Namespace 'agent-workspace' does not exist",
"details": {
"available_namespaces": ["shared-data"],
"suggestion": "Call prism_create_namespace first"
}
}
- Permission Denied:
{
"error": "PERMISSION_DENIED",
"message": "Agent 'agent://claude-code/session-123' not authorized for namespace 'production-data'",
"details": {
"required_permission": "consumer",
"agent_permissions": ["mailbox"]
}
}
- Mailbox Query Timeout:
{
"error": "TIMEOUT",
"message": "Mailbox subscribe timed out after 5 seconds",
"details": {
"messages_received": 0,
"timeout_seconds": 5
}
}
Performance Characteristics
Expected Performance
| Operation | Latency (P99) | Throughput | Notes |
|---|---|---|---|
prism_publish | <50ms | 1k msg/sec | Includes OAuth2 token check |
prism_subscribe_mailbox | <100ms | 500 msg/sec | Batched retrieval (max 10) |
prism_query_mailbox | <200ms | 100 queries/sec | SQLite indexed query |
prism_keyvalue_set | <20ms | 2k ops/sec | Redis/SQLite backend |
prism_keyvalue_get | <10ms | 5k ops/sec | Cached reads |
Optimization Strategies
- Token Caching: Cache OAuth2 tokens for 80% of token lifetime
- Connection Pooling: Reuse gRPC connections across tool calls
- Batch Retrieval: Subscribe returns up to 10 messages at once
- Local Cache: Cache namespace metadata and endpoints
Testing Strategy
Standalone Testing Without Agent Embedding
The prism-mcp tool can be tested locally without embedding into an agent using a standalone test client that simulates MCP protocol messages via STDIO.
Test Architecture:
┌────────────────────────────────────────────────────────────┐
│ mcp-test-client.ts (Test Client) │
│ Simulates MCP Agent Protocol │
│ │
│ - Spawns prism-mcp server as child process │
│ - Sends JSON-RPC messages via stdin │
│ - Reads responses from stdout │
│ - Validates tool functionality │
└────────────────────┬───────────────────────────────────────┘
│ STDIO (JSON-RPC 2.0)
┌────────────────────▼───────────────────────────────────────┐
│ prism-mcp server (MCP Tool Server) │
│ │
│ - Handles MCP tool calls │
│ - Translates to Prism client SDK │
└────────────────────┬───────────────────────────────────────┘
│ gRPC
┌────────────────────▼───────────────────────────────────────┐
│ Prism Proxy + Backends (Docker Compose) │
│ │
│ - PostgreSQL (KeyValue) │
│ - NATS (Mailbox message source) │
│ - Redis (Cache) │
└────────────────────────────────────────────────────────────┘
Test Infrastructure Location: tests/testing/mcp/
tests/testing/mcp/
├── docker-compose.mcp-test.yml # Prism + backends
├── mcp-test-client.ts # Standalone test client
├── test-config.yml # Test configuration
├── package.json # Dependencies
├── tsconfig.json # TypeScript config
└── README.md # Test documentation
Running Standalone Tests
# Start test infrastructure
cd tests/testing/mcp
npm install
npm run test:start
# Run integration tests
npm test
# Stop infrastructure
npm run test:stop
Unit Tests
describe('PrismMCPServer', () => {
it('should authenticate with OAuth2', async () => {
const server = new PrismMCPServer(config);
const token = await server.authenticate();
expect(token).toBeDefined();
expect(token.expires_at).toBeGreaterThan(Date.now());
});
it('should create namespace', async () => {
const result = await server.createNamespace({
namespace: 'test-workspace',
pattern: 'mailbox'
});
expect(result.status).toBe('active');
});
it('should publish message', async () => {
const result = await server.publish({
namespace: 'test-workspace',
topic: 'tasks',
payload: '{"task": "test"}'
});
expect(result.message_id).toBeDefined();
});
});
Integration Tests (Standalone Test Client)
The standalone test client (tests/testing/mcp/mcp-test-client.ts) simulates an MCP agent and validates all tool functionality:
// Standalone MCP test client that spawns prism-mcp server
class MCPTestClient {
async start(mcpServerPath: string, configPath?: string): Promise<void> {
// Spawn prism-mcp server as child process
this.mcpProcess = spawn(mcpServerPath, ['--config', configPath], {
stdio: ['pipe', 'pipe', 'inherit'],
});
// Setup JSON-RPC communication via STDIO
this.rl = readline.createInterface({
input: this.mcpProcess.stdout,
});
this.rl.on('line', (line) => {
const response: MCPResponse = JSON.parse(line);
this.handleResponse(response);
});
// Initialize MCP session
await this.initialize();
}
async callTool(name: string, args: Record<string, any>): Promise<any> {
// Send MCP tools/call request
return await this.sendRequest('tools/call', { name, arguments: args });
}
}
// Integration tests using standalone client
class MCPIntegrationTests {
async testListTools(): Promise<void> {
const tools = await this.client.listTools();
assert(tools.length === 7, 'Expected 7 MCP tools');
}
async testMailboxMessaging(): Promise<void> {
// Publish to mailbox
await this.client.callTool('prism_publish', {
namespace: 'agent-workspace',
topic: 'mailbox',
payload: '{"task": "test"}',
metadata: { correlation_id: 'test-123' }
});
// Subscribe to mailbox
const result = await this.client.callTool('prism_subscribe_mailbox', {
namespace: 'agent-workspace',
max_messages: 10
});
const data = JSON.parse(result.content[0].text);
assert(data.messages.length > 0, 'Expected messages in mailbox');
}
async testQueryMailbox(): Promise<void> {
// Query by correlation_id
const result = await this.client.callTool('prism_query_mailbox', {
namespace: 'agent-workspace',
filter: { correlation_id: 'test-123' }
});
const data = JSON.parse(result.content[0].text);
assert(data.events.length > 0, 'Expected matching events');
assert(data.events[0].correlation_id === 'test-123', 'Correlation ID mismatch');
}
}
// Usage
const client = new MCPTestClient();
await client.start('./prism-mcp/dist/index.js', './test-config.yml');
const tests = new MCPIntegrationTests(client);
await tests.runAll();
client.stop();
Test Output Example:
================================================================================
PRISM MCP INTEGRATION TESTS
================================================================================
📋 TEST: List Tools
Found 7 tools:
✓ prism_create_namespace
✓ prism_publish
✓ prism_subscribe_mailbox
✓ prism_query_mailbox
✓ prism_keyvalue_set
✓ prism_keyvalue_get
✓ prism_get_identity
✅ PASSED: List Tools
🆔 TEST: Get Identity
Principal: agent://test-agent@local.prism
Permissions: producer, consumer, keyvalue, mailbox
✅ PASSED: Get Identity
🔑 TEST: KeyValue Operations
✓ SET test:kv:1234567890
✓ GET test:kv:1234567890
✅ PASSED: KeyValue Operations
📤 TEST: Publish Message
✓ Published message_id: msg-abc-123
✓ Offset: 1
✅ PASSED: Publish Message
📥 TEST: Subscribe Mailbox
✓ Published message to mailbox
✓ Received 1 messages
✅ PASSED: Subscribe Mailbox
🔍 TEST: Query Mailbox
✓ Found matching events with correlation_id
✅ PASSED: Query Mailbox
================================================================================
RESULTS: 6 passed, 0 failed
================================================================================
Docker Compose Test Infrastructure
File: tests/testing/mcp/docker-compose.mcp-test.yml
services:
# PostgreSQL for KeyValue pattern
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: prism_test
POSTGRES_USER: prism
POSTGRES_PASSWORD: prism_test_password
healthcheck:
test: ["CMD-SHELL", "pg_isready -U prism"]
interval: 1s
retries: 30
# NATS for Mailbox pattern
nats:
image: nats:2.10-alpine
command: ["-js", "-m", "8222"]
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://localhost:8222/healthz"]
interval: 1s
retries: 10
# Redis for caching
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
interval: 1s
retries: 10
# Prism Proxy
prism-proxy:
build:
context: ../../..
dockerfile: prism-proxy/Dockerfile
environment:
RUST_LOG: debug
PRISM_AUTH_MODE: dev # Developer identity (no OAuth2)
PRISM_DEV_PRINCIPAL: agent://dev@local.prism
ports:
- "8980:8980"
depends_on:
postgres: { condition: service_healthy }
nats: { condition: service_healthy }
redis: { condition: service_healthy }
Test Configuration
File: tests/testing/mcp/test-config.yml
prism:
endpoints:
- localhost:8980
discovery: static
auth:
type: dev_identity
principal: agent://test-agent@local.prism
agent:
name: test-agent
defaults:
namespace: agent-workspace
durability: strong
retention: 30days
mcp:
transport: stdio
log_level: info
Related Documents
- RFC-037: Mailbox Pattern - Searchable event store for agent messaging
- RFC-040: Multi-Language Client SDK - TypeScript client SDK architecture
- RFC-027: Namespace Configuration - Client perspective on namespaces
- RFC-014: Layered Data Access Patterns - Pattern composition
- ADR-007: Authentication and Authorization - Auth mechanisms
- ADR-006: Namespace and Multi-Tenancy - Namespace isolation
Open Questions
- MCP Version: Which MCP protocol version to target? (Latest stable)
- Streaming: Should mailbox subscription support true streaming vs polling?
- Batch Operations: Support batch publish/query for efficiency?
- Schema Validation: Validate payload schemas before publish?
- Offline Mode: Cache messages locally when proxy unavailable?
Success Criteria
- ✅ MCP server starts and registers all tools
- ✅ Agent can authenticate with OAuth2 or API key
- ✅ Agent can create namespace and publish messages
- ✅ Agent can subscribe to personal mailbox
- ✅ Agent-to-agent messaging works via mailbox pattern
- ✅ Agent can query mailbox history by filters
- ✅ Agent can store/retrieve key-value data
- ✅ Integration tests pass with local Prism
- ✅ Performance targets met (see table above)
Revision History
- 2025-10-22: Initial draft defining Prism MCP agent integration with mailbox pattern support