mcp-proxy
by dyy-fq
README.md
# MCP Proxy Service
An enterprise-grade MCP (Model Context Protocol) proxy that bridges LLM clients with existing RESTful microservices. Configure any REST API as an MCP tool — no changes to your microservices required.
## Table of Contents
- [Features](#features)
- [Prerequisites](#prerequisites)
- [Quick Start](#quick-start)
- [Environment Setup](#environment-setup)
- [Configuration](#configuration)
- [CLI Usage](#cli-usage)
- [Transport Modes](#transport-modes)
- [Monitoring](#monitoring)
- [Security](#security)
- [Testing](#testing)
- [Project Structure](#project-structure)
- [Troubleshooting](#troubleshooting)
- [Scripts Reference](#scripts-reference)
- [Technology Stack](#technology-stack)
- [Related Documentation](#related-documentation)
- [Contributing](#contributing)
- [License](#license)
## Features
- **Protocol Translation** — Automatically converts MCP tool calls into REST API requests
- **Dynamic Tool Registration** — Define REST endpoints as MCP tools via YAML configuration
- **OpenAPI Import** — Generate tool definitions from OpenAPI/Swagger specifications
- **Transport Agnostic** — Supports stdio (for Claude Desktop, CLI) and HTTP (Streamable HTTP with SSE)
- **Circuit Breaker** — Fault tolerance with automatic service recovery (opossum)
- **Rate Limiting** — Fixed window, sliding window, and token bucket strategies
- **Access Control** — Role-based permissions at service and tool level
- **Authentication** — API key, bearer token, basic auth, and OAuth2 client credentials
- **Request Validation** — Type checking, pattern matching, format validation (email, URL, UUID)
- **Request Cancellation** — Abort in-flight requests with signal propagation to upstream services
- **Response Transformation** — JSON, text, and XML response format conversion
- **Monitoring** — Prometheus metrics, health checks, readiness probes
- **Retry with Jittered Backoff** — Prevents thundering herd on failure recovery
- **Graceful Shutdown** — Clean connection draining on SIGINT/SIGTERM
## Prerequisites
- **Node.js** >= 18.0.0
- **npm** >= 8.0.0
- **Docker** (optional, for containerized deployment)
- **Redis** (optional, for distributed rate limiting across multiple instances)
## Quick Start
```bash
# Install dependencies
npm install
# Copy environment file
cp .env.example .env
# Build
npm run build
# Start with stdio transport (default, for Claude Desktop)
npm run start:stdio
# Start with HTTP transport
npm run start:http
```
## Environment Setup
### Development
```bash
# .env
NODE_ENV=development
LOG_LEVEL=debug
# Server
MCP_SERVER_PORT=3000
HEALTH_CHECK_PORT=8080
# Redis (optional — in-memory rate limiting used if not configured)
REDIS_HOST=localhost
REDIS_PORT=6379
# Monitoring
METRICS_ENABLED=true
```
Run in development mode with hot reload:
```bash
npm run dev
```
### Production
```bash
# .env
NODE_ENV=production
LOG_LEVEL=info
# Server
MCP_SERVER_PORT=3000
HEALTH_CHECK_PORT=8080
# Redis (required for distributed rate limiting)
REDIS_HOST=redis.internal
REDIS_PORT=6379
REDIS_PASSWORD=your-secure-password
# MCP server authentication (protect the /mcp endpoint)
MCP_SERVER_AUTH_ENABLED=true
MCP_SERVER_AUTH_TYPE=bearer
MCP_SERVER_AUTH_TOKEN_ENV=MCP_AUTH_TOKEN
MCP_AUTH_TOKEN=your-secret-token-here
# Service authentication tokens
USER_SERVICE_TOKEN=your_user_service_token
PAYMENT_API_KEY=your_payment_api_key
ANALYTICS_CLIENT_SECRET=your_oauth_client_secret
# OAuth2 (if using oauth2 auth strategy)
OAUTH2_CLIENT_ID=your_client_id
OAUTH2_CLIENT_SECRET=your_client_secret
OAUTH2_TOKEN_URL=https://auth.example.com/oauth/token
# Monitoring
METRICS_ENABLED=true
PROMETHEUS_PORT=9090
```
Deploy with Docker:
```bash
docker build -t mcp-proxy .
docker run -p 3000:3000 -p 8080:8080 \
-v ./config:/app/config:ro \
--env-file .env \
mcp-proxy
```
Or with Docker Compose (includes Redis):
```bash
docker-compose up
```
## Configuration
Service configuration is defined in YAML. The proxy reads `config/services.yaml` by default.
### Specifying a Custom Config File
Use the `--config` (or `-c`) flag to load a different configuration file:
```bash
# Stdio with custom config
node dist/server/unified-server.js --transport stdio --config ./config/my-services.yaml
# HTTP with custom config
node dist/server/unified-server.js --transport http --port 3000 --config /absolute/path/to/services.yaml
```
> **Important:** The config path is resolved relative to the **working directory** of the process, not relative to the project root. When the proxy is spawned by an external tool (Claude Desktop, LangChain, etc.), the working directory may differ from the project root. Use an **absolute path** to avoid `CONFIGURATION_ERROR` failures.
### Minimal Example (No Auth)
```yaml
version: "1.0"
settings:
log_level: "info"
metrics_enabled: true
health_check_port: 8080
services:
- name: "jsonplaceholder"
description: "JSONPlaceholder - Free fake REST API"
base_url: "https://jsonplaceholder.typicode.com"
tools:
- name: "get_post"
description: "Get a blog post by ID"
method: "GET"
path: "/posts/{id}"
parameters:
- name: "id"
type: "number"
required: true
description: "Post ID (1-100)"
in: "path"
- name: "list_posts"
description: "List all blog posts"
method: "GET"
path: "/posts"
- name: "get_user"
description: "Get user by ID"
method: "GET"
path: "/users/{id}"
parameters:
- name: "id"
type: "number"
required: true
description: "User ID (1-10)"
in: "path"
```
### Full Enterprise Example
```yaml
version: "1.0"
settings:
log_level: "info"
metrics_enabled: true
health_check_port: 8080
mcp_server_port: 3000
services:
- name: "user_service"
description: "User management service"
base_url: "https://api.example.com/v1/users"
auth:
type: "bearer"
config:
token_env: "USER_SERVICE_TOKEN"
circuit_breaker:
enabled: true
timeout: 3000
error_threshold: 50
reset_timeout: 30000
volume_threshold: 10
rate_limit:
enabled: true
max_requests: 100
window: 60000
strategy: "sliding_window"
access_control:
enabled: true
allowed_roles: ["admin", "user"]
required_permissions: ["read:users"]
retry:
enabled: true
max_attempts: 3
backoff_ms: 1000
timeout: 5000
tools:
- name: "create_user"
description: "Create a new user account"
method: "POST"
path: "/"
access_control:
enabled: true
required_permissions: ["write:users"]
parameters:
- name: "username"
type: "string"
required: true
description: "Username for the new account"
in: "body"
validation:
min_length: 3
max_length: 50
pattern: "^[a-zA-Z0-9_]+$"
- name: "email"
type: "string"
required: true
description: "Email address"
in: "body"
validation:
format: "email"
request_body:
content_type: "application/json"
template: |
{
"username": "{{username}}",
"email": "{{email}}",
"created_at": "{{$timestamp}}"
}
response:
success_codes: [201]
error_codes: [400, 409]
transform: "json"
- name: "payment_service"
description: "Payment processing service"
base_url: "https://api.payments.example.com/v2"
auth:
type: "api_key"
config:
key_env: "PAYMENT_API_KEY"
header_name: "X-Payment-API-Key"
circuit_breaker:
enabled: true
timeout: 5000
error_threshold: 30
reset_timeout: 60000
volume_threshold: 5
rate_limit:
enabled: true
max_requests: 50
window: 60000
strategy: "token_bucket"
tools:
- name: "create_payment"
description: "Process a payment transaction"
method: "POST"
path: "/payments"
parameters:
- name: "amount"
type: "number"
required: true
description: "Payment amount in cents"
in: "body"
validation:
minimum: 1
- name: "currency"
type: "string"
required: true
description: "Currency code"
in: "body"
validation:
enum: ["USD", "EUR", "GBP"]
- name: "analytics_service"
description: "Analytics and reporting service"
base_url: "https://analytics.example.com/api"
auth:
type: "oauth2"
config:
client_id: "analytics_client"
client_secret_env: "ANALYTICS_CLIENT_SECRET"
token_url: "https://auth.example.com/oauth/token"
scope: "analytics:read analytics:write"
tools:
- name: "get_report"
description: "Generate analytics report"
method: "GET"
path: "/reports/{report_id}"
parameters:
- name: "report_id"
type: "string"
required: true
description: "Report identifier"
in: "path"
- name: "format"
type: "string"
required: false
description: "Report format"
in: "query"
validation:
enum: ["json", "csv", "pdf"]
```
### Authentication Types
| Type | Config | Description |
|------|--------|-------------|
| `bearer` | `token_env` | Bearer token from environment variable |
| `api_key` | `key_env`, `header_name` | API key injected as a header |
| `basic` | `username_env`, `password_env` | HTTP Basic authentication |
| `oauth2` | `client_id`, `client_secret_env`, `token_url`, `scope` | OAuth2 client credentials flow |
### MCP Server Inbound Authentication
Protect the `/mcp` endpoint for HTTP transport with environment variables:
```bash
# Bearer token
MCP_SERVER_AUTH_ENABLED=true
MCP_SERVER_AUTH_TYPE=bearer
MCP_AUTH_TOKEN=your-secret-token-here
# API key
MCP_SERVER_AUTH_ENABLED=true
MCP_SERVER_AUTH_TYPE=api_key
MCP_API_KEY=your-api-key-here
# JWT (HMAC-SHA256)
MCP_SERVER_AUTH_ENABLED=true
MCP_SERVER_AUTH_TYPE=jwt
JWT_SECRET=your-jwt-secret-here
```
### Request Body Templates
Templates support variable substitution with JSON injection prevention:
```yaml
request_body:
content_type: "application/json"
template: |
{
"name": "{{name}}",
"id": "{{$uuid}}",
"timestamp": "{{$timestamp}}",
"date": "{{$date}}"
}
```
Special variables: `{{$timestamp}}` (ISO 8601), `{{$date}}` (YYYY-MM-DD), `{{$uuid}}` (v4 UUID).
### Parameter Validation
```yaml
parameters:
- name: "email"
type: "string"
required: true
in: "body"
validation:
format: "email" # email, url, uuid, date
pattern: "^[a-z]+$" # regex pattern
min_length: 5
max_length: 100
enum: ["a", "b", "c"] # allowed values
- name: "count"
type: "number"
required: false
in: "query"
validation:
minimum: 1
maximum: 1000
```
### Response Transformation
Control how upstream REST responses are converted to MCP tool results:
```yaml
response:
success_codes: [200, 201]
error_codes: [400, 404, 500]
transform: "json" # json | text | xml
```
| Transform | Behavior |
|-----------|----------|
| `json` (default) | Parses response as JSON object. If already an object, passes through. If string, attempts `JSON.parse`. |
| `text` | Wraps response in `{ "text": "..." }`. Useful for plain-text APIs. |
| `xml` | Wraps raw XML in `{ "xml": "..." }`. Returns the XML string as-is for client-side parsing. |
### Request Cancellation
The proxy supports MCP request cancellation. When a client cancels a pending tool call:
1. The MCP engine receives the cancellation notification
2. The associated `AbortSignal` is triggered
3. The in-flight HTTP request to the upstream service is aborted
4. Any pending retry sleep is interrupted immediately
5. The client receives a cancellation acknowledgment
This prevents wasted upstream resources on abandoned requests.
## CLI Usage
The CLI manages configuration and server lifecycle.
### Generate Config from OpenAPI
```bash
# Generate from an OpenAPI spec
npm run cli -- generate \
-i ./specs/petstore.yaml \
-n pet_service \
-u https://api.petstore.example.com \
-o ./config/pet-service.yaml
# With auth and filtering
npm run cli -- generate \
-i ./specs/api.yaml \
-n my_service \
-u https://api.example.com \
--auth-type bearer \
--auth-token-env MY_SERVICE_TOKEN \
--include-tags "users,orders" \
--exclude-operations "deleteAll,purge" \
-o ./config/my-service.yaml
```
**Options:**
| Flag | Description |
|------|-------------|
| `-i, --openapi <path>` | Path to OpenAPI/Swagger spec (required) |
| `-n, --service-name <name>` | Service name (required) |
| `-u, --base-url <url>` | Base URL (required) |
| `-o, --output <path>` | Output path (default: `./config/generated-service.yaml`) |
| `--auth-type <type>` | Auth type: `api_key`, `bearer`, `basic`, `oauth2` |
| `--auth-token-env <var>` | Env var name for auth token |
| `--include-operations <ops>` | Comma-separated operation IDs to include |
| `--exclude-operations <ops>` | Comma-separated operation IDs to exclude |
| `--include-tags <tags>` | Comma-separated tags to include |
| `--exclude-tags <tags>` | Comma-separated tags to exclude |
| `--circuit-breaker` | Enable circuit breaker (default: true) |
| `--rate-limit` | Enable rate limiting (default: true) |
### Validate Configuration
```bash
# Validate a config file
npm run cli -- validate -c ./config/services.yaml
# Strict mode
npm run cli -- validate -c ./config/services.yaml --strict
```
### Start Server via CLI
```bash
npm run cli -- serve -c ./config/services.yaml -p 3000
```
## Transport Modes
### Stdio (Default)
Used with Claude Desktop, LangChain, and other MCP clients that communicate over stdin/stdout.
```bash
# Using default config (config/services.yaml)
npm run start:stdio
# Using a custom config file
node dist/server/unified-server.js --transport stdio --config ./config/my-services.yaml
```
Add to Claude Desktop config (`claude_desktop_config.json`):
```json
{
"mcpServers": {
"my-proxy": {
"command": "node",
"args": [
"/path/to/mcp-proxy/dist/server/unified-server.js",
"--transport", "stdio",
"--config", "/path/to/mcp-proxy/config/services.yaml"
],
"env": {
"NODE_ENV": "production"
}
}
}
}
```
Use with LangChain (`langchain-mcp-adapters`):
```python
from langchain_mcp_adapters.client import MultiServerMCPClient
server_configs = {
"my_proxy": {
"command": "node",
"args": [
"/path/to/mcp-proxy/dist/server/unified-server.js",
"--transport", "stdio",
"--config", "/path/to/mcp-proxy/config/services.yaml"
],
"transport": "stdio",
}
}
async with MultiServerMCPClient(server_configs) as client:
tools = await client.get_tools()
```
> **Note:** Always use absolute paths for both the server script and the `--config` file when the proxy is launched by an external tool. These tools may set a different working directory, causing relative paths to fail with `CONFIGURATION_ERROR`.
### HTTP (Streamable HTTP + SSE)
For web-based clients and multi-client deployments.
```bash
# Using default config
npm run start:http
# With custom port, host, and config
node dist/server/unified-server.js --transport http --host 127.0.0.1 --port 8000 --config ./config/my-services.yaml
```
The HTTP transport supports:
- Session management with cryptographic session IDs
- Optional inbound authentication (bearer, API key, JWT, basic)
- CORS configuration
- TLS support
### Graceful Shutdown
The server handles `SIGINT` and `SIGTERM` for clean shutdown:
1. Stops accepting new connections
2. Waits for in-flight requests to complete
3. Closes transport connections
4. Cleans up the MCP engine (flushes metrics, closes circuit breakers)
5. Exits with code 0
Uncaught exceptions and unhandled rejections also trigger graceful shutdown with exit code 1.
## Monitoring
The monitoring server runs on a separate port (default: 8080) and exposes:
| Endpoint | Description |
|----------|-------------|
| `GET /health` | Detailed health status of all services (ping + circuit breaker state) |
| `GET /ready` | Readiness probe — returns 200 when all services are reachable |
| `GET /live` | Liveness probe — always returns 200 if the process is running |
| `GET /metrics` | Prometheus-format metrics |
| `GET /metrics/json` | Metrics in JSON format |
| `GET /status` | Human-readable status summary |
### Metrics Collected
- `mcp_requests_total` — Total MCP requests by tool and status
- `mcp_request_duration_seconds` — Request duration histogram
- `mcp_request_errors_total` — Error count by tool and error type
- `mcp_tool_executions_total` — Tool execution count
- `mcp_tool_execution_duration_seconds` — Tool execution duration
### Health Check Response
```json
{
"status": "healthy",
"services": {
"user_service": {
"status": "up",
"responseTime": 45,
"circuitBreaker": "closed"
}
},
"timestamp": "2025-01-15T10:30:00.000Z"
}
```
### Kubernetes Integration
```yaml
# Deployment probe configuration
livenessProbe:
httpGet:
path: /live
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
```
## Security
### Credential Management
All secrets are managed through environment variables — never stored in configuration files. The `.env` file is gitignored. Use a secrets manager (Vault, AWS Secrets Manager, etc.) in production.
### JSON Template Injection Prevention
Request body templates use `JSON.stringify().slice(1,-1)` to escape user-supplied values before substitution. This prevents injection of additional JSON keys or malformed payloads:
```
Input: hello", "admin": true, "x": "y
Result: {"message": "hello\", \"admin\": true, \"x\": \"y"}
^--- injection neutralized, treated as literal string
```
### Timing-Safe Token Comparison
Authentication token comparison uses `crypto.timingSafeEqual` with buffer padding to prevent timing attacks. Both buffers are padded to equal length before comparison, eliminating length-based timing leaks.
### Cryptographic Session IDs
HTTP transport sessions use `crypto.randomUUID()` (CSPRNG-backed) instead of predictable `Math.random()`. This prevents session prediction attacks.
### Input Validation
- **Configuration**: Zod schemas validate all config at load time (types, ranges, required fields)
- **Runtime**: Per-tool parameter validation checks types, patterns, formats, and ranges before any upstream call is made
### Rate Limiting
Protects upstream services from abuse. Supports per-service and per-user keying with Redis for distributed enforcement across multiple proxy instances.
## Testing
```bash
# Unit tests
npm test
# Unit tests with coverage
npm run test:coverage
# Watch mode
npm run test:watch
# E2E tests (stdio transport + cancellation)
npm run test:e2e
# E2E: HTTP transport
npm run test:http
# E2E: HTTP with authentication
npm run test:http:auth
# All tests (unit + e2e)
npm run test:all
# Type checking only
npm run typecheck
```
### Test Coverage
| Area | Tests |
|------|-------|
| Config schema validation | Zod schema correctness |
| Template injection | JSON escape and injection neutralization |
| Health checker | Ping, circuit breaker state, multi-service |
| REST client | Ping, timeout, error handling |
| Access control | Role/permission checks, deny/allow |
| Request validator | Type, pattern, format, range validation |
| Timing-safe comparison | Correctness across lengths, no early-return |
| E2E stdio | Full tool call roundtrip over stdin/stdout |
| E2E HTTP | HTTP transport with session management |
| E2E cancellation | Request abort propagation |
## Project Structure
```
mcp-proxy/
├── src/
│ ├── core/
│ │ └── mcp-engine.ts # Transport-agnostic MCP protocol engine
│ ├── transport/
│ │ ├── index.ts # Transport exports
│ │ ├── types.ts # ITransport interface, configs, states
│ │ ├── factory.ts # Transport factory (createTransport)
│ │ ├── stdio-transport.ts # Stdio transport implementation
│ │ └── http-transport.ts # HTTP transport (Streamable HTTP + SSE)
│ ├── server/
│ │ ├── unified-server.ts # Main entry: CLI arg parsing + bootstrap
│ │ └── tool-registry.ts # Dynamic tool registration
│ ├── config/
│ │ ├── loader.ts # YAML/JSON configuration loader
│ │ ├── schema.ts # Zod validation schemas
│ │ └── openapi-parser.ts # OpenAPI/Swagger → tool config parser
│ ├── rest/
│ │ ├── client.ts # Axios HTTP client with circuit breaker + retry
│ │ └── transformer.ts # Response transformation (JSON, text, XML)
│ ├── auth/
│ │ ├── manager.ts # Auth strategy manager
│ │ ├── types.ts # Auth types
│ │ └── strategies/
│ │ ├── api-key.ts
│ │ ├── bearer.ts
│ │ ├── basic.ts
│ │ └── oauth2.ts
│ ├── middleware/
│ │ ├── rate-limiter.ts # Rate limiting (fixed/sliding/token bucket)
│ │ ├── access-control.ts # RBAC implementation
│ │ └── validator.ts # Request parameter validation
│ ├── monitoring/
│ │ ├── metrics.ts # Prometheus-style metrics collector
│ │ ├── health.ts # Health checker (ping + circuit breaker)
│ │ └── http-server.ts # Monitoring HTTP server (/health, /metrics)
│ ├── types/
│ │ └── config.ts # ProxyConfig, ServiceConfig, ToolConfig types
│ ├── utils/
│ │ ├── errors.ts # Custom error classes
│ │ └── logger.ts # Winston structured logging
│ └── cli/
│ ├── index.ts # CLI entry point (commander)
│ └── commands/
│ ├── generate.ts # Generate config from OpenAPI
│ ├── validate.ts # Validate configuration
│ └── serve.ts # Start server
├── config/
│ ├── services.yaml # Active service configuration
│ ├── example-services.yaml # Full-featured example
│ └── openapi/
│ └── example-user-api.yaml # Example OpenAPI spec
├── tests/
│ ├── unit/ # Unit tests (Jest)
│ └── e2e/ # End-to-end tests
├── Dockerfile # Multi-stage production build
├── docker-compose.yaml # Docker Compose (proxy + Redis)
├── package.json
├── tsconfig.json
└── jest.config.js
```
## Troubleshooting
### Circuit breaker stays open
**Symptom**: All requests to a service fail immediately with "service temporarily unavailable".
**Cause**: The error rate exceeded `error_threshold` percentage within `volume_threshold` requests.
**Fix**:
1. Check the upstream service is healthy: `curl <service_base_url>/health`
2. Review logs for the root cause: `LOG_LEVEL=debug npm run start:http`
3. The circuit will auto-close after `reset_timeout` ms if a test request succeeds
4. To force reset, restart the proxy
### Rate limit exceeded
**Symptom**: Requests return rate limit errors before reaching the upstream service.
**Cause**: More than `max_requests` were made within `window` ms.
**Fix**:
1. Increase `max_requests` or `window` in config
2. If using `per_user` keying, check if a single user is dominating
3. For distributed deployments, ensure Redis is connected — without Redis, each instance tracks limits independently
### Redis connection failures
**Symptom**: Startup warning about Redis connection, or rate limiting behaves inconsistently.
**Cause**: Redis is unreachable or credentials are wrong.
**Fix**:
1. Verify Redis is running: `redis-cli ping`
2. Check `REDIS_HOST`, `REDIS_PORT`, `REDIS_PASSWORD` in `.env`
3. The proxy falls back to in-memory rate limiting if Redis is unavailable — this is safe for single-instance deployments
### Config validation errors
**Symptom**: Server fails to start with a Zod validation error.
**Fix**:
1. Run `npm run cli -- validate -c ./config/services.yaml` for detailed error output
2. Common issues: missing `base_url`, invalid `method` (must be uppercase GET/POST/PUT/DELETE/PATCH), `type` must be one of string/number/boolean/object/array
### Authentication failures to upstream services
**Symptom**: Upstream returns 401/403 even though auth is configured.
**Fix**:
1. Verify the env var specified in `token_env` / `key_env` is set: `echo $USER_SERVICE_TOKEN`
2. For OAuth2, check that `token_url` is reachable and client credentials are valid
3. Enable debug logging to see the outgoing auth headers (tokens are redacted): `LOG_LEVEL=debug`
### Stdio transport not connecting
**Symptom**: Claude Desktop shows the MCP server as disconnected.
**Fix**:
1. Ensure the project is built: `npm run build`
2. Verify the path in `claude_desktop_config.json` points to `dist/server/unified-server.js`
3. Test manually: `echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}' | node dist/server/unified-server.js`
4. Check that no other output (console.log, debug prints) pollutes stdout — the stdio transport requires clean JSON-RPC over stdin/stdout
### Request timeout
**Symptom**: Tool calls fail with "Request timeout" after the configured timeout period.
**Fix**:
1. Increase `timeout` at the service level or per-tool level
2. If circuit breaker is enabled, ensure `circuit_breaker.timeout` is >= service `timeout`
3. Check network connectivity to the upstream service
## Scripts Reference
| Script | Description |
|--------|-------------|
| `npm run build` | Compile TypeScript to `dist/` |
| `npm run dev` | Development mode with hot reload |
| `npm run start` | Start server (legacy entry point) |
| `npm run start:unified` | Start unified server (auto-detect transport) |
| `npm run start:stdio` | Start with stdio transport |
| `npm run start:http` | Start with HTTP transport on port 3000 |
| `npm run test` | Run unit tests |
| `npm run test:all` | Run unit + e2e tests |
| `npm run test:e2e` | Run E2E tests (stdio + cancellation) |
| `npm run test:http` | Run HTTP transport E2E |
| `npm run test:http:auth` | Run HTTP auth E2E |
| `npm run test:coverage` | Unit tests with coverage report |
| `npm run cli -- <cmd>` | Run CLI commands (generate, validate, serve) |
| `npm run typecheck` | TypeScript type checking |
| `npm run lint` | ESLint |
| `npm run lint:fix` | ESLint with auto-fix |
| `npm run format` | Prettier formatting |
## Technology Stack
| Component | Technology |
|-----------|------------|
| Runtime | Node.js >= 18 |
| Language | TypeScript 5.x |
| MCP SDK | `@modelcontextprotocol/sdk` |
| HTTP Client | Axios |
| Circuit Breaker | Opossum |
| Rate Limiting | rate-limiter-flexible + optional Redis (ioredis) |
| Validation | Zod |
| Logging | Winston (structured JSON) |
| Metrics | prom-client (Prometheus) |
| HTTP Server | Express |
| OpenAPI Parsing | @apidevtools/swagger-parser |
| CLI | Commander |
| Testing | Jest + ts-jest (ESM) |
| Containerization | Docker (multi-stage, node:20-alpine) |
## Related Documentation
- [Architecture Overview](./ARCHITECTURE.md) — System design, request flow diagrams, component details
- [Testing Guide](./docs/TEST_GUIDE.md) — End-to-end testing walkthrough
## Contributing
1. Fork the repository
2. Create a feature branch: `git checkout -b feature/my-feature`
3. Make your changes and add tests
4. Run the full test suite: `npm run test:all`
5. Run type checking: `npm run typecheck`
6. Run linting: `npm run lint`
7. Commit with a descriptive message
8. Open a Pull Request
Please ensure all tests pass and type checking succeeds before submitting.
## License
MIT
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues