Programmatic API
The muxed package exposes a full JavaScript/TypeScript client for managing MCP servers, calling tools, reading resources, and controlling muxed — all programmatically.
Installation
Section titled “Installation”npm install muxedImport paths
Section titled “Import paths”import { createClient } from 'muxed';// orimport { createClient } from 'muxed/client';Creating a client
Section titled “Creating a client”import { createClient } from 'muxed';
const client = await createClient();// or with options:const client = await createClient({ configPath: './muxed.config.json', autoStart: true, // default: true — starts daemon if not running});CreateClientOptions
Section titled “CreateClientOptions”| Option | Type | Default | Description |
|---|---|---|---|
configPath | string | — | Path to muxed.config.json. Uses default resolution if omitted. |
autoStart | boolean | true | Auto-starts the daemon if not running. Set to false to throw if the daemon is not running. |
API reference
Section titled “API reference”client.tools(server?)
Section titled “client.tools(server?)”List all tools, optionally filtered by server name.
const tools = await client.tools();const tools = await client.tools('filesystem');// Returns: Array<{ server: string; tool: Tool }>client.tool(toolPath)
Section titled “client.tool(toolPath)”Get a single tool’s schema by its fully qualified name.
const tool = await client.tool('filesystem/read_file');// Returns: Toolclient.grep(query)
Section titled “client.grep(query)”Search tools by name or description.
const matches = await client.grep('search');// Returns: Array<{ server: string; tool: Tool }>client.call(toolPath, args?, options?)
Section titled “client.call(toolPath, args?, options?)”Call a tool and wait for the result.
const result = await client.call('filesystem/read_file', { path: '/tmp/file.txt' });// Returns: CallResultPass a timeout (in milliseconds) to limit how long the call can take:
const result = await client.call('server/tool', args, { timeout: 5000 });Extract specific fields from the response to reduce context window usage:
const result = await client.call('db/query', { sql: 'SELECT * FROM users' }, { fields: ['rows[].name', 'rows[].email'],});Field filtering only applies to JSON-parseable content (structuredContent or text blocks with valid JSON). Non-JSON responses are returned unchanged.
client.validate(toolPath, args?)
Section titled “client.validate(toolPath, args?)”Validate arguments against a tool’s schema without executing the call (dry-run mode).
const result = await client.validate('postgres/query', { sql: 'DROP TABLE users' });// Returns: ValidationResult { valid, errors, warnings, tool? }
if (!result.valid) { console.error('Validation errors:', result.errors);}for (const warning of result.warnings) { console.warn(warning); // e.g. "Tool is marked as destructive."}Checks required fields, unknown fields, type mismatches, and enum values. Warnings include tool annotation hints (destructive, not idempotent, not read-only).
client.callAsync(toolPath, args?)
Section titled “client.callAsync(toolPath, args?)”Call a tool asynchronously. Returns a task handle you can poll for completion.
const task = await client.callAsync('analytics/export', { range: '30d' });// Returns: TaskHandle { taskId, server, status }Resources
Section titled “Resources”client.resources(server?)
Section titled “client.resources(server?)”List resources, optionally filtered by server name.
const resources = await client.resources();const resources = await client.resources('server-name');// Returns: Array<{ server: string; resource: Resource }>client.read(server, uri)
Section titled “client.read(server, uri)”Read a resource by server name and URI.
const content = await client.read('server-name', 'resource://uri');// Returns: ReadResourceResultPrompts
Section titled “Prompts”client.prompts(server?)
Section titled “client.prompts(server?)”List prompts, optionally filtered by server name.
const prompts = await client.prompts();const prompts = await client.prompts('server-name');// Returns: Array<{ server: string; prompt: Prompt }>client.prompt(server, name, args?)
Section titled “client.prompt(server, name, args?)”Get a prompt result by server name and prompt name.
const result = await client.prompt('server-name', 'prompt-name', { arg: 'value' });// Returns: GetPromptResultCompletions
Section titled “Completions”client.complete(server, ref, argument)
Section titled “client.complete(server, ref, argument)”Request argument completions from a server.
const result = await client.complete( 'server-name', { type: 'ref/prompt', name: 'prompt-name' }, { name: 'argument', value: 'partial-value' });// Returns: CompleteResultclient.tasks(server?)
Section titled “client.tasks(server?)”List tasks, optionally filtered by server name.
const tasks = await client.tasks();const tasks = await client.tasks('server-name');// Returns: Array<{ server: string; tasks: Array<Record<string, unknown>> }>client.task(server, taskId)
Section titled “client.task(server, taskId)”Get the status of a specific task.
const status = await client.task('server-name', 'task-id');client.taskResult(server, taskId)
Section titled “client.taskResult(server, taskId)”Get the result of a completed task.
const result = await client.taskResult('server-name', 'task-id');client.taskCancel(server, taskId)
Section titled “client.taskCancel(server, taskId)”Cancel a running task.
const cancelled = await client.taskCancel('server-name', 'task-id');Daemon
Section titled “Daemon”client.servers()
Section titled “client.servers()”List all configured servers and their state.
const servers = await client.servers();// Returns: ServerState[]client.status()
Section titled “client.status()”Get the current daemon status.
const status = await client.status();// Returns: DaemonStatus { pid, uptime, serverCount, servers }client.reload()
Section titled “client.reload()”Reload the daemon configuration. Returns a summary of what changed.
const changes = await client.reload();// Returns: ReloadResult { added, removed, changed }client.stop()
Section titled “client.stop()”Stop the daemon process.
await client.stop();client.close()
Section titled “client.close()”Close the client connection. Call this when you are done using the client.
client.close();Key types
Section titled “Key types”CallResult
Section titled “CallResult”type CallResult = { content: Array<{ type: string; text?: string; mimeType?: string; data?: string; name?: string; uri?: string; resource?: { text?: string; blob?: string; mimeType?: string }; }>; structuredContent?: Record<string, unknown>; isError?: boolean;};CallOptions
Section titled “CallOptions”type CallOptions = { timeout?: number; fields?: string[];};ValidationResult
Section titled “ValidationResult”type ValidationResult = { valid: boolean; errors: string[]; warnings: string[]; tool?: { name: string; annotations?: Record<string, unknown> };};TaskHandle
Section titled “TaskHandle”type TaskHandle = { taskId: string; server: string; status: string };Exported types
Section titled “Exported types”The following types are available as named exports from the muxed package:
Tool, Resource, Prompt, ServerState, ServerConfig, DaemonStatus, ReloadResult, TaskHandle, ValidationResult, MuxedError
Type generation with muxed typegen
Section titled “Type generation with muxed typegen”Run muxed typegen to generate TypeScript types from your live MCP tool schemas:
muxed typegenThis generates muxed.generated.d.ts in node_modules/muxed/ using module augmentation on the MuxedToolMap interface. After running typegen:
call()gets autocomplete on tool names- Arguments are typed based on the tool’s
inputSchema - Results are typed based on the tool’s
outputSchema(when available) - Tool and property descriptions become JSDoc comments
- Unknown tools fall back to untyped
CallResult
Uses json-schema-to-typescript for schema conversion. Refresh with muxed typegen when tools change — same workflow as prisma generate.
Error handling
Section titled “Error handling”import { createClient, MuxedError } from 'muxed';
const client = await createClient();try { await client.call('server/nonexistent-tool');} catch (err) { if (err instanceof MuxedError) { console.error(`RPC error ${err.code}: ${err.message}`); // err.data contains structured error info const data = err.data as { code: string; suggestion: string; context?: Record<string, unknown> }; console.error(`Error code: ${data.code}`); // e.g. "TOOL_NOT_FOUND" console.error(`Suggestion: ${data.suggestion}`); // e.g. "Did you mean: server/similar_tool?" if (data.context?.similarTools) { console.error(`Similar tools: ${(data.context.similarTools as string[]).join(', ')}`); } }}MuxedError is thrown for JSON-RPC errors (tool not found, server not found, etc.). Standard Error is thrown for transport failures.
Structured error codes
Section titled “Structured error codes”All errors include a machine-readable code in err.data:
| Code | Description |
|---|---|
TOOL_NOT_FOUND | Tool doesn’t exist (includes fuzzy-matched similar tool names) |
SERVER_NOT_FOUND | Server doesn’t exist (includes available server names) |
SERVER_NOT_CONNECTED | Server exists but isn’t connected |
INVALID_FORMAT | Tool name is not in server/tool format |
MISSING_PARAMETER | Required parameter not provided |
INVALID_ARGUMENTS | Arguments failed schema validation |
TIMEOUT | Tool call exceeded timeout |
Usage examples
Section titled “Usage examples”List tools and call one
Section titled “List tools and call one”const client = await createClient();const tools = await client.tools();console.log(`Found ${tools.length} tools`);
const result = await client.call('filesystem/read_file', { path: '/etc/hostname' });console.log(result.content[0]?.text);client.close();Search and invoke
Section titled “Search and invoke”const client = await createClient();const matches = await client.grep('search');for (const { server, tool } of matches) { console.log(`${server}/${tool.name}: ${tool.description}`);}Parallel calls
Section titled “Parallel calls”const client = await createClient();const [users, tickets] = await Promise.all([ client.call('posthog/query-run', { query: { kind: 'HogQLQuery', query: 'SELECT ...' } }), client.call('intercom/search-conversations', { query: 'billing', limit: 10 }),]);Async tasks
Section titled “Async tasks”const client = await createClient();const handle = await client.callAsync('server/long-running-tool', { input: 'data' });
let status = await client.task(handle.server, handle.taskId);while (status.status !== 'completed' && status.status !== 'failed') { await new Promise(r => setTimeout(r, 1000)); status = await client.task(handle.server, handle.taskId);}
const result = await client.taskResult(handle.server, handle.taskId);