Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/mcp-use/mcp-use/llms.txt

Use this file to discover all available pages before exploring further.

Overview

MCPClient supports multiple transport protocols for connecting to MCP servers. The client automatically selects the appropriate connector based on your configuration and handles connection lifecycle, retries, and fallbacks.

Transport Types

The mcp-use client supports three main transport types:

Stdio

Process-based communication via stdin/stdout. Best for local Node.js servers.

HTTP

Streamable HTTP with automatic SSE fallback. Best for remote servers.

WebSocket

Bidirectional streaming (browser-only).

Stdio Connector

The StdioConnector spawns a local process and communicates via standard input/output streams. This is the most efficient method for local servers.

Configuration

mcp-config.json
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
      "env": {
        "DEBUG": "mcp:*",
        "NODE_ENV": "production"
      }
    }
  }
}

How It Works

  1. Process Spawn (src/connectors/stdio.ts:49): Client spawns the command with provided args
  2. Stream Setup: Creates bidirectional stdio transport
  3. MCP Handshake: Performs initialization protocol
  4. Ready: Session is ready for tool calls
import { MCPClient } from 'mcp-use';

const client = new MCPClient({
  mcpServers: {
    'python-server': {
      command: 'python',
      args: ['server.py'],
      env: {
        PYTHONPATH: '/app/lib',
        LOG_LEVEL: 'INFO'
      }
    },
    'node-server': {
      command: 'node',
      args: ['dist/server.js', '--port', '3000']
    }
  }
});

const session = await client.createSession('python-server');
console.log('Connected via stdio');

Stdio Options

command
string
required
Executable command. Can be absolute path or PATH-resolved binary.
"command": "npx"  // or "node", "python", "/usr/bin/python3"
args
string[]
required
Command line arguments passed to the process.
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/data"]
env
Record<string, string>
Environment variables. Merged with process.env (src/connectors/stdio.ts:60).
"env": {
  "DEBUG": "*",
  "API_KEY": "secret"
}

Stdio Best Practices

Launch npm-published MCP servers easily:
{
  "command": "npx",
  "args": ["-y", "@modelcontextprotocol/server-filesystem", "/home"]
}
Always close sessions to terminate child processes:
const session = await client.createSession('my-server');
try {
  // Use session...
} finally {
  await client.closeSession('my-server'); // Kills process
}
Server logs go to stderr by default:
import { StdioConnector } from 'mcp-use';
import { Writable } from 'stream';

const logStream = new Writable({
  write(chunk, encoding, callback) {
    console.log('[SERVER]', chunk.toString());
    callback();
  }
});

const connector = new StdioConnector({
  command: 'node',
  args: ['server.js'],
  errlog: logStream
});

HTTP Connector

The HttpConnector communicates with remote MCP servers over HTTP. It automatically tries streamable HTTP first, then falls back to SSE (Server-Sent Events) for maximum compatibility.

Configuration

mcp-config.json
{
  "mcpServers": {
    "brave-search": {
      "url": "https://mcp.brave.com/mcp",
      "authToken": "${BRAVE_API_KEY}",
      "preferSse": false,
      "headers": {
        "X-Client-ID": "my-app"
      }
    }
  }
}

Transport Selection

The HttpConnector follows this connection flow (src/connectors/http.ts:185):

Streamable HTTP vs SSE

Streamable HTTP (src/connectors/http.ts:276):
  • Uses HTTP POST for requests and responses
  • Lower latency for request/response patterns
  • Requires server support for mcp-session-id header
  • Automatically extracts session ID from initialize response
SSE (Server-Sent Events) (src/connectors/http.ts:418):
  • Uses HTTP POST + EventSource for streaming
  • Better compatibility with existing HTTP servers
  • Fallback when streamable HTTP is not available
  • Works with FastMCP and other SSE-based servers

HTTP Options

url
string
required
Base URL of the MCP server endpoint.
"url": "https://api.example.com/mcp"
authToken
string
Bearer token for authentication. Added as Authorization: Bearer <token> header.
"authToken": "sk-1234567890abcdef"
headers
Record<string, string>
Additional HTTP headers for all requests.
"headers": {
  "X-API-Key": "key",
  "X-Client-Version": "1.0.0"
}
preferSse
boolean
Force SSE transport instead of trying streamable HTTP first. Default: false.
"preferSse": true  // Skip streamable HTTP attempt
disableSseFallback
boolean
Disable automatic SSE fallback when streamable HTTP fails. Default: false.
"disableSseFallback": true  // Fail if streamable HTTP doesn't work
transport
'http' | 'sse'
Explicit transport selection. Default: "http" with auto-fallback.
fetch
typeof fetch
Custom fetch implementation for proxying or testing.
import { MCPClient } from 'mcp-use';

const client = new MCPClient({
  mcpServers: {
    'api': {
      url: 'https://api.example.com/mcp',
      fetch: async (url, init) => {
        console.log('Fetching:', url);
        return fetch(url, init);
      }
    }
  }
});

Authentication

Bearer Token

Simplest method for API keys:
const client = new MCPClient({
  mcpServers: {
    'api': {
      url: 'https://api.example.com/mcp',
      authToken: process.env.API_TOKEN
    }
  }
});

OAuth

For OAuth-based servers (src/connectors/http.ts:424):
const client = new MCPClient({
  mcpServers: {
    'github': {
      url: 'https://mcp.github.com/mcp',
      authProvider: {
        type: 'oauth',
        serverUrl: 'https://oauth.github.com',
        clientId: process.env.GITHUB_CLIENT_ID,
        clientSecret: process.env.GITHUB_CLIENT_SECRET,
        scopes: ['repo', 'user'],
        redirectUri: 'http://localhost:3000/callback'
      }
    }
  }
});

