@ebowwa/mcp-transport
v0.2.0
Published
Unified MCP server transport - switch between stdio, HTTP, CLI, WebSocket, and Webhook at runtime
Maintainers
Readme
@ebowwa/mcp-transport
Unified MCP server transport - switch between stdio, HTTP, CLI, REST, WebSocket, and Webhook at runtime.
Why?
Every MCP server currently hardcodes its transport mode. This package provides a unified API so you can:
- Develop with HTTP - Test your MCP server in a browser or with curl
- Deploy with stdio - Run in production with Claude Desktop
- Test with CLI - Invoke tools directly from command line
- Expose as REST - Provide pure REST API with OpenAPI spec
- Real-time with WebSocket - Full-duplex communication
- Notify with Webhook - Push events to external systems
- Switch with env vars - No code changes needed
Installation
bun add @ebowwa/mcp-transportQuick Start
import { createAndStartServer } from '@ebowwa/mcp-transport';
// Define your tools
const tools = [
{
name: 'echo',
description: 'Echo a message back',
inputSchema: {
type: 'object',
properties: {
message: { type: 'string', description: 'Message to echo' },
},
required: ['message'],
},
handler: async ({ message }) => {
return { content: [{ type: 'text', text: message }] };
},
},
];
// Start server - transport mode determined by env vars
const running = await createAndStartServer({
config: { name: 'my-server' },
tools,
});
// Graceful shutdown
process.on('SIGINT', async () => {
await running.shutdown();
});Transport Modes
| Mode | Use Case | Command |
|------|----------|---------|
| stdio | Claude Desktop, IDEs (default) | bun run server.ts |
| http | Web clients, SSE streaming | MCP_TRANSPORT=http bun run server.ts |
| cli | Direct tool invocation, testing | mcp-transport --module ./server.js --invoke echo |
| rest | REST API consumers | MCP_TRANSPORT=rest bun run server.ts |
| websocket | Real-time apps, low-latency | MCP_TRANSPORT=websocket bun run server.ts |
| webhook | Event notifications, integrations | MCP_TRANSPORT=webhook bun run server.ts |
Environment Variables
Core Variables
| Variable | Default | Description |
|----------|---------|-------------|
| MCP_TRANSPORT | stdio | Transport mode: stdio, http, sse, cli, rest, websocket, webhook |
| MCP_PORT | 3000 | HTTP/WebSocket port |
| MCP_HOST | localhost | Server host |
| MCP_SERVER_NAME | mcp-server | Server name for handshake |
| MCP_SERVER_VERSION | 1.0.0 | Server version |
REST Mode Variables
| Variable | Default | Description |
|----------|---------|-------------|
| MCP_REST_BASE_PATH | /api | REST API base path |
| MCP_REST_AUTH_TYPE | none | Auth type: bearer, basic, api-key, oauth2 |
| MCP_REST_API_KEY | - | API key value |
| MCP_REST_BEARER_TOKEN | - | Bearer token |
| MCP_REST_RATE_LIMIT | false | Enable rate limiting |
| MCP_REST_RATE_LIMIT_MAX | 100 | Max requests per window |
| MCP_REST_OPENAPI | true | Generate OpenAPI spec |
WebSocket Mode Variables
| Variable | Default | Description |
|----------|---------|-------------|
| MCP_WS_PATH | /ws | WebSocket endpoint path |
| MCP_WS_HEARTBEAT | 30000 | Heartbeat interval (ms) |
| MCP_WS_MAX_MESSAGE_SIZE | 1048576 | Max message size (bytes) |
| MCP_WS_COMPRESSION | false | Enable compression |
Webhook Mode Variables
| Variable | Default | Description |
|----------|---------|-------------|
| MCP_WEBHOOK_SECRET | - | HMAC-SHA256 signing secret |
| MCP_WEBHOOK_OUTBOUND_URL | - | Webhook destination URL |
| MCP_WEBHOOK_RETRY_ENABLED | true | Enable retry mechanism |
| MCP_WEBHOOK_RETRY_MAX | 3 | Max retry attempts |
| MCP_WEBHOOK_EVENTS | tool.called,tool.completed,tool.failed | Events to emit |
Usage Examples
Stdio Mode (Default)
# Run in stdio mode
bun run server.ts
# Claude Desktop config
{
"mcpServers": {
"my-server": {
"command": "bun",
"args": ["run", "server.ts"]
}
}
}HTTP Mode
# Run in HTTP mode
MCP_TRANSPORT=http MCP_PORT=3000 bun run server.ts
# Test with curl
curl http://localhost:3000/health
# {"status":"ok","sessions":0,"transport":"http-sse"}CLI Mode
Direct tool invocation without running a server:
# List available tools
mcp-transport --module ./dist/server.js --list-tools
# Output:
# Available tools:
# echo
# Echo a message back
# Invoke a tool directly
mcp-transport --module ./dist/server.js --invoke echo --input '{"message":"hello"}'
# Output (JSON):
# {"content":[{"type":"text","text":"hello"}]}
# Interactive REPL mode
mcp-transport --module ./dist/server.js --interactive
# mcp> list
# mcp> invoke echo {"message":"test"}
# mcp> exitREST Mode
Pure REST API with OpenAPI specification:
# Start REST server
MCP_TRANSPORT=rest MCP_PORT=3000 bun run server.ts
# List all tools
curl http://localhost:3000/api/tools
# Get tool schema
curl http://localhost:3000/api/tools/echo
# Invoke tool
curl -X POST http://localhost:3000/api/tools/echo/invoke \
-H "Content-Type: application/json" \
-d '{"message":"hello"}'
# Get OpenAPI specification
curl http://localhost:3000/api/openapi.json
# Health check
curl http://localhost:3000/api/healthREST Endpoints
| Method | Path | Description |
|--------|------|-------------|
| GET | /api/tools | List all tools |
| GET | /api/tools/:name | Get tool schema |
| POST | /api/tools/:name/invoke | Invoke a tool |
| GET | /api/resources | List resources |
| GET | /api/resources/* | Read resource |
| GET | /api/prompts | List prompts |
| POST | /api/prompts/:name/render | Render prompt |
| GET | /api/health | Health check |
| GET | /api/openapi.json | OpenAPI specification |
WebSocket Mode
Full-duplex communication with NDJSON protocol:
# Start WebSocket server
MCP_TRANSPORT=websocket MCP_PORT=3000 bun run server.ts
# Connect with wscat
wscat -c ws://localhost:3000/wsNDJSON Protocol
Messages are newline-delimited JSON:
// Request (requires response)
{"id": "req-1", "type": "request", "method": "tools/call", "params": {"name": "echo", "arguments": {"message": "hi"}}}
// Response
{"id": "req-1", "type": "response", "result": {"content": [{"type": "text", "text": "hi"}]}}
// Notification (no response)
{"type": "notification", "method": "notifications/message", "params": {"level": "info", "data": "Hello"}}Webhook Mode
Push notifications to external URLs:
# Start webhook transport
MCP_TRANSPORT=webhook \
MCP_WEBHOOK_SECRET=whsec_xxx \
MCP_WEBHOOK_OUTBOUND_URL=https://example.com/webhook \
bun run server.tsWebhook Events
| Event | Description |
|-------|-------------|
| tool.called | Tool invocation started |
| tool.completed | Tool finished successfully |
| tool.failed | Tool failed with error |
| resource.updated | Resource changed |
Webhook Payload
{
"type": "tool.completed",
"timestamp": "2026-02-24T21:30:00.000Z",
"sessionId": "sess-abc123",
"eventId": "evt_xyz123",
"data": {
"toolName": "echo",
"result": {"content": [{"type": "text", "text": "hello"}]},
"durationMs": 15
}
}Signature Verification
import { verifySignature } from '@ebowwa/mcp-transport/webhook';
const payload = JSON.stringify(webhookBody);
const signature = req.headers['x-webhook-signature'];
if (verifySignature(payload, signature, 'whsec_xxx')) {
// Valid webhook
}Using Zod Schemas
import { createAndStartServer } from '@ebowwa/mcp-transport';
import { z } from 'zod';
await createAndStartServer({
tools: [{
name: 'add',
description: 'Add two numbers',
inputSchema: z.object({
a: z.number().describe('First number'),
b: z.number().describe('Second number'),
}),
handler: async ({ a, b }) => ({ result: a + b }),
}],
});Custom Express Integration
import express from 'express';
import { createMCPExpressApp, createMCPServer } from '@ebowwa/mcp-transport';
const app = express();
// Your existing routes
app.get('/api/data', (req, res) => res.json({ data: 'hello' }));
// Add MCP routes to existing app
const serverFactory = () => createMCPServer({
tools: [...],
});
const { app: mcpApp, sessions } = createMCPExpressApp(serverFactory, {
expressApp: app,
sseEndpoint: '/mcp/sse',
messagesEndpoint: '/mcp/messages',
});
app.listen(3000);Resources and Prompts
import { createAndStartServer } from '@ebowwa/mcp-transport';
await createAndStartServer({
config: { name: 'resource-server' },
tools: [...],
resources: [
{
uriTemplate: 'file://config/{path}',
name: 'config',
description: 'Access config files',
mimeType: 'application/json',
handler: async (uri, params) => ({
contents: [{
uri: uri.href,
text: JSON.stringify({ setting: params.path }),
}],
}),
},
],
prompts: [
{
name: 'greeting',
description: 'Generate a greeting',
arguments: [
{ name: 'name', description: 'Person to greet', required: true },
],
handler: async ({ name }) => ({
messages: [{
role: 'user',
content: { type: 'text', text: `Hello, ${name}!` },
}],
}),
},
],
});API Reference
createAndStartServer(definition)
Create and start an MCP server with automatic transport selection.
interface MCPServerDefinition {
config?: MCPTransportConfig;
tools?: MCPToolDefinition[];
resources?: MCPResourceDefinition[];
prompts?: MCPPromptDefinition[];
setup?: (server: McpServer) => void | Promise<void>;
}createMCPServer(definition)
Create an MCP server instance without starting transport.
Transport Functions
| Function | Description |
|----------|-------------|
| startStdioTransport(server, config) | Start with stdio transport |
| startHttpTransport(serverFactory, config) | Start with HTTP/SSE transport |
| startCLITransport(serverFactory, config) | Start with CLI transport |
| startRESTTransport(serverFactory, config) | Start with REST transport |
| startWebSocketTransport(serverFactory, config) | Start with WebSocket transport |
| startWebhookTransport(serverFactory, config) | Start with Webhook transport |
| createMCPExpressApp(serverFactory, config) | Create Express app with MCP routes |
CLI Commands
mcp-transport --module <path> [options]
Options:
--module, -m <path> Path to server module
--name, -n <name> Server name
--list-tools, -l List available tools
--invoke, -i <name> Invoke a tool
--input <json> JSON input for tool
--interactive, -I Start interactive REPL
--json, -j Output as JSON
--mode <transport> Transport mode
--help, -h Show helpLicense
MIT
