v2/docs/mcp-spec-2025-implementation-plan.md
Timeline: RC November 14, 2025 → Final November 25, 2025 Status: Implementation Phase Priority: CRITICAL - Spec-breaking changes require immediate action
The upcoming MCP spec introduces 3 major changes that require updates to Claude Flow:
Combined with Anthropic's engineering guidance, these changes will:
Goal: Have infrastructure ready for RC validation
Goal: Test compatibility and fix issues before final spec
Goal: Deploy to production with full spec compliance
MCP will support first-class async operations:
handler() functionsCreate: src/mcp/async/job-manager.ts
import { EventEmitter } from 'events';
import { v4 as uuidv4 } from 'uuid';
export type JobStatus =
| 'queued' // Job submitted but not started
| 'running' // Job in progress
| 'completed' // Job finished successfully
| 'failed' // Job failed with error
| 'cancelled'; // Job cancelled by user
export interface AsyncJob<TInput = any, TResult = any> {
id: string;
toolName: string;
status: JobStatus;
progress?: number; // 0-100
input: TInput;
result?: TResult;
error?: {
code: string;
message: string;
details?: any;
};
metadata: {
createdAt: Date;
startedAt?: Date;
completedAt?: Date;
estimatedDuration?: number; // milliseconds
actualDuration?: number;
};
context?: any; // Tool context
}
export interface JobHandle {
jobId: string;
status: JobStatus;
progress?: number;
pollUrl?: string; // URL to poll for status
webhookUrl?: string; // Optional webhook for completion
}
/**
* Manages async job lifecycle for MCP tools
* Supports polling, resumption, and cancellation
*/
export class JobManager extends EventEmitter {
private jobs: Map<string, AsyncJob> = new Map();
private executors: Map<string, Promise<any>> = new Map();
constructor(
private maxJobs: number = 1000,
private jobTTL: number = 86400000 // 24 hours
) {
super();
// Cleanup expired jobs every hour
setInterval(() => this.cleanupExpiredJobs(), 3600000);
}
/**
* Submit a new async job
* Returns job handle immediately, execution happens in background
*/
async submitJob<TInput, TResult>(
toolName: string,
input: TInput,
executor: (input: TInput, progress: (percent: number) => void) => Promise<TResult>,
context?: any
): Promise<JobHandle> {
// Check capacity
if (this.jobs.size >= this.maxJobs) {
this.cleanupExpiredJobs();
if (this.jobs.size >= this.maxJobs) {
throw new Error('Job queue full. Please try again later.');
}
}
// Create job
const jobId = uuidv4();
const job: AsyncJob<TInput, TResult> = {
id: jobId,
toolName,
status: 'queued',
input,
metadata: {
createdAt: new Date(),
},
context,
};
this.jobs.set(jobId, job);
// Start execution in background
this.executeJob(job, executor);
// Return handle immediately
return {
jobId,
status: 'queued',
pollUrl: `/mcp/jobs/${jobId}`,
};
}
/**
* Execute job in background
*/
private async executeJob<TInput, TResult>(
job: AsyncJob<TInput, TResult>,
executor: (input: TInput, progress: (percent: number) => void) => Promise<TResult>
): Promise<void> {
// Update status to running
job.status = 'running';
job.metadata.startedAt = new Date();
this.emit('job:started', job.id);
try {
// Execute with progress callback
const progressCallback = (percent: number) => {
job.progress = Math.min(100, Math.max(0, percent));
this.emit('job:progress', job.id, job.progress);
};
const result = await executor(job.input, progressCallback);
// Mark completed
job.status = 'completed';
job.result = result;
job.progress = 100;
job.metadata.completedAt = new Date();
job.metadata.actualDuration =
job.metadata.completedAt.getTime() - job.metadata.startedAt!.getTime();
this.emit('job:completed', job.id, result);
} catch (error: any) {
// Mark failed
job.status = 'failed';
job.error = {
code: error.code || 'EXECUTION_ERROR',
message: error.message,
details: error.details || error.stack,
};
job.metadata.completedAt = new Date();
this.emit('job:failed', job.id, error);
}
}
/**
* Get job status (for polling)
*/
getJobStatus(jobId: string): JobHandle | null {
const job = this.jobs.get(jobId);
if (!job) return null;
return {
jobId: job.id,
status: job.status,
progress: job.progress,
pollUrl: `/mcp/jobs/${jobId}`,
};
}
/**
* Get full job details
*/
getJob(jobId: string): AsyncJob | null {
return this.jobs.get(jobId) || null;
}
/**
* Get job result (blocks until completed or failed)
*/
async waitForJob<TResult>(
jobId: string,
timeout: number = 300000 // 5 minutes default
): Promise<TResult> {
const job = this.jobs.get(jobId);
if (!job) {
throw new Error(`Job not found: ${jobId}`);
}
// If already completed, return immediately
if (job.status === 'completed') {
return job.result as TResult;
}
if (job.status === 'failed') {
throw new Error(job.error?.message || 'Job failed');
}
// Wait for completion
return new Promise((resolve, reject) => {
const timeoutHandle = setTimeout(() => {
this.removeListener('job:completed', completedHandler);
this.removeListener('job:failed', failedHandler);
reject(new Error('Job timeout'));
}, timeout);
const completedHandler = (completedJobId: string, result: TResult) => {
if (completedJobId === jobId) {
clearTimeout(timeoutHandle);
this.removeListener('job:failed', failedHandler);
resolve(result);
}
};
const failedHandler = (failedJobId: string, error: Error) => {
if (failedJobId === jobId) {
clearTimeout(timeoutHandle);
this.removeListener('job:completed', completedHandler);
reject(error);
}
};
this.on('job:completed', completedHandler);
this.on('job:failed', failedHandler);
});
}
/**
* Cancel a running job
*/
async cancelJob(jobId: string): Promise<boolean> {
const job = this.jobs.get(jobId);
if (!job) return false;
if (job.status === 'completed' || job.status === 'failed') {
return false; // Already finished
}
job.status = 'cancelled';
job.metadata.completedAt = new Date();
this.emit('job:cancelled', jobId);
return true;
}
/**
* List jobs with filtering
*/
listJobs(filter?: {
status?: JobStatus;
toolName?: string;
limit?: number;
}): AsyncJob[] {
let jobs = Array.from(this.jobs.values());
if (filter?.status) {
jobs = jobs.filter(j => j.status === filter.status);
}
if (filter?.toolName) {
jobs = jobs.filter(j => j.toolName === filter.toolName);
}
// Sort by creation time (newest first)
jobs.sort((a, b) =>
b.metadata.createdAt.getTime() - a.metadata.createdAt.getTime()
);
if (filter?.limit) {
jobs = jobs.slice(0, filter.limit);
}
return jobs;
}
/**
* Cleanup expired jobs
*/
private cleanupExpiredJobs(): number {
const now = Date.now();
let cleaned = 0;
for (const [jobId, job] of this.jobs.entries()) {
const age = now - job.metadata.createdAt.getTime();
// Remove if expired and not running
if (age > this.jobTTL && job.status !== 'running') {
this.jobs.delete(jobId);
cleaned++;
}
}
return cleaned;
}
/**
* Get metrics
*/
getMetrics() {
const jobs = Array.from(this.jobs.values());
return {
total: jobs.length,
byStatus: {
queued: jobs.filter(j => j.status === 'queued').length,
running: jobs.filter(j => j.status === 'running').length,
completed: jobs.filter(j => j.status === 'completed').length,
failed: jobs.filter(j => j.status === 'failed').length,
cancelled: jobs.filter(j => j.status === 'cancelled').length,
},
averageDuration: this.calculateAverageDuration(jobs),
};
}
private calculateAverageDuration(jobs: AsyncJob[]): number {
const completed = jobs.filter(j =>
j.status === 'completed' && j.metadata.actualDuration
);
if (completed.length === 0) return 0;
const total = completed.reduce((sum, j) =>
sum + (j.metadata.actualDuration || 0), 0
);
return total / completed.length;
}
}
Create: src/mcp/async/async-tool.ts
import type { MCPTool } from '../types.js';
import type { ILogger } from '../../interfaces/logger.js';
import { JobManager, JobHandle } from './job-manager.js';
/**
* Wraps synchronous tools to support async execution
*/
export function makeToolAsync(
tool: MCPTool,
jobManager: JobManager,
logger: ILogger
): MCPTool {
return {
...tool,
name: `${tool.name}:async`,
description: `${tool.description} (Async version - returns job handle immediately)`,
// Add async-specific parameters
inputSchema: {
type: 'object',
properties: {
...((tool.inputSchema as any).properties || {}),
_async: {
type: 'object',
properties: {
mode: {
type: 'string',
enum: ['fire-and-forget', 'wait', 'poll'],
description: 'Execution mode',
default: 'poll',
},
timeout: {
type: 'number',
description: 'Timeout in ms (for wait mode)',
default: 300000,
},
webhook: {
type: 'string',
description: 'Webhook URL for completion notification',
},
},
},
},
required: (tool.inputSchema as any).required || [],
},
handler: async (input: any, context?: any) => {
const { _async, ...toolInput } = input;
const mode = _async?.mode || 'poll';
// Submit job
const jobHandle = await jobManager.submitJob(
tool.name,
toolInput,
async (input, onProgress) => {
// Execute original tool
return await tool.handler(input, context);
},
context
);
logger.info('Async job submitted', {
jobId: jobHandle.jobId,
tool: tool.name,
mode
});
// Handle different modes
if (mode === 'fire-and-forget') {
// Return job handle immediately
return {
async: true,
jobHandle,
message: 'Job submitted. Use jobs/status to check progress.',
};
} else if (mode === 'wait') {
// Wait for completion
try {
const result = await jobManager.waitForJob(
jobHandle.jobId,
_async?.timeout || 300000
);
return {
async: true,
jobHandle,
completed: true,
result,
};
} catch (error: any) {
return {
async: true,
jobHandle,
completed: false,
error: error.message,
message: 'Use jobs/status to check current state.',
};
}
} else {
// Poll mode (default)
return {
async: true,
jobHandle,
message: 'Job submitted. Poll the jobHandle.pollUrl to check status.',
};
}
},
};
}
Create: src/mcp/tools/jobs/status.ts
import type { MCPTool, ClaudeFlowToolContext } from '../../types.js';
import type { ILogger } from '../../../interfaces/logger.js';
export function createJobStatusTool(logger: ILogger): MCPTool {
return {
name: 'jobs/status',
description: 'Get status of an async job. Use for polling long-running operations.',
inputSchema: {
type: 'object',
properties: {
jobId: {
type: 'string',
description: 'Job ID returned from async tool call',
},
},
required: ['jobId'],
},
metadata: {
category: 'jobs',
tags: ['async', 'status', 'polling'],
detailLevel: 'standard',
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
if (!context?.jobManager) {
throw new Error('Job manager not available');
}
const { jobId } = input;
const job = context.jobManager.getJob(jobId);
if (!job) {
return {
success: false,
error: 'Job not found',
jobId,
};
}
return {
success: true,
job: {
id: job.id,
toolName: job.toolName,
status: job.status,
progress: job.progress,
result: job.status === 'completed' ? job.result : undefined,
error: job.status === 'failed' ? job.error : undefined,
metadata: job.metadata,
},
};
},
};
}
export const toolMetadata = {
name: 'jobs/status',
description: 'Get async job status',
category: 'jobs',
detailLevel: 'standard',
};
Create: src/mcp/tools/jobs/list.ts
import type { MCPTool, ClaudeFlowToolContext } from '../../types.js';
import type { ILogger } from '../../../interfaces/logger.js';
export function createJobListTool(logger: ILogger): MCPTool {
return {
name: 'jobs/list',
description: 'List async jobs with optional filtering',
inputSchema: {
type: 'object',
properties: {
status: {
type: 'string',
enum: ['queued', 'running', 'completed', 'failed', 'cancelled'],
description: 'Filter by status',
},
toolName: {
type: 'string',
description: 'Filter by tool name',
},
limit: {
type: 'number',
description: 'Maximum number of jobs to return',
default: 20,
},
},
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
if (!context?.jobManager) {
throw new Error('Job manager not available');
}
const jobs = context.jobManager.listJobs(input);
return {
success: true,
jobs: jobs.map(j => ({
id: j.id,
toolName: j.toolName,
status: j.status,
progress: j.progress,
createdAt: j.metadata.createdAt,
duration: j.metadata.actualDuration,
})),
total: jobs.length,
};
},
};
}
export const toolMetadata = {
name: 'jobs/list',
description: 'List async jobs',
category: 'jobs',
detailLevel: 'standard',
};
Create: src/mcp/tools/jobs/cancel.ts
import type { MCPTool, ClaudeFlowToolContext } from '../../types.js';
import type { ILogger } from '../../../interfaces/logger.js';
export function createJobCancelTool(logger: ILogger): MCPTool {
return {
name: 'jobs/cancel',
description: 'Cancel a running async job',
inputSchema: {
type: 'object',
properties: {
jobId: {
type: 'string',
description: 'Job ID to cancel',
},
},
required: ['jobId'],
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
if (!context?.jobManager) {
throw new Error('Job manager not available');
}
const { jobId } = input;
const cancelled = await context.jobManager.cancelJob(jobId);
return {
success: cancelled,
jobId,
message: cancelled
? 'Job cancelled successfully'
: 'Job not found or already completed',
};
},
};
}
export const toolMetadata = {
name: 'jobs/cancel',
description: 'Cancel async job',
category: 'jobs',
detailLevel: 'standard',
};
Update: src/mcp/server.ts
import { JobManager } from './async/job-manager.js';
import { makeToolAsync } from './async/async-tool.js';
export class MCPServer {
private jobManager: JobManager;
constructor(config: MCPConfig, eventBus: IEventBus, logger: ILogger) {
// ... existing code ...
// Initialize job manager
this.jobManager = new JobManager(
config.async?.maxJobs || 1000,
config.async?.jobTTL || 86400000
);
logger.info('Job manager initialized', {
maxJobs: config.async?.maxJobs || 1000,
});
}
/**
* Register tool with optional async support
*/
async registerTool(tool: MCPTool, enableAsync: boolean = true): Promise<void> {
// Register synchronous version
await this.toolRegistry.registerTool(tool);
// Also register async version if enabled
if (enableAsync && this.isLongRunningTool(tool)) {
const asyncTool = makeToolAsync(tool, this.jobManager, this.logger);
await this.toolRegistry.registerTool(asyncTool);
this.logger.info('Registered async version of tool', {
tool: tool.name,
asyncName: asyncTool.name
});
}
}
/**
* Determine if tool should have async version
*/
private isLongRunningTool(tool: MCPTool): boolean {
// Tools that typically take > 5 seconds should be async
const longRunningCategories = [
'agents/spawn',
'agents/spawn-parallel',
'tasks/create',
'workflow/execute',
'data/filter',
'swarm/',
];
return longRunningCategories.some(prefix => tool.name.startsWith(prefix));
}
/**
* Add job manager to tool context
*/
private get toolContext(): ClaudeFlowToolContext {
return {
orchestrator: this.orchestrator,
swarmCoordinator: this.swarmCoordinator,
jobManager: this.jobManager, // NEW
sessionId: this.currentSessionId,
};
}
}
Update: src/config/default-config.ts
export interface MCPConfig {
// ... existing config ...
async: {
enabled: boolean;
maxJobs: number;
jobTTL: number; // milliseconds
defaultTimeout: number; // milliseconds
enableWebhooks: boolean;
};
}
export const defaultConfig: MCPConfig = {
// ... existing config ...
async: {
enabled: true,
maxJobs: 1000,
jobTTL: 86400000, // 24 hours
defaultTimeout: 300000, // 5 minutes
enableWebhooks: false,
},
};
The MCP Registry provides:
Create: src/mcp/registry/client.ts
/**
* MCP Registry Client
* Integrates with official MCP Registry for server discovery
*/
export interface ServerMetadata {
name: string;
version: string;
description: string;
author: string;
homepage?: string;
repository?: string;
capabilities: {
tools: boolean;
resources: boolean;
prompts: boolean;
async: boolean;
streaming: boolean;
};
categories: string[];
tags: string[];
transport: Array<'stdio' | 'http' | 'websocket'>;
healthCheck?: {
endpoint: string;
interval: number; // seconds
};
security: {
authRequired: boolean;
authMethods: Array<'token' | 'basic' | 'oauth'>;
piiHandling: 'none' | 'tokenized' | 'encrypted';
};
}
export class RegistryClient {
private baseUrl: string = 'https://registry.mcp.anthropic.com/api/v1';
constructor(private apiKey?: string) {}
/**
* Publish server to registry
*/
async publishServer(metadata: ServerMetadata): Promise<{
success: boolean;
serverId: string;
url: string;
}> {
const response = await fetch(`${this.baseUrl}/servers`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiKey}`,
},
body: JSON.stringify(metadata),
});
if (!response.ok) {
throw new Error(`Failed to publish server: ${response.statusText}`);
}
return await response.json();
}
/**
* Update server metadata
*/
async updateServer(
serverId: string,
metadata: Partial<ServerMetadata>
): Promise<void> {
const response = await fetch(`${this.baseUrl}/servers/${serverId}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiKey}`,
},
body: JSON.stringify(metadata),
});
if (!response.ok) {
throw new Error(`Failed to update server: ${response.statusText}`);
}
}
/**
* Report health status
*/
async reportHealth(
serverId: string,
health: {
status: 'healthy' | 'degraded' | 'unhealthy';
latency?: number;
metrics?: Record<string, number>;
}
): Promise<void> {
await fetch(`${this.baseUrl}/servers/${serverId}/health`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiKey}`,
},
body: JSON.stringify(health),
});
}
/**
* Search registry for servers
*/
async searchServers(query: {
category?: string;
tags?: string[];
capabilities?: string[];
limit?: number;
}): Promise<ServerMetadata[]> {
const params = new URLSearchParams();
if (query.category) params.set('category', query.category);
if (query.tags) params.set('tags', query.tags.join(','));
if (query.capabilities) params.set('capabilities', query.capabilities.join(','));
if (query.limit) params.set('limit', query.limit.toString());
const response = await fetch(`${this.baseUrl}/servers?${params}`);
if (!response.ok) {
throw new Error(`Failed to search servers: ${response.statusText}`);
}
return await response.json();
}
}
Create: scripts/publish-to-registry.ts
#!/usr/bin/env node
import { RegistryClient, ServerMetadata } from '../src/mcp/registry/client.js';
import { version } from '../package.json';
async function main() {
const apiKey = process.env.MCP_REGISTRY_API_KEY;
if (!apiKey) {
console.error('❌ MCP_REGISTRY_API_KEY not set');
process.exit(1);
}
const client = new RegistryClient(apiKey);
const metadata: ServerMetadata = {
name: 'claude-flow',
version,
description: 'Advanced MCP server with swarm coordination, async operations, and neural capabilities',
author: 'ruvnet',
homepage: 'https://github.com/ruvnet/claude-flow',
repository: 'https://github.com/ruvnet/claude-flow',
capabilities: {
tools: true,
resources: true,
prompts: true,
async: true,
streaming: true,
},
categories: [
'orchestration',
'swarm-coordination',
'task-management',
'memory-management',
],
tags: [
'async',
'swarm',
'neural',
'coordination',
'agentdb',
'reasoningbank',
],
transport: ['stdio', 'http'],
healthCheck: {
endpoint: '/health',
interval: 60,
},
security: {
authRequired: true,
authMethods: ['token', 'oauth'],
piiHandling: 'tokenized',
},
};
console.log('📤 Publishing to MCP Registry...');
const result = await client.publishServer(metadata);
console.log('✅ Published successfully!');
console.log(` Server ID: ${result.serverId}`);
console.log(` URL: ${result.url}`);
}
main().catch(console.error);
Create: src/mcp/endpoints/health.ts
export class HealthCheckHandler {
constructor(
private server: MCPServer,
private jobManager: JobManager,
private toolRegistry: ToolRegistry
) {}
async getHealth(): Promise<{
status: 'healthy' | 'degraded' | 'unhealthy';
uptime: number;
metrics: {
activeJobs: number;
totalTools: number;
avgResponseTime: number;
errorRate: number;
};
}> {
const jobMetrics = this.jobManager.getMetrics();
const toolMetrics = await this.toolRegistry.getMetrics();
// Calculate health status
const errorRate = toolMetrics.failedInvocations / toolMetrics.totalInvocations;
const status = errorRate > 0.1 ? 'unhealthy' : errorRate > 0.05 ? 'degraded' : 'healthy';
return {
status,
uptime: process.uptime(),
metrics: {
activeJobs: jobMetrics.byStatus.running,
totalTools: toolMetrics.totalTools,
avgResponseTime: toolMetrics.averageExecutionTime,
errorRate,
},
};
}
}
Update: .github/workflows/publish.yml
name: Publish to MCP Registry
on:
release:
types: [published]
push:
branches: [main]
jobs:
publish-registry:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Run tests
run: npm test
- name: Publish to MCP Registry
env:
MCP_REGISTRY_API_KEY: ${{ secrets.MCP_REGISTRY_API_KEY }}
run: npm run registry:publish
- name: Update health check
env:
MCP_REGISTRY_API_KEY: ${{ secrets.MCP_REGISTRY_API_KEY }}
run: npm run registry:health
This is covered in the original plan (Phase 1: Progressive Disclosure, Phase 4: Data Processing).
Status: Implementation details provided in main plan
Create: tests/mcp-spec-2025-compliance.test.ts
import { describe, it, expect, beforeAll } from '@jest/globals';
describe('MCP Spec 2025 Compliance', () => {
describe('Async Operations', () => {
it('should return job handle immediately for long-running tasks', async () => {
const result = await mcpClient.callTool('agents/spawn:async', {
type: 'researcher',
name: 'Test Agent',
_async: { mode: 'poll' },
});
expect(result).toHaveProperty('jobHandle');
expect(result.jobHandle).toHaveProperty('jobId');
expect(result.jobHandle).toHaveProperty('pollUrl');
});
it('should allow polling for job status', async () => {
const { jobHandle } = await mcpClient.callTool('agents/spawn:async', {
type: 'researcher',
name: 'Test Agent',
_async: { mode: 'poll' },
});
const status = await mcpClient.callTool('jobs/status', {
jobId: jobHandle.jobId,
});
expect(status.job.status).toMatch(/queued|running|completed/);
});
it('should support wait mode with timeout', async () => {
const result = await mcpClient.callTool('agents/spawn:async', {
type: 'researcher',
name: 'Test Agent',
_async: { mode: 'wait', timeout: 10000 },
});
expect(result).toHaveProperty('completed');
if (result.completed) {
expect(result).toHaveProperty('result');
}
});
it('should support job cancellation', async () => {
const { jobHandle } = await mcpClient.callTool('workflow/execute:async', {
workflowId: 'long-running-workflow',
_async: { mode: 'poll' },
});
const cancelled = await mcpClient.callTool('jobs/cancel', {
jobId: jobHandle.jobId,
});
expect(cancelled.success).toBe(true);
const status = await mcpClient.callTool('jobs/status', {
jobId: jobHandle.jobId,
});
expect(status.job.status).toBe('cancelled');
});
});
describe('Registry Integration', () => {
it('should be discoverable in MCP Registry', async () => {
const servers = await registryClient.searchServers({
tags: ['claude-flow'],
});
expect(servers).toContainEqual(
expect.objectContaining({
name: 'claude-flow',
capabilities: expect.objectContaining({
async: true,
}),
})
);
});
it('should report health status', async () => {
const health = await fetch('http://localhost:3000/health');
const data = await health.json();
expect(data.status).toMatch(/healthy|degraded|unhealthy/);
expect(data.metrics).toHaveProperty('activeJobs');
});
});
describe('Code Execution Pattern', () => {
it('should process data in execution environment', async () => {
// Create large dataset (10,000 rows)
const largeDataset = Array.from({ length: 10000 }, (_, i) => ({
id: i,
value: Math.random() * 1000,
category: ['A', 'B', 'C'][i % 3],
}));
// Store in memory
await memoryStore.store('test-dataset', JSON.stringify(largeDataset));
// Filter in execution environment
const result = await mcpClient.callTool('data/filter', {
dataSource: 'memory',
source: 'test-dataset',
filters: [
{ field: 'value', operator: 'gt', value: 500 },
{ field: 'category', operator: 'eq', value: 'A' },
],
returnFormat: 'summary',
});
// Result should be small (summary only)
const resultSize = JSON.stringify(result).length;
expect(resultSize).toBeLessThan(1000); // < 1KB
// Original dataset was ~500KB
const originalSize = JSON.stringify(largeDataset).length;
expect(originalSize).toBeGreaterThan(500000);
// Verify token savings
const tokenReduction = ((originalSize - resultSize) / originalSize) * 100;
expect(tokenReduction).toBeGreaterThan(98);
});
});
});
# Install dependencies
npm install
# Run async operation tests
npm run test:async
# Run registry integration tests
npm run test:registry
# Run full compliance suite
npm run test:compliance
# Publish to registry
npm run registry:publish
# Start server with async support
npm run start:async
# Monitor job queue
npm run jobs:monitor
[MCP-2025-URGENT] prefixWould you like me to start implementing any specific phase?