Transport-level routing for MCP/ACP protocols
We appreciate your patience. The service is temporarily operating in an external runtime environment.
Transport-level routing for MCP/ACP protocols
We appreciate your patience. The service is temporarily operating in an external runtime environment.
Complete API reference for @stdiobus/workers-registry, including module imports, TypeScript types, and environment variables.
The @stdiobus/workers-registry package provides worker implementations for stdio Bus kernel. This reference covers the programmatic API for importing and using workers in your applications.
Package name: @stdiobus/workers-registry
Version: 1.3.19 (pre-release)
License: Apache-2.0
Repository: github.com/stdiobus/workers-registry
npm install @stdiobus/workers-registry
Requirements:
The default export provides the ACP Worker:
// CommonJSconst worker = require('@stdiobus/workers-registry');// ES Modulesimport worker from '@stdiobus/workers-registry';
Import specific workers using named exports:
// Import specific workersimport {acpWorker,echoWorker,mcpEchoServer,mcpToAcpProxy,registryLauncher} from '@stdiobus/workers-registry/workers';// Import workers metadataimport { workers } from '@stdiobus/workers-registry/workers';
Import workers by path:
// ACP Workerimport acpWorker from '@stdiobus/workers-registry/workers/acp-worker';// Echo Workerimport echoWorker from '@stdiobus/workers-registry/workers/echo-worker';// MCP Echo Serverimport mcpEchoServer from '@stdiobus/workers-registry/workers/mcp-echo-server';// MCP-to-ACP Proxyimport mcpToAcpProxy from '@stdiobus/workers-registry/workers/mcp-to-acp-proxy';// Registry Launcherimport registryLauncher from '@stdiobus/workers-registry/workers/registry-launcher';
The package exports a metadata object containing information about all available workers:
import { workers } from '@stdiobus/workers-registry/workers';console.log(workers);// {// 'acp-worker': {// name: 'ACP Worker',// description: 'Full ACP protocol implementation',// entrypoint: './workers/acp-worker/dist/index.js',// protocol: 'ACP'// },// 'echo-worker': {// name: 'Echo Worker',// description: 'Simple echo worker for testing',// entrypoint: './workers/echo-worker/echo-worker.js',// protocol: 'NDJSON'// },// // ... other workers// }
interface WorkersMetadata {[workerId: string]: {name: string; // Display namedescription: string; // Brief descriptionentrypoint: string; // Path to worker entry pointprotocol: string; // Protocol(s) supported};}
// ACP Worker typesimport type { ACPAgent } from '@stdiobus/workers-registry/workers/acp-worker';import type { ACPSession } from '@stdiobus/workers-registry/workers/acp-worker';import type { ACPMessage } from '@stdiobus/workers-registry/workers/acp-worker';// MCP Echo Server typesimport type { MCPServer } from '@stdiobus/workers-registry/workers/mcp-echo-server';import type { MCPTool } from '@stdiobus/workers-registry/workers/mcp-echo-server';// Registry Launcher typesimport type { RegistryAgent } from '@stdiobus/workers-registry/workers/registry-launcher';import type { AgentMetadata } from '@stdiobus/workers-registry/workers/registry-launcher';
/*** stdio Bus pool configuration*/interface PoolConfig {/** Unique identifier for this worker pool */id: string;/** Path to the executable */command: string;/** Command-line arguments */args?: string[];/** Number of worker instances */instances: number;/** Environment variables */env?: Record<string, string>;}/*** stdio Bus limits configuration*/interface LimitsConfig {/** Maximum input buffer size per connection (bytes) */max_input_buffer?: number;/** Maximum output queue size per connection (bytes) */max_output_queue?: number;/** Maximum worker restarts within restart window */max_restarts?: number;/** Time window for counting restarts (seconds) */restart_window_sec?: number;/** Timeout for graceful shutdown (seconds) */drain_timeout_sec?: number;/** Timeout before closing connection when queue is full (seconds) */backpressure_timeout_sec?: number;}/*** Complete stdio Bus configuration*/interface StdioBusConfig {/** Worker pool configurations */pools: PoolConfig[];/** Resource limits */limits?: LimitsConfig;}
/*** JSON-RPC 2.0 request*/interface JSONRPCRequest {/** JSON-RPC version (always "2.0") */jsonrpc: '2.0';/** Request ID (string or number) */id: string | number;/** Method name */method: string;/** Method parameters */params?: Record<string, any>;/** Optional session ID for session affinity */sessionId?: string;}/*** JSON-RPC 2.0 response*/interface JSONRPCResponse {/** JSON-RPC version (always "2.0") */jsonrpc: '2.0';/** Request ID */id: string | number;/** Result (if successful) */result?: any;/** Error (if failed) */error?: JSONRPCError;/** Optional session ID */sessionId?: string;}/*** JSON-RPC 2.0 error*/interface JSONRPCError {/** Error code */code: number;/** Error message */message: string;/** Additional error data */data?: any;}/*** JSON-RPC 2.0 notification (no response expected)*/interface JSONRPCNotification {/** JSON-RPC version (always "2.0") */jsonrpc: '2.0';/** Method name */method: string;/** Method parameters */params?: Record<string, any>;}
These environment variables apply to all workers:
| Variable | Type | Default | Description |
|---|---|---|---|
NODE_ENV | string | development | Node.js environment (development, production) |
LOG_LEVEL | string | info | Logging level (debug, info, warn, error) |
DEBUG | string | - | Enable debug output (set to * for all) |
| Variable | Type | Default | Description |
|---|---|---|---|
MCP_SERVERS | string | - | Comma-separated list of MCP server names |
MCP_CONFIG_PATH | string | ./mcp-servers.json | Path to MCP servers configuration file |
| Variable | Type | Default | Description |
|---|---|---|---|
REGISTRY_URL | string | ACP Registry URL | URL to ACP Registry JSON |
CACHE_TTL | number | 3600 | Registry cache TTL in seconds |
API_KEYS_PATH | string | - | Path to API keys configuration file |
| Variable | Type | Default | Description |
|---|---|---|---|
ACP_HOST | string | localhost | stdio Bus host address |
ACP_PORT | string | 9000 | stdio Bus port number |
AGENT_ID | string | - | Target agent ID for routing |
TIMEOUT | number | 30000 | Request timeout in milliseconds |
| Variable | Type | Default | Description |
|---|---|---|---|
LOG_LEVEL | string | info | Logging level |
NODE_ENV | string | development | Node.js environment |
import { spawn } from 'child_process';import { workers } from '@stdiobus/workers-registry/workers';/*** Spawn a worker process*/function spawnWorker(workerId, args = []) {const workerMeta = workers[workerId];if (!workerMeta) {throw new Error(`Unknown worker: ${workerId}`);}const worker = spawn('node', [workerMeta.entrypoint,...args], {stdio: ['pipe', 'pipe', 'pipe']});return worker;}// Usageconst echoWorker = spawnWorker('echo-worker');// Send message to workerechoWorker.stdin.write(JSON.stringify({jsonrpc: '2.0',id: '1',method: 'test',params: {}}) + '\n');// Read response from workerechoWorker.stdout.on('data', (data) => {const response = JSON.parse(data.toString());console.log('Response:', response);});// Handle errorsechoWorker.stderr.on('data', (data) => {console.error('Worker error:', data.toString());});// Handle exitechoWorker.on('exit', (code) => {console.log('Worker exited with code:', code);});
import readline from 'readline';/*** Base class for custom workers*/class BaseWorker {constructor() {this.rl = readline.createInterface({input: process.stdin,output: process.stdout,terminal: false});this.setupHandlers();}setupHandlers() {this.rl.on('line', (line) => {try {const message = JSON.parse(line);this.handleMessage(message);} catch (err) {console.error('Parse error:', err.message);}});process.on('SIGTERM', () => {this.shutdown();});this.rl.on('close', () => {process.exit(0);});}handleMessage(message) {// Override in subclassif (message.id !== undefined) {this.sendResponse(message.id, {status: 'ok'}, message.sessionId);}}sendResponse(id, result, sessionId = null) {const response = {jsonrpc: '2.0',id,result};if (sessionId) {response.sessionId = sessionId;}console.log(JSON.stringify(response));}sendError(id, code, message, sessionId = null) {const response = {jsonrpc: '2.0',id,error: {code,message}};if (sessionId) {response.sessionId = sessionId;}console.log(JSON.stringify(response));}shutdown() {console.error('Shutting down...');this.rl.close();}}// Usageclass MyWorker extends BaseWorker {handleMessage(message) {if (message.method === 'myMethod') {this.sendResponse(message.id, {result: 'success'}, message.sessionId);} else {this.sendError(message.id, -32601, 'Method not found', message.sessionId);}}}const worker = new MyWorker();
import { EventEmitter } from 'events';import readline from 'readline';/*** Worker communication helper*/class WorkerClient extends EventEmitter {constructor(worker) {super();this.worker = worker;this.requestId = 0;this.pendingRequests = new Map();this.setupReadline();}setupReadline() {const rl = readline.createInterface({input: this.worker.stdout,crlfDelay: Infinity});rl.on('line', (line) => {try {const response = JSON.parse(line);this.handleResponse(response);} catch (err) {this.emit('error', err);}});this.worker.stderr.on('data', (data) => {this.emit('stderr', data.toString());});this.worker.on('exit', (code) => {this.emit('exit', code);});}handleResponse(response) {if (response.id && this.pendingRequests.has(response.id)) {const { resolve, reject } = this.pendingRequests.get(response.id);this.pendingRequests.delete(response.id);if (response.error) {reject(new Error(response.error.message));} else {resolve(response.result);}}}sendRequest(method, params = {}, sessionId = null) {return new Promise((resolve, reject) => {const id = String(++this.requestId);const request = {jsonrpc: '2.0',id,method,params};if (sessionId) {request.sessionId = sessionId;}this.pendingRequests.set(id, { resolve, reject });this.worker.stdin.write(JSON.stringify(request) + '\n');});}close() {this.worker.kill('SIGTERM');}}// Usageimport { spawn } from 'child_process';const worker = spawn('node', ['@stdiobus/workers-registry','echo-worker']);const client = new WorkerClient(worker);client.on('stderr', (data) => {console.error('Worker stderr:', data);});client.on('exit', (code) => {console.log('Worker exited:', code);});// Send requestconst result = await client.sendRequest('test', { foo: 'bar' });console.log('Result:', result);// Close workerclient.close();
Run any worker using the universal launcher:
npx @stdiobus/workers-registry <worker-name> [args...]
Available workers:
acp-worker - ACP Workerregistry-launcher - Registry Launcherecho-worker - Echo Workermcp-echo-server - MCP Echo Servermcp-to-acp-proxy - MCP-to-ACP ProxyExamples:
# Run echo workernpx @stdiobus/workers-registry echo-worker# Run ACP workernpx @stdiobus/workers-registry acp-worker# Run registry launcher with API keysnpx @stdiobus/workers-registry registry-launcher /path/to/api-keys.json
Run workers directly using their entry points:
# Echo Workernode ./node_modules/@stdiobus/workers-registry/workers/echo-worker/echo-worker.js# ACP Workernode ./node_modules/@stdiobus/workers-registry/workers/acp-worker/dist/index.js# MCP Echo Servernode ./node_modules/@stdiobus/workers-registry/workers/mcp-echo-server/dist/index.js
Standard JSON-RPC 2.0 error codes:
| Code | Message | Description |
|---|---|---|
| -32700 | Parse error | Invalid JSON |
| -32600 | Invalid Request | Missing required fields |
| -32601 | Method not found | Unknown method |
| -32602 | Invalid params | Invalid parameters |
| -32603 | Internal error | Worker internal error |
Worker-specific error codes:
| Code | Message | Description |
|---|---|---|
| -32000 | Server error | Generic worker error |
| -32001 | Session not found | Invalid session ID |
| -32002 | Agent not found | Invalid agent ID |
| -32003 | Tool not found | Invalid tool name |
| -32004 | Tool execution error | Tool execution failed |
try {const result = await client.sendRequest('test', {});console.log('Success:', result);} catch (err) {if (err.code === -32601) {console.error('Method not found');} else if (err.code === -32602) {console.error('Invalid parameters');} else {console.error('Error:', err.message);}}