mcpd-sdk-javascript is a TypeScript/JavaScript SDK for interacting with the mcpd application.
A daemon that exposes MCP server tools via a simple HTTP API.
This SDK provides high-level and dynamic access to those tools, making it easy to integrate with scripts, applications, or agentic frameworks.
- Discover and list available
mcpdhosted MCP servers - Retrieve tool, prompt, and resource definitions from individual servers
- Dynamically invoke any tool using a clean, attribute-based syntax
- Unified AI framework integration - works directly with LangChain JS and Vercel AI SDK via
getAgentTools() - Generate self-contained, framework-compatible tool functions without conversion layers
- Multiple output formats (
'array','object','map') for different framework needs - Full TypeScript support with comprehensive type definitions and overloads
- Minimal dependencies (
lru-cachefor caching,zodfor schema validation) - Works in both Node.js and browser environments
- Clean API wrapper over mcpd HTTP endpoints - no opinionated aggregation logic
npm install @mozilla-ai/mcpd
# or
yarn add @mozilla-ai/mcpd
# or
pnpm add @mozilla-ai/mcpdNote: This SDK works seamlessly with both JavaScript and TypeScript. TypeScript users automatically get full type safety and autocomplete via the included
.d.tstype definitions—no additional setup required.
const { McpdClient, McpdError } = require("@mozilla-ai/mcpd");
const client = new McpdClient({
apiEndpoint: "http://localhost:8090",
});
// List available servers
const servers = await client.listServers();
console.log(servers);
// Example: ['time', 'fetch', 'git']
// List tool definitions for a specific server
const tools = await client.servers.time.getTools();
console.log(tools);
// Dynamically call a tool via the .tools namespace
try {
const result = await client.servers.time.tools.get_current_time({
timezone: "UTC",
});
console.log(result);
} catch (error) {
if (error instanceof McpdError) {
console.error("Error:", error.message);
}
}import { McpdClient, McpdError, Tool } from "@mozilla-ai/mcpd";
const client = new McpdClient({
apiEndpoint: "http://localhost:8090",
apiKey: "optional-key", // Optional API key
healthCacheTtl: 10, // Cache health checks for 10 seconds
serverCacheTtl: 60, // Cache server/tool metadata for 60 seconds
});
// Full type safety and autocomplete
const servers: string[] = await client.listServers();
// Get tools with proper typing
const tools: Tool[] = await client.servers.time.getTools();
// Dynamic tool invocation with error handling via .tools namespace
try {
const result = await client.servers.time.tools.get_current_time({
timezone: "UTC",
});
console.log(result);
} catch (error) {
if (error instanceof McpdError) {
console.error("Operation failed:", error.message);
}
}import { McpdClient } from "@mozilla-ai/mcpd";
// Initialize the client with your mcpd API endpoint
const client = new McpdClient({
apiEndpoint: "http://localhost:8090", // Required
apiKey: "optional-key", // Optional: API key for authentication
healthCacheTtl: 10, // Optional: TTL in seconds for health cache (default: 10)
serverCacheTtl: 60, // Optional: TTL in seconds for server/tools cache (default: 60)
timeout: 30000, // Optional: Request timeout in ms (default: 30000)
});Returns a list of all configured server names.
const servers = await client.listServers();
// Returns: ['time', 'fetch', 'git']Returns tool schemas for a specific server.
// Get tools for a specific server
const timeTools = await client.servers.time.getTools();
// Returns: [{ name: 'get_current_time', description: '...', inputSchema: {...} }]Dynamically invoke any tool using natural syntax via the .tools namespace. Tool names must match exactly as returned by the MCP server.
// Call a tool with parameters using property access (recommended)
const result = await client.servers.weather.tools.get_forecast({
city: "Tokyo",
days: 3,
});
// Call without parameters
const time = await client.servers.time.tools.get_current_time();Get all tools available on a specific server.
// List tools for a server using property access
const tools = await client.servers.time.getTools();
for (const tool of tools) {
console.log(`${tool.name}: ${tool.description}`);
}
// Useful in loops with dynamic server names
const servers = await client.listServers();
for (const serverName of servers) {
const tools = await client.servers[serverName].getTools();
console.log(`${serverName}: ${tools.length} tools`);
}Call a tool by name with the given arguments. This is useful for programmatic tool invocation when the tool name is in a variable.
// Call with dynamic tool name
const toolName = "get_current_time";
const result = await client.servers.time.callTool(toolName, {
timezone: "UTC",
});
// Using with dynamic server name too
const serverName = "time";
const result2 = await client.servers[serverName].callTool(toolName, {
timezone: "UTC",
});Check if a specific tool exists on a server. Tool names must match exactly as returned by the MCP server.
// Check if tool exists before calling it
if (await client.servers.time.hasTool("get_current_time")) {
const result = await client.servers.time.callTool("get_current_time", {
timezone: "UTC",
});
}
// Using with dynamic server names
const serverName = "time";
if (await client.servers[serverName].hasTool("get_current_time")) {
const result = await client.servers[serverName].tools.get_current_time();
}Returns prompt schemas for a specific server.
// Get prompts for a specific server
const githubPrompts = await client.servers.github.getPrompts();
// Returns: [{ name: 'create_pr', description: '...', arguments: [...] }]Dynamically generate any prompt using natural syntax via the .prompts namespace. Prompt names must match exactly as returned by the MCP server.
// Generate a prompt with parameters using property access (recommended)
const result = await client.servers.github.prompts.create_pr({
title: "Fix bug",
description: "Fixed authentication issue",
});
// Generate without parameters (if prompt has no required args)
const result = await client.servers.templates.prompts.default_template();Generate a prompt by name with the given arguments. This is useful for programmatic prompt generation when the prompt name is in a variable.
// Generate with dynamic prompt name
const promptName = "create_pr";
const result = await client.servers.github.generatePrompt(promptName, {
title: "Fix bug",
description: "Fixed authentication issue",
});
// Using with dynamic server name too
const serverName = "github";
const result2 = await client.servers[serverName].generatePrompt(promptName, {
title: "Fix bug",
});Check if a specific prompt exists on a server. Prompt names must match exactly as returned by the MCP server.
// Check if prompt exists before generating it
if (await client.servers.github.hasPrompt("create_pr")) {
const result = await client.servers.github.generatePrompt("create_pr", {
title: "Fix bug",
});
}
// Using with dynamic server names
const serverName = "github";
if (await client.servers[serverName].hasPrompt("create_pr")) {
const result = await client.servers[serverName].prompts.create_pr({
title: "Fix bug",
});
}Returns resource schemas for a specific server.
// Get resources for a specific server
const githubResources = await client.servers.github.getResources();
// Returns: [{ name: 'readme', uri: 'file:///repo/README.md', ... }]Returns resource template schemas for a specific server.
// Get resource templates for a specific server
const githubTemplates = await client.servers.github.getResourceTemplates();
// Returns: [{ name: 'file', uriTemplate: 'file:///{path}', ... }]Read resource content by URI from a specific server.
// Read resource content by URI
const contents = await client.servers.github.readResource(
"file:///repo/README.md",
);
for (const content of contents) {
if (content.text) {
console.log(content.text);
} else if (content.blob) {
console.log("Binary content (base64):", content.blob);
}
}Check if a specific resource exists on a server. Resource URIs must match exactly as returned by the MCP server.
// Check if resource exists before reading it
if (await client.servers.github.hasResource("file:///repo/README.md")) {
const contents = await client.servers.github.readResource(
"file:///repo/README.md",
);
}
// Using with dynamic server names
const serverName = "github";
if (await client.servers[serverName].hasResource("file:///repo/README.md")) {
const contents = await client.servers[serverName].readResource(
"file:///repo/README.md",
);
}Get health information for one or all servers.
// Get health for all servers
const allHealth = await client.getServerHealth();
// Returns: { time: { status: 'ok' }, fetch: { status: 'ok' } }
// Get health for specific server
const timeHealth = await client.getServerHealth("time");
// Returns: { status: 'ok' }Check if a specific server is healthy.
if (await client.isServerHealthy("time")) {
// Server is healthy, safe to use
const result = await client.servers.time.tools.get_current_time({
timezone: "UTC",
});
}Generate callable functions that work directly with AI agent frameworks. No conversion layers needed.
// Options: { servers?: string[], format?: 'array' | 'object' | 'map' }
// Default format is 'array' (for LangChain)
// Use with LangChain JS (array format is default)
import { ChatOpenAI } from "@langchain/openai";
const langchainTools = await client.getAgentTools({ format: "array" });
// Or simply: const langchainTools = await client.getAgentTools();
// Bind tools to model
const model = new ChatOpenAI({ modelName: "gpt-4o-mini" });
const modelWithTools = model.bindTools(langchainTools);
// Or use with agents
import { createOpenAIToolsAgent } from "langchain/agents";
const agent = await createOpenAIToolsAgent({
llm,
tools: langchainTools,
prompt,
});
// Use with Vercel AI SDK (expects object format)
import { generateText } from "ai";
const vercelTools = await client.getAgentTools({ format: "object" });
const result = await generateText({
model: openai("gpt-4o-mini"),
tools: vercelTools,
prompt: "What time is it in Tokyo?",
});
// Filter to specific servers
const timeTools = await client.getAgentTools({
servers: ["time"],
format: "array",
});
// Use with Map for efficient lookups
const toolMap = await client.getAgentTools({ format: "map" });
const timeTool = toolMap.get("time__get_current_time");
if (timeTool) {
const result = await timeTool({ timezone: "UTC" });
}
// Each function has metadata for both frameworks
const tools = await client.getAgentTools();
for (const tool of tools) {
console.log(`${tool.name}: ${tool.description}`);
console.log(`Server: ${tool._serverName}, Tool: ${tool._toolName}`);
// LangChain properties: tool.schema, tool.invoke, tool.lc_namespace
// Vercel AI properties: tool.inputSchema, tool.execute
}Clear the cache of generated agent tools functions.
// Clear cache to regenerate tools with latest schemas
client.clearAgentToolsCache();
const freshTools = await client.getAgentTools();Clear the server health cache, forcing fresh health checks on next call.
// Force fresh health check
client.clearServerHealthCache();
const health = await client.getServerHealth("time");The SDK provides a comprehensive error hierarchy for different failure scenarios:
import {
McpdError, // Base error class
ConnectionError, // Cannot connect to mcpd daemon
AuthenticationError, // Auth failed (invalid API key)
ServerNotFoundError, // Server doesn't exist
ServerUnhealthyError, // Server is unhealthy
ToolNotFoundError, // Tool doesn't exist
ToolExecutionError, // Tool execution failed
ValidationError, // Input validation failed
TimeoutError, // Operation timed out
} from "@mozilla-ai/mcpd";
try {
const result = await client.servers.unknown.tools.tool();
} catch (error) {
if (error instanceof ToolNotFoundError) {
console.error(
`Tool not found: ${error.toolName} on server ${error.serverName}`,
);
} else if (error instanceof ConnectionError) {
console.error("Cannot connect to mcpd daemon. Is it running?");
} else if (error instanceof McpdError) {
console.error("Operation failed:", error.message);
}
}# Clone the repository
git clone https://github.com/mozilla-ai/mcpd-sdk-javascript.git
cd mcpd-sdk-javascript
# Install dependencies
npm install# Build the project
npm run build
# Build in watch mode
npm run dev# Run tests
npm test
# Run tests with coverage
npm run test:coverage# Run all checks (format, lint, typecheck, test, build)
npm run check
# Run linter
npm run lint
# Fix linting issues
npm run lint:fix
# Format code
npm run format
# Check formatting
npm run format:checkApache-2.0
Please see CONTRIBUTING.md for details on how to contribute to this project.
- mcpd - The MCP daemon this SDK connects to
- mcpd-sdk-python - Python version of this SDK