@orchestree/mcp-sdk
v1.0.0
Published
MCP (Model Context Protocol) server SDK for Orchestree
Maintainers
Readme
@orchestree/mcp-sdk
A production-grade SDK for building servers that implement the Model Context Protocol (MCP). Enable AI models to safely interact with your tools, data sources, and business logic.
Overview
The MCP SDK provides everything you need to expose tools, resources, and prompts to AI models via the Model Context Protocol. Whether you're building a simple tool server or a complex enterprise application, this SDK handles the protocol details so you can focus on your business logic.
Features
- Tool Registration: Define tools that AI models can call with proper validation
- Resource Management: Expose files, databases, and APIs as standardized resources
- Prompt Templates: Create reusable prompts with customizable arguments
- Multiple Transports: Support for stdio, HTTP, and Server-Sent Events (SSE)
- MCP Protocol Compliance: Full implementation of MCP v2024-11-05 specification
- Event System: Built-in events for monitoring and debugging
- Type Safety: Complete TypeScript definitions included
- Error Handling: Proper error propagation and validation
Installation
npm install @orchestree/mcp-sdkQuick Start
Basic Tool Server
const { McpServer } = require('@orchestree/mcp-sdk');
const server = new McpServer({
name: 'my-tools-server',
version: '1.0.0'
});
// Register a simple tool
server.registerTool('get_weather', {
description: 'Get current weather for a location',
parameters: {
properties: {
location: { type: 'string' },
units: { type: 'string', enum: ['celsius', 'fahrenheit'] }
},
required: ['location']
},
handler: async (args) => {
const { location, units = 'celsius' } = args;
// Your weather logic here
return {
location,
temperature: 22,
units,
conditions: 'Partly cloudy'
};
}
});
// Start the server
server.start({ transport: 'stdio' });Resource Provider
server.registerResource('file://config.json', {
description: 'Application configuration',
mimeType: 'application/json',
handler: async () => {
return {
apiUrl: 'https://api.example.com',
timeout: 5000,
retries: 3
};
}
});Prompt Templates
server.registerPrompt('code_review', {
description: 'Generates a code review prompt',
arguments: [
{
name: 'language',
description: 'Programming language',
required: true
},
{
name: 'focus',
description: 'Review focus area (security, performance, style)',
required: false
}
],
handler: async (args) => {
const { language, focus = 'style' } = args;
return `Review this ${language} code for ${focus} issues:\n\n{code}`;
}
});API Reference
McpServer
Constructor
new McpServer(config)Parameters:
config.name(string, required): Server nameconfig.version(string): Server version (default: "1.0.0")config.modules(string[]): List of module names
registerTool(name, definition)
Register a callable tool.
Parameters:
name(string): Tool namedefinition(object):description(string, required): What the tool doesparameters(object): JSON Schema for input validationproperties(object): Parameter definitionsrequired(string[]): Required parameter names
handler(function, required): Async or sync handler functionmetadata(object): Optional metadata
Returns: The server instance (for chaining)
Example:
server.registerTool('add_numbers', {
description: 'Add two numbers together',
parameters: {
properties: {
a: { type: 'number' },
b: { type: 'number' }
},
required: ['a', 'b']
},
handler: async (args) => args.a + args.b
});registerResource(uri, definition)
Register a readable resource.
Parameters:
uri(string): Resource URI (e.g., "file://config.json")definition(object):description(string, required): Resource descriptionname(string): Display namemimeType(string): MIME type (default: "text/plain")handler(function, required): Async or sync handler that returns contentmetadata(object): Optional metadata
Returns: The server instance (for chaining)
Example:
server.registerResource('database://users', {
description: 'User database connection',
mimeType: 'application/json',
handler: async () => {
const users = await db.getUsers();
return users;
}
});registerPrompt(name, definition)
Register a prompt template.
Parameters:
name(string): Prompt namedefinition(object):description(string, required): Prompt descriptionarguments(array): Prompt argumentsname(string): Argument namedescription(string): Argument descriptionrequired(boolean): Whether required
handler(function, required): Handler that generates promptmetadata(object): Optional metadata
Returns: The server instance (for chaining)
listTools()
Get all registered tools.
Returns: Array of tool definitions
listResources()
Get all registered resources.
Returns: Array of resource definitions
listPrompts()
Get all registered prompts.
Returns: Array of prompt definitions
callTool(name, args)
Execute a registered tool.
Parameters:
name(string): Tool nameargs(object): Tool arguments
Returns: Promise resolving to tool result
readResource(uri)
Read a registered resource.
Parameters:
uri(string): Resource URI
Returns: Promise resolving to resource content
getPrompt(name, args)
Get a prompt with resolved arguments.
Parameters:
name(string): Prompt nameargs(object): Prompt arguments
Returns: Promise resolving to prompt content
start(config)
Start the MCP server.
Parameters:
config(object):transport('stdio' | 'sse' | 'http'): Transport type (default: 'stdio')host(string): Host to bind to (default: 'localhost')port(number): Port to bind to (default: 3000)
Returns: Promise that resolves when server starts
Example:
// Start with stdio transport
await server.start({ transport: 'stdio' });
// Start with HTTP
await server.start({ transport: 'http', host: 'localhost', port: 3000 });
// Start with Server-Sent Events
await server.start({ transport: 'sse', host: '0.0.0.0', port: 8080 });stop()
Stop the running server.
Returns: Promise that resolves when server stops
isRunning()
Check if the server is running.
Returns: boolean
Events
The McpServer extends EventEmitter and emits the following events:
server:started- Server has startedserver:stopped- Server has stoppedserver:error- Server error occurredtool:registered- Tool was registeredtool:executed- Tool was executedtool:error- Tool execution failedresource:registered- Resource was registeredresource:read- Resource was readresource:error- Resource read failedprompt:registered- Prompt was registeredprompt:generated- Prompt was generatedprompt:error- Prompt generation failed
Example:
server.on('tool:executed', (data) => {
console.log(`Tool "${data.name}" returned:`, data.result);
});
server.on('tool:error', (data) => {
console.error(`Tool "${data.name}" failed:`, data.error);
});Utils
Utility functions for building MCP servers:
Utils.textResponse(text)
Create a text response for tools.
handler: async (args) => {
return Utils.textResponse('Success!');
}Utils.imageResponse(base64Data, mimeType)
Create an image response for tools.
handler: async (args) => {
const imageData = await generateImage(args.prompt);
return Utils.imageResponse(imageData, 'image/png');
}Utils.validateParameters(args, schema)
Validate tool parameters against a schema.
const validation = Utils.validateParameters(
{ a: 5, b: 'invalid' },
{
properties: {
a: { type: 'number' },
b: { type: 'number' }
},
required: ['a', 'b']
}
);
if (!validation.valid) {
console.error('Validation errors:', validation.errors);
}Complete Example
const { McpServer, Utils } = require('@orchestree/mcp-sdk');
const server = new McpServer({
name: 'example-server',
version: '1.0.0'
});
// Tool: Calculator
server.registerTool('calculate', {
description: 'Perform basic arithmetic operations',
parameters: {
properties: {
operation: { type: 'string', enum: ['add', 'subtract', 'multiply', 'divide'] },
a: { type: 'number' },
b: { type: 'number' }
},
required: ['operation', 'a', 'b']
},
handler: async (args) => {
const { operation, a, b } = args;
let result;
switch (operation) {
case 'add':
result = a + b;
break;
case 'subtract':
result = a - b;
break;
case 'multiply':
result = a * b;
break;
case 'divide':
if (b === 0) throw new Error('Division by zero');
result = a / b;
break;
default:
throw new Error(`Unknown operation: ${operation}`);
}
return Utils.textResponse(`${a} ${operation} ${b} = ${result}`);
}
});
// Resource: Math documentation
server.registerResource('docs://math-operations', {
description: 'Documentation for available math operations',
mimeType: 'text/markdown',
handler: async () => {
return `# Math Operations\n\n- **add**: Add two numbers\n- **subtract**: Subtract two numbers\n- **multiply**: Multiply two numbers\n- **divide**: Divide two numbers`;
}
});
// Prompt: Generate math problem
server.registerPrompt('generate_problem', {
description: 'Generate a math problem for practice',
arguments: [
{
name: 'difficulty',
description: 'Difficulty level (easy, medium, hard)',
required: true
}
],
handler: async (args) => {
const { difficulty } = args;
return `Generate a ${difficulty} math problem for the user to solve.`;
}
});
// Event handling
server.on('tool:executed', (data) => {
console.log(`[Tool] ${data.name} executed`);
});
server.on('tool:error', (data) => {
console.error(`[Tool Error] ${data.name}: ${data.error.message}`);
});
// Start the server
server.start({ transport: 'stdio' }).catch(console.error);
// Graceful shutdown
process.on('SIGTERM', () => {
server.stop().then(() => {
console.log('Server stopped');
process.exit(0);
});
});Transport Protocols
Stdio (Default)
JSON-RPC messages over standard input/output. Best for local integration.
await server.start({ transport: 'stdio' });HTTP
RESTful HTTP endpoint for MCP messages.
await server.start({
transport: 'http',
host: 'localhost',
port: 3000
});POST JSON-RPC messages to http://localhost:3000/
Server-Sent Events (SSE)
Bidirectional communication using HTTP and SSE. Best for web integration.
await server.start({
transport: 'sse',
host: 'localhost',
port: 3000
});Connect to http://localhost:3000/sse for events.
Error Handling
The SDK provides comprehensive error handling:
server.on('tool:error', (data) => {
const { name, args, error } = data;
console.error(`Tool ${name} failed with:`, error.message);
// Log, alert, or recover
});
server.on('resource:error', (data) => {
const { uri, error } = data;
console.error(`Resource ${uri} failed with:`, error.message);
});
server.on('server:error', (error) => {
console.error('Server error:', error.message);
// Restart, fallback, or shutdown
});Best Practices
- Validate Input: Use the
parametersschema to describe expected inputs - Handle Errors: Always use try-catch in handlers or return error responses
- Be Descriptive: Write clear descriptions for tools, resources, and prompts
- Monitor Events: Listen to server events for debugging and monitoring
- Use TypeScript: Leverage the included type definitions
- Test Thoroughly: Test your server with various inputs and error conditions
- Document APIs: Keep documentation of your tools and resources updated
- Handle Cleanup: Implement proper shutdown procedures
MCP Protocol Compliance
This SDK implements the Model Context Protocol v2024-11-05 specification, including:
- ✓ Tool definition and execution
- ✓ Resource provisioning
- ✓ Prompt templates
- ✓ Server initialization
- ✓ JSON-RPC 2.0 messaging
- ✓ Multiple transport protocols
Troubleshooting
Server won't start
Ensure the port is available and you have permission to bind to it:
lsof -i :3000 # Check port usageHandler timeout
Set appropriate timeouts for long-running operations:
handler: async (args) => {
const result = await Promise.race([
longOperation(args),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), 5000)
)
]);
return result;
}Type mismatches
Use TypeScript with the included type definitions:
import { McpServer, ToolRegistration } from '@orchestree/mcp-sdk';
const toolDef: ToolRegistration = {
description: 'My tool',
handler: async (args) => 'result'
};License
MIT - See LICENSE file
Support
For issues, questions, or contributions:
- GitHub: https://github.com/orchestree/orchestree
- Docs: https://orchestree.ai/developer/mcp-sdk
- Community: https://discord.gg/orchestree
