npm package: @portel/mcp
Description: MCP protocol utilities - client, transport, elicitation
Author: Portel
Latest version: 1.0.1

# @portel/mcp

MCP (Model Context Protocol) client library for connecting to and interacting with MCP servers. Provides transport abstraction, configuration management, and user elicitation utilities.

## Part of the Portel Ecosystem

```
┌─────────────────────────────────────────────────────────────────┐
│                        @portel/cli                              │
│            CLI utilities: formatting, progress, logging         │
└─────────────────────────────────────────────────────────────────┘
                              ▲
                              │
┌─────────────────────────────────────────────────────────────────┐
│                  @portel/mcp (this package)                     │
│              MCP protocol: client, transport, config            │
└─────────────────────────────────────────────────────────────────┘
                              ▲
                              │
┌─────────────────────────────────────────────────────────────────┐
│                     @portel/photon-core                         │
│         Core library: schema extraction, generators, UI         │
└─────────────────────────────────────────────────────────────────┘
                              ▲
                              │
        ┌─────────────────────┼─────────────────────┐
        │                     │                     │
┌───────┴───────┐    ┌───────┴───────┐    ┌───────┴───────┐
│ @portel/photon│    │    lumina     │    │ @portel/ncp   │
│  CLI + BEAM   │    │  REST runtime │    │ MCP orchestr. │
└───────────────┘    └───────────────┘    └───────────────┘
```

**Use this package if:** You're building tools that need to connect to MCP servers, call MCP tools, or manage MCP server configurations.

## Installation

```bash
npm install @portel/mcp
```

## Features

### MCP Client

Connect to MCP servers and call tools.

```typescript
import { MCPClient, SDKMCPClientFactory } from '@portel/mcp';

// Create client factory
const factory = new SDKMCPClientFactory();

// Connect to an MCP server
const client = await factory.create({
  command: 'npx',
  args: ['-y', '@anthropic/weather-mcp'],
});

// List available tools
const tools = await client.listTools();
console.log(tools);

// Call a tool
const result = await client.callTool('get-weather', { city: 'London' });
console.log(result);

// Disconnect when done
await client.disconnect();
```

### MCP Proxy

Create a proxy object that maps tool calls to method calls.

```typescript
import { createMCPProxy, SDKMCPClientFactory } from '@portel/mcp';

const factory = new SDKMCPClientFactory();
const client = await factory.create(config);

// Create proxy - tool names become methods
const mcp = createMCPProxy(client);

// Call tools as methods
const weather = await mcp.getWeather({ city: 'Tokyo' });
const forecast = await mcp.getForecast({ days: 5 });
```

### Configuration Management

Load and save MCP server configurations (Claude Desktop format).

```typescript
import {
  loadPhotonMCPConfig,
  savePhotonMCPConfig,
  getMCPServerConfig,
  setMCPServerConfig,
  listMCPServers,
} from '@portel/mcp';

// Load config from ~/.photon/mcp-servers.json
const config = loadPhotonMCPConfig();

// List configured servers
const servers = listMCPServers();
// => ['weather', 'database', 'github']

// Get specific server config
const weatherConfig = getMCPServerConfig('weather');

// Add/update a server
setMCPServerConfig('my-server', {
  command: 'node',
  args: ['./my-server.js'],
  env: { API_KEY: '${MY_API_KEY}' },
});

// Save changes
savePhotonMCPConfig(config);
```

### User Elicitation

Prompt users for input during tool execution.

```typescript
import { prompt, confirm, elicit, setElicitHandler } from '@portel/mcp';

// Simple prompts
const name = await prompt('What is your name?');
const proceed = await confirm('Continue?');

// Rich elicitation with schema
const result = await elicit({
  message: 'Configure settings',
  schema: {
    type: 'object',
    properties: {
      theme: { type: 'string', enum: ['light', 'dark'] },
      fontSize: { type: 'number', minimum: 8, maximum: 24 },
    },
  },
});

// Custom handler (for different UIs)
setElicitHandler(async (options) => {
  // Custom UI implementation
  return { action: 'submit', data: formData };
});
```

## API Reference

### MCP Client

| Export | Description |
|--------|-------------|
| `MCPClient` | Core MCP client class |
| `MCPClientFactory` | Factory interface for creating clients |
| `SDKMCPClientFactory` | Factory using @modelcontextprotocol/sdk |
| `createMCPProxy(client)` | Create proxy for tool-as-method calls |
| `MCPError` | Base error class |
| `MCPNotConnectedError` | Client not connected error |
| `MCPToolError` | Tool execution error |

### Configuration

| Export | Description |
|--------|-------------|
| `loadPhotonMCPConfig()` | Load config from ~/.photon |
| `savePhotonMCPConfig(config)` | Save config to ~/.photon |
| `getMCPServerConfig(name)` | Get server config by name |
| `setMCPServerConfig(name, config)` | Add/update server config |
| `removeMCPServerConfig(name)` | Remove server config |
| `listMCPServers()` | List all configured servers |
| `isMCPConfigured(name)` | Check if server is configured |
| `resolveEnvVars(config)` | Resolve ${VAR} in config |

### Elicitation

| Export | Description |
|--------|-------------|
| `prompt(message)` | Simple text prompt |
| `confirm(message)` | Yes/no confirmation |
| `elicit(options)` | Rich form elicitation |
| `setPromptHandler(handler)` | Set custom prompt handler |
| `setElicitHandler(handler)` | Set custom elicit handler |
| `elicitReadline` | Readline-based handler |
| `elicitNativeDialog` | Native dialog handler |

### Types

```typescript
interface MCPServerConfig {
  command: string;
  args?: string[];
  env?: Record<string, string>;
}

interface MCPToolInfo {
  name: string;
  description?: string;
  inputSchema?: object;
}

interface MCPToolResult {
  content: Array<{ type: string; text?: string }>;
  isError?: boolean;
}

interface ElicitOptions {
  message: string;
  schema?: object;
  requestedFields?: string[];
}

interface ElicitResult {
  action: 'submit' | 'cancel' | 'skip';
  data?: Record<string, any>;
}
```

## License

MIT