Skip to main content

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:

  1. Coordinate work: Multi-agent systems need message queues for task distribution
  2. Store state: Agents need persistent key-value storage for context/memory
  3. Subscribe to events: Agents should react to events from other systems/agents
  4. Query history: Agents need searchable message history for context retrieval
  5. 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

  1. Agent-Native Data Access: Provide MCP tools that feel natural for agent workflows
  2. Mailbox Pattern Integration: Enable agents to subscribe to personal mailboxes for async messaging
  3. Namespace Isolation: Each agent/project gets isolated namespaces with proper authorization
  4. TypeScript + STDIO: Leverage MCP's TypeScript ecosystem with STDIO transport
  5. Full Prism Integration: Expose Prism's patterns (Producer, Consumer, KeyValue, Mailbox) via MCP
  6. Authentication: Support OAuth2, API keys, and developer identity for local testing
  7. Query Capabilities: Enable agents to search mailbox history by headers (principal, topic, correlation_id)

Non-Goals

  1. Admin Operations: MCP tool focuses on data plane, not control plane management
  2. Schema Registry: Schema evolution/validation deferred to separate RFC
  3. Multi-Region Failover: DNS-based discovery sufficient for initial version
  4. 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:

  1. MCP server loads credentials from config or environment
  2. OAuth2 token acquired on first request (or API key used)
  3. Token attached to all gRPC requests via Authorization header
  4. Prism proxy validates token and extracts principal
  5. 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:

  1. Agent calls prism_subscribe_mailbox(namespace: "agent-workspace")
  2. MCP server determines agent principal from auth context
  3. Subscribes to topic: agent-workspace/mailbox/claude-code
  4. Mailbox pattern queries SQLite for new messages with principal filter
  5. Returns array of MailboxEvent objects with headers + payload
  6. Agent processes messages and optionally ACKs them

Query Flow:

  1. Agent calls prism_query_mailbox(filter: {from_principal: "agent://coordinator"})
  2. MCP server translates to mailbox query using TableReaderInterface
  3. SQLite executes indexed query on headers
  4. Returns matching events sorted by timestamp
  5. 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_namespace tool
  • Implement prism_publish tool
  • Implement prism_keyvalue_set/get tools
  • 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_mailbox tool
  • Implement prism_query_mailbox tool
  • 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

  1. 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
  2. API Key: Simpler authentication for development

    • Single API key per agent or team
    • Passed via prism-api-key header
  3. Developer Identity: Local testing without OAuth2

    • Auto-provisioned identity: agent://dev@local.prism
    • No actual authentication required
    • Only for local dev environments

Namespace Authorization

  • Each namespace has access control policies (RFC-027)
  • Agent principal must be in namespace consumers list
  • 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

  1. Authentication Failure:
{
"error": "AUTHENTICATION_FAILED",
"message": "OAuth2 token invalid or expired",
"details": {
"token_endpoint": "https://auth.example.com/oauth/token",
"retry_after": 60
}
}
  1. 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"
}
}
  1. 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"]
}
}
  1. Mailbox Query Timeout:
{
"error": "TIMEOUT",
"message": "Mailbox subscribe timed out after 5 seconds",
"details": {
"messages_received": 0,
"timeout_seconds": 5
}
}

Performance Characteristics

Expected Performance

OperationLatency (P99)ThroughputNotes
prism_publish<50ms1k msg/secIncludes OAuth2 token check
prism_subscribe_mailbox<100ms500 msg/secBatched retrieval (max 10)
prism_query_mailbox<200ms100 queries/secSQLite indexed query
prism_keyvalue_set<20ms2k ops/secRedis/SQLite backend
prism_keyvalue_get<10ms5k ops/secCached reads

Optimization Strategies

  1. Token Caching: Cache OAuth2 tokens for 80% of token lifetime
  2. Connection Pooling: Reuse gRPC connections across tool calls
  3. Batch Retrieval: Subscribe returns up to 10 messages at once
  4. 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

Open Questions

  1. MCP Version: Which MCP protocol version to target? (Latest stable)
  2. Streaming: Should mailbox subscription support true streaming vs polling?
  3. Batch Operations: Support batch publish/query for efficiency?
  4. Schema Validation: Validate payload schemas before publish?
  5. 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