Skip to main content
Glama

MCP Utils

by haakco

@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-utils

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 status
Size & 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• item2

DateTime 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'); // 216000000

Caching 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 TTL
LRU 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 size
Combined 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 items
Function 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 CallToolResult

Resource 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

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes with tests
  4. Ensure all tests pass and linting is clean
  5. Submit a pull request

Built with TypeScript, tested with Jest, and designed for production MCP servers.

Related MCP Servers

  • A
    security
    A
    license
    A
    quality
    A TypeScript-based template for building Model Context Protocol servers, featuring fast testing, automated version management, and a clean structure for MCP tool implementations.
    Last updated -
    1
    1
    2
    TypeScript
    MIT License
  • A
    security
    A
    license
    A
    quality
    A Model Context Protocol server that provides tools for code modification and generation via Large Language Models, allowing users to create, modify, rewrite, and delete files using structured XML instructions.
    Last updated -
    12
    Python
    MIT License
    • Linux
    • Apple
  • -
    security
    -
    license
    -
    quality
    A simple implementation of a Model Context Protocol server that demonstrates core functionality including mathematical tools (add, subtract) and personalized greeting resources.
    Last updated -
    3
    Python
    GPL 3.0
  • -
    security
    F
    license
    -
    quality
    A utility module for creating Model Context Protocol servers declaratively, allowing developers to easily define tools, prompts, and resources with a simplified syntax.
    Last updated -
    64
    JavaScript

View all related MCP servers

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/haakco/mcp-utils'

If you have feedback or need assistance with the MCP directory API, please join our Discord server