npm package: @orchestree/mcp-sdk
Description: MCP (Model Context Protocol) server SDK for Orchestree
Author: Orchestree
Latest version: 1.0.0

# @orchestree/mcp-sdk

A production-grade SDK for building servers that implement the [Model Context Protocol (MCP)](https://modelcontextprotocol.io). 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

```bash
npm install @orchestree/mcp-sdk
```

## Quick Start

### Basic Tool Server

```javascript
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

```javascript
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

```javascript
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

```javascript
new McpServer(config)
```

**Parameters:**
- `config.name` (string, required): Server name
- `config.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 name
- `definition` (object):
  - `description` (string, required): What the tool does
  - `parameters` (object): JSON Schema for input validation
    - `properties` (object): Parameter definitions
    - `required` (string[]): Required parameter names
  - `handler` (function, required): Async or sync handler function
  - `metadata` (object): Optional metadata

**Returns:** The server instance (for chaining)

**Example:**
```javascript
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 description
  - `name` (string): Display name
  - `mimeType` (string): MIME type (default: "text/plain")
  - `handler` (function, required): Async or sync handler that returns content
  - `metadata` (object): Optional metadata

**Returns:** The server instance (for chaining)

**Example:**
```javascript
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 name
- `definition` (object):
  - `description` (string, required): Prompt description
  - `arguments` (array): Prompt arguments
    - `name` (string): Argument name
    - `description` (string): Argument description
    - `required` (boolean): Whether required
  - `handler` (function, required): Handler that generates prompt
  - `metadata` (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 name
- `args` (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 name
- `args` (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:**
```javascript
// 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 started
- `server:stopped` - Server has stopped
- `server:error` - Server error occurred
- `tool:registered` - Tool was registered
- `tool:executed` - Tool was executed
- `tool:error` - Tool execution failed
- `resource:registered` - Resource was registered
- `resource:read` - Resource was read
- `resource:error` - Resource read failed
- `prompt:registered` - Prompt was registered
- `prompt:generated` - Prompt was generated
- `prompt:error` - Prompt generation failed

**Example:**
```javascript
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.

```javascript
handler: async (args) => {
  return Utils.textResponse('Success!');
}
```

#### Utils.imageResponse(base64Data, mimeType)

Create an image response for tools.

```javascript
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.

```javascript
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

```javascript
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.

```javascript
await server.start({ transport: 'stdio' });
```

### HTTP

RESTful HTTP endpoint for MCP messages.

```javascript
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.

```javascript
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:

```javascript
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

1. **Validate Input**: Use the `parameters` schema to describe expected inputs
2. **Handle Errors**: Always use try-catch in handlers or return error responses
3. **Be Descriptive**: Write clear descriptions for tools, resources, and prompts
4. **Monitor Events**: Listen to server events for debugging and monitoring
5. **Use TypeScript**: Leverage the included type definitions
6. **Test Thoroughly**: Test your server with various inputs and error conditions
7. **Document APIs**: Keep documentation of your tools and resources updated
8. **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:

```bash
lsof -i :3000  # Check port usage
```

### Handler timeout

Set appropriate timeouts for long-running operations:

```javascript
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:

```typescript
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