@fractalizer/mcp-infrastructure
v0.2.2
Published
Reusable infrastructure layer: HTTP, cache, logging, async utilities
Maintainers
Readme
@fractalizer/mcp-infrastructure
Reusable infrastructure layer: HTTP, cache, logging, async utilities
🎯 Purpose
Principle: Infrastructure layer does NOT know about domain (Yandex.Tracker, MCP)
Reusability: All components can be used in other projects without modifications
Architecture rule: Infrastructure does NOT import domain-specific code
📦 Installation
npm install @fractalizer/mcp-infrastructureDependencies: 0 framework dependencies (only external libs: axios, pino, rotating-file-stream)
📁 Structure
src/
├── http/ # HTTP client + retry + error mapping
│ ├── client/
│ │ └── http-client.ts # Axios wrapper
│ ├── retry/
│ │ ├── retry-handler.ts
│ │ └── exponential-backoff.strategy.ts
│ └── error/
│ └── error-mapper.ts # AxiosError → ApiError
├── cache/ # Caching (Strategy Pattern)
│ ├── cache-manager.interface.ts
│ ├── entity-cache-key.ts # Cache key generator for entities
│ └── no-op-cache.ts # Null Object
├── async/ # Parallel execution
│ └── parallel-executor.ts # Throttling for batch requests
├── logging/ # Production logging (Pino)
│ └── README.md # Detailed docs
├── types.ts # Type definitions
└── index.ts # Public exports🔧 Components
HTTP Layer
AxiosHttpClient (alias HttpClient) — Axios wrapper with built-in retry and error mapping
Key features:
- ✅ Automatic retry via
RetryHandler - ✅
AxiosError→ApiErrormapping - ✅ Request/response logging via interceptors
- ✅ Type-safe generic methods:
get<T>(),post<T>(),patch<T>(),delete<T>()
Implementation: src/http/client/axios-http-client.ts
Interface:
interface IHttpClient {
get<T>(path: string, params?: QueryParams): Promise<T>;
post<T>(path: string, data?: unknown): Promise<T>;
patch<T>(path: string, data?: unknown): Promise<T>;
delete<T>(path: string): Promise<T>;
}Caching
CacheManager — interface (Strategy Pattern)
Implementations:
NoOpCache— Null Object (cache disabled by default)EntityCacheKey— generates cache keys for entities (e.g.,issue:PROJ-123)
Details: src/cache/
Interface:
interface CacheManager {
get<T>(key: string): Promise<T | null>;
set<T>(key: string, value: T, ttl?: number): Promise<void>;
delete(key: string): Promise<void>;
clear(): Promise<void>;
}Parallel Execution
ParallelExecutor — executes batch operations with concurrency control (using p-limit)
Configuration:
maxBatchSize(business limit, default: 200)maxConcurrentRequests(technical limit, default: 5)
Features:
- ✅ Validates batch size before execution
- ✅ Uses
p-limitfor concurrency control - ✅ Logs metrics (success/error counts, duration)
- ✅ Returns typed
BatchResult<TKey, TValue>
Implementation: src/async/parallel-executor.ts
Method signature:
async executeParallel<TKey, TValue>(
operations: Array<{ key: TKey; fn: () => Promise<TValue> }>,
operationName?: string
): Promise<BatchResult<TKey, TValue>>Logging
Pino logger — production-ready structured logging with rotation
Key features:
- ✅ Structured JSON logs
- ✅ Automatic rotation (daily + size-based →
.gzarchives) - ✅ Dual output (errors → stderr + file, info/debug → file only)
- ✅ Child loggers for request tracing
Configuration ENV vars:
LOGS_DIR,LOG_LEVEL,PRETTY_LOGS,LOG_MAX_SIZE,LOG_MAX_FILES
Full documentation: src/logging/README.md
Function signature:
function createLogger(config: LoggerConfig): Logger🔄 Migration from v1.x
BREAKING: Configuration removed (v2.0.0)
ServerConfig, loadConfig(), and domain-specific constants have been removed from infrastructure.
Reason: Infrastructure layer must be domain-agnostic.
Migration:
// Before (v1.x):
import { ServerConfig, loadConfig } from '@fractalizer/mcp-infrastructure';
// After (v2.0.0):
// For Yandex Tracker server:
import { ServerConfig, loadConfig } from '@fractalizer/mcp-server-yandex-tracker/config';
// For custom servers:
// Implement your own config loader based on your domain requirements🚨 Critical Rules
1. Infrastructure does NOT know about domain
// ❌ FORBIDDEN (domain import)
import { Issue } from 'your-domain/entities/issue.js';
// ✅ CORRECT (generic types)
class HttpClient {
async get<T>(url: string): Promise<T> { ... }
}2. Use config for all parameters
// ❌ FORBIDDEN (hardcoded values)
const timeout = 30000;
// ✅ CORRECT (from config)
const timeout = config.requestTimeout;3. Retry is built into HttpClient
// ✅ Retry works automatically
const client = new HttpClient(config, logger, retryHandler);
await client.get('/api/endpoint'); // Auto-retry on error4. All errors are mapped to ApiError
// ✅ HttpClient automatically maps AxiosError → ApiError
try {
await client.get('/api/not-found');
} catch (error) {
// error: ApiError (not AxiosError)
console.error(error.statusCode, error.message);
}📖 API Reference
Exports
// HTTP
export { HttpClient } from './http/client/http-client.js';
export { RetryHandler } from './http/retry/retry-handler.js';
export { ExponentialBackoffStrategy } from './http/retry/exponential-backoff.strategy.js';
export { ErrorMapper } from './http/error/error-mapper.js';
// Cache
export type { CacheManager } from './cache/cache-manager.interface.js';
export { NoOpCache } from './cache/no-op-cache.js';
export { EntityCacheKey, EntityType } from './cache/entity-cache-key.js';
// Async
export { ParallelExecutor } from './async/parallel-executor.js';
// Logging
export { createLogger } from './logging/logger.js';
// Types
export type { ApiError, BatchResult, LogLevel } from './types.js';🧪 Testing
Run tests:
cd packages/framework/infrastructure
npm run testWith coverage:
npm run test:coverageWatch mode:
npm run test:watch🤝 Contributing
See ../../.github/CONTRIBUTING.md
Architecture rules: ../../CLAUDE.md
📄 License
MIT License
🔗 Links
- Monorepo root: ../../README.md
- Architecture: ../../ARCHITECTURE.md