try {
  const session = await client.createSession('github');
} catch (error) {
  if (error.code === 401) {
    console.error('OAuth authentication required');
    // Implement OAuth flow
  }
}

Custom Headers

For API key authentication:
const client = new MCPClient({
  mcpServers: {
    'api': {
      url: 'https://api.example.com/mcp',
      headers: {
        'X-API-Key': process.env.API_KEY,
        'X-Client-ID': 'my-app'
      }
    }
  }
});

Error Handling

import { MCPClient } from 'mcp-use';

const client = new MCPClient({
  mcpServers: {
    'remote': { url: 'https://api.example.com/mcp' }
  }
});

try {
  const session = await client.createSession('remote');
  console.log('Connected via:', session.connector.getTransportType());
} catch (error: any) {
  if (error.code === 401) {
    console.error('Authentication required');
  } else if (error.code === 404) {
    console.error('Server endpoint not found');
  } else if (error.message?.includes('SSE fallback')) {
    console.error('Streamable HTTP and SSE both failed');
  } else {
    console.error('Connection failed:', error.message);
  }
}

HTTP Best Practices

Don’t disable SSE fallback unless you’re sure the server supports streamable HTTP:
// Good: Automatic fallback
{ url: 'https://api.example.com/mcp' }

// Risky: Fails if streamable HTTP not supported
{ url: 'https://api.example.com/mcp', disableSseFallback: true }
Skip the streamable HTTP attempt for servers you know use SSE:
{
  url: 'https://fastmcp-server.com/mcp',
  preferSse: true  // FastMCP uses SSE
}
Properly handle 401 responses:
try {
  await client.createSession('api');
} catch (error: any) {
  if (error.code === 401) {
    // Refresh token or re-authenticate
    await refreshAuthentication();
    await client.createSession('api');
  }
}
Know which transport succeeded:
const session = await client.createSession('api');
const transport = session.connector.getTransportType();
console.log(`Connected via: ${transport}`);
// "streamable-http" or "sse"

Connection Lifecycle

Creating Sessions

import { MCPClient } from 'mcp-use';

const client = new MCPClient('./mcp-config.json');

// Create single session (auto-initializes)
const session1 = await client.createSession('server1');

// Create without auto-initialization
const session2 = await client.createSession('server2', false);
await session2.connect();
await session2.initialize();

// Create all configured sessions
const sessions = await client.createAllSessions();

Connection States

Each session goes through these states (src/session.ts:55):
  1. Created: Session object exists but not connected
  2. Connecting: Establishing transport connection
  3. Connected: Transport ready, performing MCP handshake
  4. Initialized: Ready for operations
  5. Disconnected: Connection closed
const session = new MCPSession(connector, false);

console.log(session.isConnected); // false

await session.connect();
console.log(session.isConnected); // true

await session.initialize();
console.log('Ready for operations');

await session.disconnect();
console.log(session.isConnected); // false

Graceful Shutdown

import { MCPClient } from 'mcp-use';

const client = new MCPClient('./config.json');

try {
  await client.createAllSessions();
  
  // Use client...
  
} finally {
  // Always cleanup
  await client.close(); // Closes executors and all sessions
}

// Or in shutdown handler
process.on('SIGINT', async () => {
  console.log('Shutting down...');
  await client.close();
  process.exit(0);
});

Connection Examples

Multi-Transport Setup

import { MCPClient } from 'mcp-use';

const client = new MCPClient({
  mcpServers: {
    // Local stdio servers
    'filesystem': {
      command: 'npx',
      args: ['-y', '@modelcontextprotocol/server-filesystem', '/data']
    },
    'postgres': {
      command: 'npx',
      args: ['-y', '@modelcontextprotocol/server-postgres'],
      env: { DATABASE_URL: process.env.DATABASE_URL }
    },
    
    // Remote HTTP servers
    'brave-search': {
      url: 'https://mcp.brave.com/mcp',
      authToken: process.env.BRAVE_API_KEY
    },
    'anthropic': {
      url: 'https://api.anthropic.com/mcp',
      headers: {
        'X-API-Key': process.env.ANTHROPIC_API_KEY
      },
      preferSse: true
    }
  }
});

// Create all sessions
const sessions = await client.createAllSessions();
console.log(`Connected to ${Object.keys(sessions).length} servers`);

Connection with Retry

import { MCPClient } from 'mcp-use';

const client = new MCPClient('./config.json');

async function connectWithRetry(
  serverName: string,
  maxRetries: number = 3
): Promise<MCPSession | null> {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const session = await client.createSession(serverName);
      console.log(`Connected to ${serverName}`);
      return session;
    } catch (error) {
      console.error(`Attempt ${i + 1} failed:`, error.message);
      if (i < maxRetries - 1) {
        await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
      }
    }
  }
  return null;
}

const session = await connectWithRetry('my-server');
if (!session) {
  console.error('Failed to connect after retries');
}

Conditional Connection

import { MCPClient } from 'mcp-use';

const client = new MCPClient('./config.json');

const results = await Promise.allSettled(
  client.getServerNames().map(name =>
    client.createSession(name)
  )
);

const connected = results
  .filter(r => r.status === 'fulfilled')
  .map(r => (r as PromiseFulfilledResult<MCPSession>).value);

const failed = results
  .filter(r => r.status === 'rejected')
  .map(r => (r as PromiseRejectedResult).reason);

console.log(`Connected: ${connected.length}`);
console.log(`Failed: ${failed.length}`);

Next Steps

Sessions

Learn about session management and operations

Configuration

Master configuration options and formats

Build docs developers (and LLMs) love