Transport Configuration
MCP servers can be accessed via different transport mechanisms. This guide covers all supported transport types and their configuration.
Table of Contents
- Transport Types
- Stdio (Local Server)
- HTTP (Remote Server)
- Multiple Transports
- Environment Variables
- Troubleshooting
Transport Types
@gleanwork/mcp-server-tester supports two transport types:
- stdio - Local server processes (via stdin/stdout)
- HTTP - Remote servers (via HTTP/SSE)
Choose based on your server deployment:
- Use stdio for local development and testing
- Use HTTP for remote servers or production environments
Evaluation client support
Plain stdio is supported by these built-in evaluation client families:
- Claude CLI (
claude-code) and Vercel AI SDK (api). - The ChatGPT desktop app's ChatGPT Work and Codex surfaces: the
chatgptandcodex-appclients. - Cowork (
cowork) on macOS and Linux. The package exportsCOWORK_STDIO_PLATFORMSas['darwin', 'linux'].
Plain stdio uses command, optional args, cwd, and declared env; it does
not require a URL or plugin. Cowork also supports private file-backed native
proxies and mixed HTTP/stdio sets. Its client-resolved fields (url, auth,
files, minTools, and placeholders) are not portable to ChatGPT or direct
MCP clients. ChatGPT plugin-specific overrides use plugins[].mcp instead.
Over HTTP, chatgpt and codex-app take a bearer token only: an HTTP server
with headers or OAuth fails before the app starts
(ChatGPT guide). Cowork takes headers and a bearer
token.
Cowork rejects inheritEnv: true; declare the server environment explicitly.
It implements cwd with a fixed argv wrapper, not shell-interpolated values.
Mac setup owns the private files and runtime paths; Linux setup checks
caller-staged paths. On Mac, only ${pluginRoot:...} resolution is unavailable
because marketplace installation paths are unknown before startup; native
proxies with known local paths remain supported. See the
Cowork contract and
ChatGPT guide.
Transport support does not enforce read-only tools. The caller's proxy policy must intercept writes where required; MST stdio transport alone does not.
Stdio (Local Server)
The stdio transport starts a local MCP server as a child process and communicates via standard input/output.
Basic Configuration
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'mcp-local',
use: {
mcpConfig: {
transport: 'stdio',
command: 'node',
args: ['path/to/server.js'],
},
},
},
],
});
Configuration Options
{
transport: 'stdio',
command: string, // Command to run (e.g., 'node', 'python', 'deno')
args?: string[], // Command arguments
env?: Record<string, string>, // Environment variables
capabilities?: { // MCP capabilities
roots?: { listChanged?: boolean },
sampling?: { ... },
},
protocol?: 'legacy' | 'auto' | string, // Protocol to speak (default: 'legacy'); see below
protocolProbe?: { timeoutMs?: number }, // Bounds the 'auto' probe
}
Debug Logging: Enable with
DEBUG=mcp-server-tester:* npm test
Examples
Node.js Server:
mcpConfig: {
transport: 'stdio',
command: 'node',
args: ['dist/server.js'],
}
TypeScript with ts-node:
mcpConfig: {
transport: 'stdio',
command: 'npx',
args: ['ts-node', 'src/server.ts'],
}
Python Server:
mcpConfig: {
transport: 'stdio',
command: 'python',
args: ['server.py'],
env: {
PYTHONPATH: '/path/to/modules',
},
}
Deno Server:
mcpConfig: {
transport: 'stdio',
command: 'deno',
args: ['run', '--allow-all', 'server.ts'],
}
With Environment Variables:
mcpConfig: {
transport: 'stdio',
command: 'node',
args: ['server.js'],
env: {
NODE_ENV: 'test',
API_KEY: 'test-key',
LOG_LEVEL: 'debug',
},
}
With Debug Logging:
# Enable debug logging via environment variable
DEBUG=mcp-server-tester:* npm test
Process Management
The stdio transport automatically:
- Starts the server process when tests begin
- Manages stdin/stdout communication
- Terminates the process when tests complete
- Handles process errors and crashes
HTTP (Remote Server)
The HTTP transport connects to a remote MCP server via HTTP and Server-Sent Events (SSE).
Basic Configuration
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'mcp-remote',
use: {
mcpConfig: {
transport: 'http',
serverUrl: 'http://localhost:3000/mcp',
},
},
},
],
});
Configuration Options
{
transport: 'http',
serverUrl: string, // MCP server URL
requestTimeoutMs?: number, // Request timeout (default: 30000)
headers?: Record<string, string>, // Custom HTTP headers
protocol?: 'legacy' | 'auto' | string, // Protocol to speak (default: 'legacy')
protocolProbe?: { timeoutMs?: number }, // Bounds the 'auto' probe
}
Protocol Version
Both transports accept protocol. The default, 'legacy', uses the initialize handshake exactly as MST 1.x did. Pin '2026-07-28' to test the stateless protocol, pin a legacy revision such as '2025-06-18', or use 'auto' to probe and fall back. The legacy HTTP+SSE fallback only speaks 2024-11-05, so a connection pinned to any other revision never falls back to it. See Protocol Versions for running an eval against several protocols.
Security note: When
serverUrluseshttp://with a non-localhost address, the framework emits a console warning: tokens and credentials are transmitted unencrypted over plain HTTP. Always usehttps://for remote servers. The warning is suppressed forlocalhost/127.0.0.1since local development traffic stays on the machine.
Examples
Local HTTP Server:
mcpConfig: {
transport: 'http',
serverUrl: 'http://localhost:3000/mcp',
}
Remote Server with Authentication:
mcpConfig: {
transport: 'http',
serverUrl: 'https://api.example.com/mcp',
headers: {
'Authorization': 'Bearer your-token-here',
'X-API-Key': 'your-api-key',
},
}
For OAuth 2.1 authentication and more advanced auth patterns, see the Authentication Guide.
With Custom Timeout:
mcpConfig: {
transport: 'http',
serverUrl: 'http://localhost:3000/mcp',
requestTimeoutMs: 60000, // 60 seconds
}
Production Server:
mcpConfig: {
transport: 'http',
serverUrl: process.env.MCP_SERVER_URL || 'https://mcp.production.com',
headers: {
'Authorization': `Bearer ${process.env.MCP_API_TOKEN}`,
},
requestTimeoutMs: 45000,
}
Connection Management
The HTTP transport:
- Establishes HTTP connection on first use
- Maintains SSE stream for server events
- Closes connection when tests complete
Note: Automatic reconnection is not currently implemented. If the remote server drops the connection mid-test-suite, subsequent tests will fail with connection errors. For production use against unreliable servers, implement reconnect logic at the Playwright
globalSetuplevel or use Playwright's retry mechanism.
Multiple Transports
Test against multiple server configurations using Playwright projects:
import { defineConfig } from '@playwright/test';
export default defineConfig({
projects: [
// Local development server
{
name: 'local-dev',
use: {
mcpConfig: {
transport: 'stdio',
command: 'node',
args: ['dist/server.js'],
env: { NODE_ENV: 'development' },
},
},
},
// Local production build
{
name: 'local-prod',
use: {
mcpConfig: {
transport: 'stdio',
command: 'node',
args: ['dist/server.js'],
env: { NODE_ENV: 'production' },
},
},
},
// Staging server
{
name: 'staging',
use: {
mcpConfig: {
transport: 'http',
serverUrl: 'https://staging.example.com/mcp',
headers: {
Authorization: `Bearer ${process.env.STAGING_TOKEN}`,
},
},
},
},
// Production server
{
name: 'production',
use: {
mcpConfig: {
transport: 'http',
serverUrl: 'https://api.example.com/mcp',
headers: {
Authorization: `Bearer ${process.env.PROD_TOKEN}`,
},
},
},
},
],
});
Running Specific Projects
# Run all projects
npx playwright test
# Run only local tests
npx playwright test --project=local-dev
# Run only remote tests
npx playwright test --project=staging --project=production
Environment Variables
Use environment variables for sensitive data and environment-specific config:
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'mcp',
use: {
mcpConfig: {
transport: process.env.MCP_TRANSPORT || 'stdio',
// Stdio config
...(process.env.MCP_TRANSPORT === 'stdio' && {
command: process.env.MCP_COMMAND || 'node',
args: [process.env.MCP_SERVER_PATH || 'server.js'],
}),
// HTTP config
...(process.env.MCP_TRANSPORT === 'http' && {
serverUrl: process.env.MCP_SERVER_URL,
headers: {
Authorization: `Bearer ${process.env.MCP_API_TOKEN}`,
},
}),
},
},
},
],
});
Example .env File
# Transport type
MCP_TRANSPORT=stdio
# Stdio config
MCP_COMMAND=node
MCP_SERVER_PATH=dist/server.js
NODE_ENV=test
# HTTP config (when MCP_TRANSPORT=http)
# MCP_SERVER_URL=https://api.example.com/mcp
# MCP_API_TOKEN=your-token-here
Load with dotenv:
npm install --save-dev dotenv
// playwright.config.ts
import { defineConfig } from '@playwright/test';
import * as dotenv from 'dotenv';
dotenv.config();
export default defineConfig({
// ... config using process.env
});
Troubleshooting
Stdio Transport Issues
Issue: Server process fails to start
Error: Command not found: node server.js
Solutions:
- Verify command exists:
which node - Use absolute paths:
/usr/local/bin/node - Check file exists:
ls -la server.js - Ensure executable permissions:
chmod +x server.js
Issue: Server starts but doesn't respond
Solutions:
- Enable debug logging:
DEBUG=mcp-server-tester:* npm test - Check server logs for errors
- Verify server writes to stdout (not stderr)
- Ensure server follows MCP protocol
Issue: Environment variables not set
Solutions:
- Use
envoption in config - Check variable names and values
- Verify dotenv is loaded before config
HTTP Transport Issues
Issue: Connection refused
Error: connect ECONNREFUSED localhost:3000
Solutions:
- Verify server is running:
curl http://localhost:3000/mcp - Check correct port and host
- Ensure server accepts HTTP connections
- Check firewall rules
Issue: Request timeout
Error: Request timeout after 30000ms
Solutions:
- Increase timeout:
requestTimeoutMs: 60000 - Check server response time
- Verify server isn't blocking
- Look for network issues
Issue: Authentication failure
Error: 401 Unauthorized
Solutions:
- Verify API token is correct
- Check header format:
Authorization: Bearer <token> - Ensure token hasn't expired
- Test authentication separately:
curl -H "Authorization: Bearer <token>" <url>
Next Steps
- See the Quick Start Guide for basic setup
- Learn about Authentication for OAuth and token auth
- Check the API Reference for config type details
- Explore Examples for real-world configurations