Enables integration with Express.js web applications, providing examples for implementing rate-limited endpoints, cached responses, and request handling with the MCP utilities.
Supports testing with Jest, including test structure, coverage reporting, and pattern-based test filtering for MCP server components.
Includes Kubernetes-compatible storage size formatting utilities for displaying resource metrics in standardized formats (e.g., Mi, Gi).
Available as an NPM package with installation instructions and dependency management for integrating MCP utilities into projects.
Built with TypeScript support, providing type-safe interfaces, error checking, and enhanced development experience for MCP server implementations.
Integrates with Zod schema validation for type-safe argument validation, resource operations, and structured data handling in MCP tools.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MCP Utilsformat this JSON response with proper table formatting"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@haakco/mcp-utils
Comprehensive shared utilities library for MCP (Model Context Protocol) servers
Eliminates code duplication and provides standardized, production-ready utilities for building robust MCP servers.
Installation
npm install @haakco/mcp-utilsRelated MCP server: MCP TypeScript SDK
Quick Start
import {
BaseToolHandler,
ResponseBuilder,
createTextResponse,
formatSuccess,
createLogger
} from '@haakco/mcp-utils';
class MyMCPServer extends BaseToolHandler {
private logger = createLogger('my-server');
async handleTool(args: unknown) {
try {
const result = await this.performOperation(args);
this.logger.info('Operation completed successfully');
return createTextResponse(formatSuccess(result));
} catch (error) {
this.logger.error('Operation failed:', error);
return createErrorResponse(error);
}
}
}๐ Core Features
๐๏ธ MCP Architecture Components
BaseToolHandler - Standardized tool execution patterns
ResponseBuilder - Consistent MCP response formatting
InstanceManager - Multi-instance server support
ToolRegistry - Tool registration and management
๐จ Formatting & Presentation
Message Formatters - โ โ โ ๏ธ โน๏ธ status indicators
Size Formatters - Bytes, storage units (KB, MB, GB, Ki, Mi, Gi)
Table Formatters - Structured data presentation
JSON/Text Utilities - Safe serialization and truncation
๐ DateTime Operations
Duration Formatting - Human-readable time spans
Age Calculation - "2 hours ago", "3 days old"
Relative Time - "in 5 minutes", "1 week ago"
Duration Parsing - "1h30m" โ milliseconds
๐ง Advanced Caching
SimpleCache - TTL-based caching
LRUCache - Least Recently Used eviction
TTLCache - Combined TTL + LRU strategies
DebouncedCache - Batched operation caching
Memoization - Function result caching
๐ฆ Rate Limiting
Token Bucket - Burst capacity with refill
Sliding Window - Rolling time-based limits
Fixed Window - Period-based rate limiting
Leaky Bucket - Smooth rate control
Multi-Tier - Multiple simultaneous limits
Keyed Limiters - Per-user/per-resource limits
๐ WebSocket Utilities
ReconnectingWebSocket - Auto-reconnection with backoff
Message Router - Type-based message handling
RPC Client - Request/response over WebSocket
Connection Pool - Managed connection lifecycle
๐ Logging & Monitoring
Structured Logging - Context-aware log entries
Performance Timing - Operation duration tracking
Environment-based - Debug/production configurations
Multiple Outputs - Console, silent, custom loggers
๐ API Reference
Core MCP Utilities
Response Creation
import { createTextResponse, createErrorResponse, createSuccessResponse } from '@haakco/mcp-utils';
// Basic responses
createTextResponse('Operation completed');
createErrorResponse(new Error('Failed to connect'));
createSuccessResponse('User created successfully');
// Multi-part responses
createMultipartResponse(['Header', 'Content', 'Footer']);
// Progress indicators
createProgressResponse(75, 100, 'Processing data');Argument Validation
import { validateToolArgs, validateRequiredArgs, extractPagination } from '@haakco/mcp-utils';
// Schema validation
const args = validateToolArgs(input, (data) => userSchema.parse(data), 'create_user');
// Required field validation
const validated = validateRequiredArgs(input, ['name', 'email'], 'User creation');
// Pagination extraction
const { page, perPage, offset, limit } = extractPagination(args);Formatting Utilities
Message Formatting
import { formatSuccess, formatError, formatWarning, formatInfo } from '@haakco/mcp-utils';
formatSuccess('Operation completed'); // โ
Operation completed
formatError('Connection failed'); // โ Error: Connection failed
formatWarning('Low disk space'); // โ ๏ธ Warning: Low disk space
formatInfo('System status'); // โน๏ธ System statusSize & Number Formatting
import { formatBytes, formatStorageSize, formatPercentage, formatCPU } from '@haakco/mcp-utils';
formatBytes(1048576); // 1 MB
formatStorageSize(1048576); // 1Mi (Kubernetes format)
formatPercentage(75, 100); // 75.00%
formatCPU(0.75); // 75.00%Table & List Formatting
import { formatTable, formatSimpleTable, formatList, formatBulletList } from '@haakco/mcp-utils';
// Object array to table
const data = [
{ name: 'John', age: 30, city: 'NYC' },
{ name: 'Jane', age: 25, city: 'LA' }
];
formatTable(data);
// name | age | city
// -----|-----|-----
// John | 30 | NYC
// Jane | 25 | LA
// Key-value table
formatSimpleTable({ name: 'Server1', status: 'Running', cpu: '45%' });
// name : Server1
// status : Running
// cpu : 45%
// Lists
formatList(['item1', 'item2', 'item3'], ' | '); // item1 | item2 | item3
formatBulletList(['item1', 'item2']); // โข item1\nโข item2DateTime Utilities
Duration Formatting
import { formatDuration, formatDurationFromSeconds, formatAge } from '@haakco/mcp-utils';
formatDuration(90061000); // 1d 1h 1m 1s
formatDurationFromSeconds(3661); // 1h 1m 1s
formatAge(Date.now() - 3600000); // 1h (age from timestamp)Relative Time
import { formatRelativeTime, parseDuration } from '@haakco/mcp-utils';
formatRelativeTime(new Date(Date.now() - 3600000)); // 1 hour ago
formatRelativeTime(new Date(Date.now() + 1800000)); // in 30 minutes
parseDuration('1h30m'); // 5400000 (milliseconds)
parseDuration('2d12h'); // 216000000Caching System
Simple TTL Cache
import { SimpleCache } from '@haakco/mcp-utils';
const cache = new SimpleCache<string>(60000); // 1 minute TTL
cache.set('key1', 'value1');
cache.get('key1'); // 'value1'
cache.has('key1'); // true
// Custom TTL for specific items
cache.set('key2', 'value2', 30000); // 30 second TTLLRU Cache
import { LRUCache } from '@haakco/mcp-utils';
const cache = new LRUCache<string>(100); // Max 100 items
cache.set('key1', 'value1');
cache.get('key1'); // Marks as recently used
cache.size(); // Current cache sizeCombined TTL + LRU Cache
import { TTLCache } from '@haakco/mcp-utils';
const cache = new TTLCache<string>({
ttl: 300000, // 5 minutes
maxSize: 1000, // Max 1000 items
onEvict: (key, value) => console.log(`Evicted ${key}`)
});
cache.set('key1', 'value1');
cache.cleanup(); // Manual cleanup of expired itemsFunction Memoization
import { memoize } from '@haakco/mcp-utils';
const expensiveOperation = async (id: string) => {
// Expensive API call or computation
return await fetch(`/api/data/${id}`).then(r => r.json());
};
const memoized = memoize(expensiveOperation, {
ttl: 300000, // 5 minute cache
keyGenerator: (id) => `data:${id}`
});
// First call - executes function
await memoized('user1');
// Second call - returns cached result
await memoized('user1'); Rate Limiting
Token Bucket Rate Limiter
import { TokenBucketRateLimiter } from '@haakco/mcp-utils';
const limiter = new TokenBucketRateLimiter(
10, // Bucket capacity (max burst)
2 // Refill rate (tokens per second)
);
// Try to acquire tokens
if (await limiter.acquire(1)) {
// Request allowed
await processRequest();
}
// Wait until tokens available
await limiter.acquireOrWait(1);Sliding Window Rate Limiter
import { SlidingWindowRateLimiter } from '@haakco/mcp-utils';
const limiter = new SlidingWindowRateLimiter(
60000, // 1 minute window
100 // Max 100 requests per window
);
if (await limiter.acquire()) {
// Request allowed
} else {
const waitTime = limiter.getTimeUntilNextRequest();
console.log(`Rate limited. Wait ${waitTime}ms`);
}Multi-Tier Rate Limiting
import { MultiTierRateLimiter } from '@haakco/mcp-utils';
const limiter = new MultiTierRateLimiter([
{ windowMs: 1000, maxRequests: 10, name: 'per-second' },
{ windowMs: 60000, maxRequests: 100, name: 'per-minute' },
{ windowMs: 3600000, maxRequests: 1000, name: 'per-hour' }
]);
const result = await limiter.acquire();
if (!result.allowed) {
console.log(`Limited by: ${result.limitedBy}`);
}Rate-Limited Functions
import { rateLimitFunction, debounce, throttle } from '@haakco/mcp-utils';
// Rate-limited function wrapper
const limitedAPI = rateLimitFunction(apiCall, {
requestsPerSecond: 5,
burst: 10
});
// Debounced function (delays execution)
const debouncedSave = debounce(saveData, 1000);
// Throttled function (limits execution frequency)
const throttledUpdate = throttle(updateUI, 100);WebSocket Utilities
Reconnecting WebSocket
import { ReconnectingWebSocket } from '@haakco/mcp-utils';
const ws = new ReconnectingWebSocket({
url: 'wss://api.example.com/ws',
maxReconnectAttempts: 5,
reconnectInterval: 5000,
reconnectBackoff: 1.5,
pingInterval: 30000
});
ws.on('open', () => console.log('Connected'));
ws.on('message', (data) => console.log('Received:', data));
ws.on('reconnecting', (attempt) => console.log(`Reconnecting... attempt ${attempt}`));
ws.send({ type: 'subscribe', channel: 'updates' });Message Router
import { WebSocketRouter } from '@haakco/mcp-utils';
const router = new WebSocketRouter<{ type: string; payload?: any }>();
router.on('user.created', async (message) => {
console.log('New user:', message.payload);
});
router.on('notification', async (message) => {
await showNotification(message.payload);
});
router.setDefaultHandler((message) => {
console.log('Unhandled message:', message);
});
// Handle incoming messages
ws.on('message', (data) => router.handle(data));WebSocket RPC
import { WebSocketRPC } from '@haakco/mcp-utils';
const rpc = new WebSocketRPC(ws, {
timeout: 30000,
idGenerator: () => `req-${Date.now()}`
});
// Make RPC calls
const user = await rpc.call('getUser', { id: '123' });
const result = await rpc.call('updateProfile', { name: 'New Name' });Logging System
Basic Logger
import { createLogger, createStructuredLogger } from '@haakco/mcp-utils';
const logger = createLogger('my-module');
logger.info('Application started');
logger.warn('Low memory warning');
logger.error('Database connection failed');
logger.debug('Debug information');Structured Logger with Context
const logger = createStructuredLogger('api', 'app', {
service: 'user-service',
version: '1.2.3'
});
logger.info('User login successful');
// Output: INFO: User login successful [{"service":"user-service","version":"1.2.3"}]
// Add context for child logger
const requestLogger = logger.child({ requestId: 'req-123', userId: 'user-456' });
requestLogger.info('Processing request');Performance Logger
import { createPerformanceLogger } from '@haakco/mcp-utils';
const perfLogger = createPerformanceLogger('performance');
// Manual timing
perfLogger.start('database-query');
await queryDatabase();
perfLogger.end('database-query', { query: 'SELECT * FROM users' });
// Automatic timing
const result = await perfLogger.measure(
'api-call',
() => fetch('/api/data').then(r => r.json()),
{ endpoint: '/api/data' }
);Environment-based Logger
import { createLoggerFromEnv, LogLevel, createLevelLogger } from '@haakco/mcp-utils';
// Automatically configures based on DEBUG and LOG_LEVEL env vars
const logger = createLoggerFromEnv('my-app');
// Or explicit level configuration
const logger = createLevelLogger('my-app', LogLevel.INFO);๐๏ธ Advanced Usage
Custom Tool Handler
import { BaseToolHandler, createTextResponse, formatSuccess } from '@haakco/mcp-utils';
import { z } from 'zod';
class CustomToolHandler extends BaseToolHandler {
constructor() {
super('my-custom-server');
}
getTools() {
return [
this.createTool(
'process_data',
'Process data with validation and formatting',
z.object({
data: z.array(z.string()),
format: z.enum(['json', 'table', 'list']).default('json')
}),
async (args) => {
const processed = await this.processData(args.data);
switch (args.format) {
case 'table':
return createTextResponse(formatTable(processed));
case 'list':
return createTextResponse(formatBulletList(processed.map(String)));
default:
return createTextResponse(formatSuccess(JSON.stringify(processed)));
}
}
)
];
}
private async processData(data: string[]): Promise<any[]> {
// Your custom processing logic
return data.map(item => ({ original: item, processed: item.toUpperCase() }));
}
}Batch Response Builder
import { BatchResponseBuilder } from '@haakco/mcp-utils';
const response = new BatchResponseBuilder()
.addSuccess('Connection established')
.addInfo('Processing 150 items')
.addSeparator()
.add('Results:')
.addSuccess('Created 145 items')
.addWarning('Skipped 3 duplicates')
.addError('Failed to create 2 items')
.addEmptyLine()
.addInfo('Operation completed in 2.3 seconds')
.build();
return response; // Returns proper CallToolResultResource Operation Mixin
import { ResourceOperationMixin } from '@haakco/mcp-utils';
import { z } from 'zod';
interface User {
id: string;
name: string;
email: string;
}
class UserTools extends ResourceOperationMixin<User> {
constructor(private userClient: UserClient) {
super('user-management');
}
getTools() {
return this.createResourceTools({
resourceName: 'User',
client: this.userClient,
formatItem: (user) => `${user.name} <${user.email}>`,
validateCreate: z.object({
name: z.string().min(1),
email: z.string().email()
}),
validateUpdate: z.object({
name: z.string().min(1).optional(),
email: z.string().email().optional()
})
});
}
}๐ฆ Integration Examples
Express.js Integration
import express from 'express';
import { createLogger, rateLimitFunction, SimpleCache } from '@haakco/mcp-utils';
const app = express();
const logger = createLogger('api-server');
const cache = new SimpleCache<any>(300000); // 5 minute cache
// Rate-limited endpoint
const rateLimitedHandler = rateLimitFunction(
async (req, res) => {
const data = await fetchData(req.params.id);
res.json(data);
},
{ requestsPerSecond: 10, burst: 20 }
);
app.get('/api/data/:id', async (req, res) => {
const cached = cache.get(req.params.id);
if (cached) {
logger.info('Cache hit', { id: req.params.id });
return res.json(cached);
}
await rateLimitedHandler(req, res);
});WebSocket Server Integration
import WebSocket from 'ws';
import { WebSocketRouter, createLogger, TokenBucketRateLimiter } from '@haakco/mcp-utils';
const logger = createLogger('ws-server');
const rateLimiter = new TokenBucketRateLimiter(10, 1); // 10 burst, 1/sec refill
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
const router = new WebSocketRouter();
router.on('message', async (data) => {
if (await rateLimiter.acquire()) {
await handleMessage(data);
} else {
ws.send(JSON.stringify({ error: 'Rate limit exceeded' }));
}
});
ws.on('message', (data) => {
try {
const message = JSON.parse(data.toString());
router.handle(message);
} catch (error) {
logger.error('Invalid message format', error);
}
});
});๐งช Testing
The library includes comprehensive test coverage (85/85 tests passing):
# Run all tests
npm test
# Run tests with coverage
npm run test:coverage
# Run specific test suites
npm test -- --testNamePattern="Cache"
npm test -- --testNamePattern="Rate.*Limiter"Test Structure
tests/
โโโ base-handler.test.ts # Core MCP functionality
โโโ cache.test.ts # All caching strategies
โโโ datetime.test.ts # DateTime utilities
โโโ formatters.test.ts # Formatting functions
โโโ response-builder.test.ts # Response building
โโโ task-helpers.test.ts # Task execution
โโโ validators.test.ts # Validation utilities๐ Development
# Install dependencies
npm install
# Run tests in watch mode
npm run test:watch
# Build the library
npm run build
# Lint and format code
npm run lint
npm run lint:fix
# Type checking
npm run type-check๐ License
MIT License - see LICENSE file for details.
๐ค Contributing
Fork the repository
Create a feature branch
Make your changes with tests
Ensure all tests pass and linting is clean
Submit a pull request
Built with TypeScript, tested with Jest, and designed for production MCP servers.
This server cannot be installed
Resources
Looking for Admin?
Admins can modify the Dockerfile, update the server description, and track usage metrics. If you are the server author, to access the admin panel.