Transport Types in MCP Firebird
June 25, 2026 · View on GitHub
This document provides comprehensive examples and configuration for the different transport types supported by MCP Firebird.
Overview
MCP Firebird supports four transport modes:
- STDIO (Standard Input/Output) - For local integrations like Claude Desktop
- SSE (Server-Sent Events) - Legacy web transport for backwards compatibility
- HTTP Streamable - Modern MCP protocol (2025-03-26) with bidirectional communication
- Unified - Supports both SSE and HTTP Streamable simultaneously with auto-detection
Which Transport Should I Use?
| Transport | Use Case | Recommended For |
|---|---|---|
| STDIO | Local integration | Claude Desktop, CLI tools, single-user |
| SSE | Legacy web clients | Older MCP clients, backwards compatibility |
| HTTP Streamable | Modern web clients | New applications, production deployments |
| Unified | Mixed environments | Supporting both old and new clients |
Recommendation: Use HTTP Streamable or Unified for new projects. Use STDIO for Claude Desktop integration.
STDIO Transport
What is STDIO?
STDIO transport uses standard input/output streams for communication. This is the recommended transport for:
- Claude Desktop integration
- Local command-line tools
- Single-user scenarios
- Development and testing
Configuration
Environment Variables
# .env file
TRANSPORT_TYPE=stdio
FIREBIRD_HOST=localhost
FIREBIRD_PORT=3050
FIREBIRD_DATABASE=/path/to/database.fdb
FIREBIRD_USER=SYSDBA
FIREBIRD_PASSWORD=masterkey
Command Line
# Basic STDIO usage
npx -y mcp-firebird \
--transport-type stdio \
--database /path/to/database.fdb \
--host localhost \
--port 3050 \
--user SYSDBA \
--password masterkey
# Windows example
npx -y mcp-firebird ^
--transport-type stdio ^
--database "F:\Proyectos\SAI\EMPLOYEE.FDB" ^
--host localhost ^
--port 3050 ^
--user SYSDBA ^
--password masterkey
# Linux/Unix example
npx -y mcp-firebird \
--transport-type stdio \
--database /var/lib/firebird/data/employee.fdb \
--host localhost \
--port 3050 \
--user SYSDBA \
--password masterkey
Claude Desktop Integration
Add to your Claude Desktop configuration file:
Windows: %APPDATA%\Claude\claude_desktop_config.json
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Linux: ~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"mcp-firebird": {
"command": "npx",
"args": [
"mcp-firebird",
"--transport-type", "stdio",
"--database", "F:\\Proyectos\\SAI\\EMPLOYEE.FDB",
"--host", "localhost",
"--port", "3050",
"--user", "SYSDBA",
"--password", "masterkey"
]
}
}
}
MCP Inspector with STDIO
# Run the inspector with STDIO transport
npm run inspector
# Or manually
npx @modelcontextprotocol/inspector node dist/index.js
STDIO Examples
Example 1: Basic Query Execution
# Start the server
npx -y mcp-firebird --transport-type stdio --database /path/to/db.fdb
# The server will communicate via STDIO
# Claude Desktop or other MCP clients can now interact with it
Example 2: Using with Custom Scripts
// custom-client.js
import { spawn } from 'child_process';
const mcpServer = spawn('npx', [
'mcp-firebird@alpha',
'--transport-type', 'stdio',
'--database', '/path/to/database.fdb',
'--host', 'localhost',
'--port', '3050',
'--user', 'SYSDBA',
'--password', 'masterkey'
]);
// Send MCP messages via stdin
mcpServer.stdin.write(JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'tools/call',
params: {
name: 'list-tables',
arguments: {}
}
}) + '\n');
// Receive responses via stdout
mcpServer.stdout.on('data', (data) => {
console.log('Response:', data.toString());
});
SSE Transport
What is SSE?
SSE (Server-Sent Events) transport runs MCP Firebird as a web server. This is recommended for:
- Web application integration
- Remote database access
- Multi-client scenarios
- Development with MCP Inspector
- Load balancing and scaling
Configuration
Environment Variables
# .env file
TRANSPORT_TYPE=sse
SSE_PORT=3003
FIREBIRD_HOST=localhost
FIREBIRD_PORT=3050
FIREBIRD_DATABASE=/path/to/database.fdb
FIREBIRD_USER=SYSDBA
FIREBIRD_PASSWORD=masterkey
Command Line
# Basic SSE server
npx -y mcp-firebird \
--transport-type sse \
--sse-port 3003 \
--database /path/to/database.fdb \
--host localhost \
--port 3050 \
--user SYSDBA \
--password masterkey \
--api-key your_super_secret_key
# With custom port
npx -y mcp-firebird \
--transport-type sse \
--sse-port 8080 \
--database /path/to/database.fdb
# Full configuration
npx -y mcp-firebird \
--transport-type sse \
--sse-port 3003 \
--host 192.168.1.100 \
--port 3050 \
--database /firebird/data/database.fdb \
--user SYSDBA \
--password masterkey
MCP Inspector with SSE
# Connect to SSE server
npx @modelcontextprotocol/inspector http://localhost:3003
# Connect to remote SSE server
npx @modelcontextprotocol/inspector http://192.168.1.100:3003
SSE Examples
Example 1: Basic HTML/JavaScript Client
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MCP Firebird SSE Client</title>
</head>
<body>
<h1>MCP Firebird SSE Client</h1>
<button onclick="listTables()">List Tables</button>
<pre id="output"></pre>
<script>
const MCP_SERVER_URL = 'http://localhost:3003';
async function listTables() {
try {
const response = await fetch(`${MCP_SERVER_URL}/messages`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'tools/call',
params: {
name: 'list-tables',
arguments: {}
}
})
});
const result = await response.json();
document.getElementById('output').textContent =
JSON.stringify(result, null, 2);
} catch (error) {
console.error('Error:', error);
document.getElementById('output').textContent =
'Error: ' + error.message;
}
}
</script>
</body>
</html>
Example 2: Python Client
import requests
import json
MCP_SERVER_URL = 'http://localhost:3003'
def call_mcp_tool(tool_name, arguments=None):
"""Call an MCP tool via SSE transport"""
payload = {
'jsonrpc': '2.0',
'id': 1,
'method': 'tools/call',
'params': {
'name': tool_name,
'arguments': arguments or {}
}
}
response = requests.post(
f'{MCP_SERVER_URL}/messages',
headers={'Content-Type': 'application/json'},
json=payload
)
return response.json()
# Example: List tables
result = call_mcp_tool('list-tables')
print(json.dumps(result, indent=2))
# Example: Execute query
result = call_mcp_tool('execute-query', {
'query': 'SELECT * FROM EMPLOYEES WHERE SALARY > 50000'
})
print(json.dumps(result, indent=2))
# Example: Get table data with filtering
result = call_mcp_tool('get-table-data', {
'tableName': 'CUSTOMERS',
'whereClause': 'COUNTRY = \'USA\'',
'orderBy': 'CUSTOMER_NAME',
'limit': 100
})
print(json.dumps(result, indent=2))
HTTP Streamable Transport (Modern - Recommended)
What is HTTP Streamable?
HTTP Streamable is the modern MCP protocol (2025-03-26) that provides bidirectional communication with improved performance and session management. This is the recommended transport for new applications.
Key Features:
- ✅ Modern MCP protocol specification
- ✅ Bidirectional communication
- ✅ Session management with automatic cleanup
- ✅ Stateful and stateless modes
- ✅ Better performance than SSE
- ✅ Full MCP SDK support
Recommended for:
- New web applications
- Production deployments
- Modern MCP clients
- High-performance scenarios
- Applications requiring session management
HTTP Streamable Configuration
Environment Variables
# .env file
TRANSPORT_TYPE=http
HTTP_PORT=3003
FIREBIRD_HOST=localhost
FIREBIRD_PORT=3050
FIREBIRD_DATABASE=/path/to/database.fdb
FIREBIRD_USER=SYSDBA
FIREBIRD_PASSWORD=masterkey
# Optional: Session configuration
STREAMABLE_SESSION_TIMEOUT_MS=1800000 # 30 minutes (only for stateful mode)
STREAMABLE_STATELESS_MODE=true # Default: true (stateless mode)
# Set to false for stateful mode
# EMA Authorization
FIREBIRD_API_KEY=your_super_secret_key
Command Line
# Default mode: Stateless (works with MCP Inspector and most clients)
npx -y mcp-firebird \
--transport-type http \
--http-port 3003 \
--database /path/to/database.fdb \
--user SYSDBA \
--password masterkey
# Windows example (Git Bash) - Stateless by default
npx -y mcp-firebird \
--transport-type http \
--http-port 3012 \
--database "F:\\Proyectos\\SAI\\EMPLOYEE.FDB" \
--user SYSDBA \
--password masterkey
# Enable stateful mode (for custom clients with proper session management)
STREAMABLE_STATELESS_MODE=false npx -y mcp-firebird \
--transport-type http \
--http-port 3003 \
--database /path/to/database.fdb \
--host localhost \
--port 3050 \
--user SYSDBA \
--password masterkey
# Stateful mode with custom session timeout
STREAMABLE_STATELESS_MODE=false STREAMABLE_SESSION_TIMEOUT_MS=600000 npx -y mcp-firebird \
--transport-type http \
--http-port 3003 \
--database /path/to/database.fdb
Important Notes:
- ✅ Stateless mode is now the default - Works with MCP Inspector and all clients
- ⚠️ Set
STREAMABLE_STATELESS_MODE=falseto enable stateful mode - ⚠️ Stateful mode requires clients to properly implement session initialization
- ✅ Stateless mode: Each request is independent, no session state maintained
MCP Inspector with HTTP Streamable
Good news! HTTP Streamable now uses stateless mode by default, so it works perfectly with MCP Inspector:
# Start server (stateless by default - works with MCP Inspector)
npx -y mcp-firebird \
--transport-type http \
--http-port 3003 \
--database /path/to/database.fdb \
--user SYSDBA \
--password masterkey
# Windows example (Git Bash)
npx -y mcp-firebird \
--transport-type http \
--http-port 3012 \
--database "F:\\Proyectos\\SAI\\EMPLOYEE.FDB" \
--user SYSDBA \
--password masterkey
# Then connect with MCP Inspector
npx @modelcontextprotocol/inspector http://localhost:3012/mcp
Note: Stateless mode is now the default. No need to set STREAMABLE_STATELESS_MODE=true anymore!
HTTP Streamable Examples
Example 1: TypeScript/JavaScript Client with MCP SDK
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
// Create transport
const transport = new StreamableHTTPClientTransport(
new URL("http://localhost:3003/mcp"),
{ headers: { Authorization: "Bearer your_super_secret_key" } }
);
// Create client
const client = new Client({
name: "my-firebird-client",
version: "1.0.0"
}, {
capabilities: {}
});
// Connect
await client.connect(transport);
// List available tools
const tools = await client.listTools();
console.log('Available tools:', tools);
// Call a tool
const result = await client.callTool({
name: 'list-tables',
arguments: {}
});
console.log('Tables:', result);
// Execute a query
const queryResult = await client.callTool({
name: 'execute-query',
arguments: {
query: 'SELECT * FROM EMPLOYEES WHERE SALARY > 50000'
}
});
console.log('Query result:', queryResult);
// Access resources
const schema = await client.readResource({
uri: '/schema'
});
console.log('Database schema:', schema);
// Use prompts
const healthCheck = await client.getPrompt({
name: 'database-health-check',
arguments: {
focusAreas: ['performance', 'security']
}
});
console.log('Health check guide:', healthCheck);
// Close connection
await client.close();
Example 2: Python Client with HTTP Streamable
import requests
import json
class MCPStreamableClient:
def __init__(self, base_url):
self.base_url = base_url
self.session_id = None
self.session = requests.Session()
def initialize(self):
"""Initialize MCP session"""
response = self.session.post(
f'{self.base_url}/mcp',
headers={'Content-Type': 'application/json'},
json={
'jsonrpc': '2.0',
'id': 1,
'method': 'initialize',
'params': {
'protocolVersion': '2024-11-05',
'capabilities': {},
'clientInfo': {
'name': 'python-mcp-client',
'version': '1.0.0'
}
}
}
)
# Extract session ID from response headers
self.session_id = response.headers.get('mcp-session-id')
return response.json()
def call_tool(self, tool_name, arguments=None):
"""Call an MCP tool"""
headers = {
'Content-Type': 'application/json'
}
if self.session_id:
headers['mcp-session-id'] = self.session_id
response = self.session.post(
f'{self.base_url}/mcp',
headers=headers,
json={
'jsonrpc': '2.0',
'id': 2,
'method': 'tools/call',
'params': {
'name': tool_name,
'arguments': arguments or {}
}
}
)
return response.json()
def read_resource(self, uri):
"""Read an MCP resource"""
headers = {
'Content-Type': 'application/json'
}
if self.session_id:
headers['mcp-session-id'] = self.session_id
response = self.session.post(
f'{self.base_url}/mcp',
headers=headers,
json={
'jsonrpc': '2.0',
'id': 3,
'method': 'resources/read',
'params': {
'uri': uri
}
}
)
return response.json()
# Usage example
client = MCPStreamableClient('http://localhost:3003')
# Initialize session
init_result = client.initialize()
print('Initialized:', json.dumps(init_result, indent=2))
# List tables
tables = client.call_tool('list-tables')
print('Tables:', json.dumps(tables, indent=2))
# Get database schema
schema = client.read_resource('/schema')
print('Schema:', json.dumps(schema, indent=2))
# Execute query
result = client.call_tool('execute-query', {
'query': 'SELECT * FROM EMPLOYEES WHERE SALARY > 50000'
})
print('Query result:', json.dumps(result, indent=2))
Unified Transport (Recommended for Production)
What is Unified Transport?
Unified transport mode runs both SSE and HTTP Streamable protocols simultaneously with automatic protocol detection. This is the recommended mode for production as it supports both legacy and modern clients.
Key Features:
- ✅ Supports both SSE (legacy) and HTTP Streamable (modern)
- ✅ Automatic protocol detection
- ✅ Backwards compatibility
- ✅ Single server instance
- ✅ Flexible client support
Endpoints:
/sse- SSE protocol (legacy)/mcp- HTTP Streamable protocol (modern)/mcp-auto- Auto-detection endpoint/health- Health check
Unified Configuration
Environment Variables
# .env file
TRANSPORT_TYPE=unified
HTTP_PORT=3003
FIREBIRD_HOST=localhost
FIREBIRD_PORT=3050
FIREBIRD_DATABASE=/path/to/database.fdb
FIREBIRD_USER=SYSDBA
FIREBIRD_PASSWORD=masterkey
Command Line
# Start unified server (supports both SSE and HTTP Streamable)
npx -y mcp-firebird \
--transport-type unified \
--http-port 3003 \
--database /path/to/database.fdb \
--host localhost \
--port 3050 \
--user SYSDBA \
--password masterkey
Unified Server Usage
# Modern clients use HTTP Streamable
npx @modelcontextprotocol/inspector http://localhost:3003/mcp
# Legacy clients use SSE
npx @modelcontextprotocol/inspector http://localhost:3003/sse
# Auto-detection endpoint
curl http://localhost:3003/mcp-auto
Unified Server Example
// Modern client (HTTP Streamable)
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const modernTransport = new StreamableHTTPClientTransport(
"http://localhost:3003/mcp"
);
const modernClient = new Client({
name: "modern-client",
version: "1.0.0"
}, {
capabilities: {}
});
await modernClient.connect(modernTransport);
// Legacy client (SSE) - still works!
const legacyResponse = await fetch('http://localhost:3003/messages', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'tools/call',
params: {
name: 'list-tables',
arguments: {}
}
})
});
Example 3: Node.js/JavaScript Client (SSE)
// sse-client.js
import fetch from 'node-fetch';
const MCP_SERVER_URL = 'http://localhost:3003';
async function callMCPTool(toolName, args = {}) {
const response = await fetch(`${MCP_SERVER_URL}/messages`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
jsonrpc: '2.0',
id: Date.now(),
method: 'tools/call',
params: {
name: toolName,
arguments: args
}
})
});
return await response.json();
}
// Example usage
async function main() {
// List all tables
const tables = await callMCPTool('list-tables');
console.log('Tables:', JSON.stringify(tables, null, 2));
// Describe a table
const schema = await callMCPTool('describe-table', {
tableName: 'EMPLOYEES'
});
console.log('Schema:', JSON.stringify(schema, null, 2));
// Execute a query
const queryResult = await callMCPTool('execute-query', {
query: 'SELECT * FROM EMPLOYEES WHERE SALARY > 50000'
});
console.log('Query Result:', JSON.stringify(queryResult, null, 2));
// Use new v2.6.0 features
// Get table data with filtering
const filteredData = await callMCPTool('get-table-data', {
tableName: 'ORDERS',
whereClause: 'ORDER_DATE > \'2024-01-01\'',
orderBy: 'ORDER_DATE DESC',
limit: 50
});
console.log('Filtered Data:', JSON.stringify(filteredData, null, 2));
// Analyze table statistics
const stats = await callMCPTool('analyze-table-statistics', {
tableName: 'CUSTOMERS'
});
console.log('Statistics:', JSON.stringify(stats, null, 2));
// Analyze missing indexes
const indexes = await callMCPTool('analyze-missing-indexes', {
tableName: 'ORDERS'
});
console.log('Missing Indexes:', JSON.stringify(indexes, null, 2));
}
main().catch(console.error);
Example 4: Using Resources
// Access MCP resources via SSE
async function getResource(resourceUri) {
const response = await fetch(`${MCP_SERVER_URL}/messages`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
jsonrpc: '2.0',
id: Date.now(),
method: 'resources/read',
params: {
uri: resourceUri
}
})
});
return await response.json();
}
// Get complete database schema
const schema = await getResource('/schema');
console.log('Database Schema:', JSON.stringify(schema, null, 2));
// Get table indexes
const indexes = await getResource('/tables/EMPLOYEES/indexes');
console.log('Indexes:', JSON.stringify(indexes, null, 2));
// Get table constraints
const constraints = await getResource('/tables/EMPLOYEES/constraints');
console.log('Constraints:', JSON.stringify(constraints, null, 2));
// Get database statistics
const statistics = await getResource('/statistics');
console.log('Statistics:', JSON.stringify(statistics, null, 2));
Example 5: Using Template Prompts
// Use template prompts for guided workflows
async function getPrompt(promptName, args = {}) {
const response = await fetch(`${MCP_SERVER_URL}/messages`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
jsonrpc: '2.0',
id: Date.now(),
method: 'prompts/get',
params: {
name: promptName,
arguments: args
}
})
});
return await response.json();
}
// Database health check
const healthCheck = await getPrompt('database-health-check', {
focusAreas: ['performance', 'security']
});
console.log('Health Check Guide:', healthCheck);
// Query optimization guide
const optimizationGuide = await getPrompt('query-optimization-guide', {
queryType: 'select'
});
console.log('Optimization Guide:', optimizationGuide);
// Migration planning
const migrationPlan = await getPrompt('migration-planning', {
migrationType: 'schema-change',
description: 'Add new customer loyalty program tables'
});
console.log('Migration Plan:', migrationPlan);
Docker Configuration
STDIO in Docker
version: '3.8'
services:
mcp-firebird-stdio:
image: mcp-firebird:latest
environment:
TRANSPORT_TYPE: stdio
FIREBIRD_HOST: firebird-db
FIREBIRD_PORT: 3050
FIREBIRD_DATABASE: /firebird/data/database.fdb
FIREBIRD_USER: SYSDBA
FIREBIRD_PASSWORD: masterkey
depends_on:
- firebird-db
stdin_open: true
tty: true
SSE in Docker
version: '3.8'
services:
mcp-firebird-sse:
image: mcp-firebird:latest
environment:
TRANSPORT_TYPE: sse
SSE_PORT: 3003
FIREBIRD_HOST: firebird-db
FIREBIRD_PORT: 3050
FIREBIRD_DATABASE: /firebird/data/database.fdb
FIREBIRD_USER: SYSDBA
FIREBIRD_PASSWORD: masterkey
ports:
- "3003:3003"
depends_on:
- firebird-db
Transport Comparison
Complete Comparison Table
| Feature | STDIO | SSE (Legacy) | HTTP Streamable | Unified |
|---|---|---|---|---|
| Protocol | Standard I/O | Server-Sent Events | Modern MCP (2025-03-26) | Both SSE + HTTP |
| Use Case | Local integration | Legacy web clients | Modern web clients | Mixed environments |
| Clients | Single | Multiple concurrent | Multiple concurrent | Multiple concurrent |
| Network | Not required | HTTP/HTTPS | HTTP/HTTPS | HTTP/HTTPS |
| Port | None | Configurable (3003) | Configurable (3003) | Configurable (3003) |
| Session Management | N/A | Basic | Advanced (stateful/stateless) | Advanced |
| Bidirectional | Yes | No (server→client only) | Yes | Yes |
| Performance | Fastest | Good | Better than SSE | Good |
| MCP Protocol Version | Latest | Legacy | Latest (2025-03-26) | Both |
| Backwards Compatible | N/A | Yes | No | Yes |
| Security | Local only | Requires auth/HTTPS | Requires auth/HTTPS | Requires auth/HTTPS |
| Debugging | MCP Inspector (local) | MCP Inspector (remote) | MCP Inspector (remote) | MCP Inspector (remote) |
| Scalability | Single instance | Load balanceable | Load balanceable | Load balanceable |
| Best For | Claude Desktop, CLI | Old clients | New applications | Production |
| Recommended | ✅ For local use | ⚠️ Legacy only | ✅ For new projects | ✅ For production |
Quick Decision Guide
Choose STDIO if:
- ✅ Integrating with Claude Desktop
- ✅ Building CLI tools
- ✅ Single-user local application
- ✅ No network access needed
Choose SSE if:
- ⚠️ Supporting legacy MCP clients
- ⚠️ Backwards compatibility required
- ❌ Not recommended for new projects
Choose HTTP Streamable if:
- ✅ Building new web applications
- ✅ Need modern MCP features
- ✅ Want best performance
- ✅ Require session management
- ✅ Production deployment
Choose Unified if:
- ✅ Need to support both old and new clients
- ✅ Production environment with mixed clients
- ✅ Want maximum compatibility
- ✅ Migrating from SSE to HTTP Streamable
Troubleshooting
STDIO Issues
Problem: Claude Desktop can't connect to MCP server
Solution:
- Check that the command in
claude_desktop_config.jsonis correct - Verify database path is accessible
- Check Firebird server is running
- Review Claude Desktop logs
Problem: "spawn ENOENT" error
Solution:
- Ensure
npxis in your PATH - Try using full path to node:
"command": "C:\\Program Files\\nodejs\\npx.cmd" - Install mcp-firebird globally:
npm install -g mcp-firebird@alpha
SSE Issues
Problem: Cannot connect to SSE server
Solution:
- Verify server is running:
curl http://localhost:3003/health - Check firewall settings
- Ensure SSE_PORT is not in use
- Review server logs
Problem: CORS errors in web browser
Solution: SSE server includes CORS headers by default. If issues persist:
- Check browser console for specific CORS error
- Verify SSE_PORT matches client configuration
- Use a proxy if needed for development
Problem: Connection timeout
Solution:
- Increase session timeout:
SSE_SESSION_TIMEOUT_MS=600000(10 minutes) - Check network connectivity
- Verify Firebird server is accessible from MCP server
HTTP Streamable Issues
Problem: "Bad Request: No valid session ID provided" error
This issue is now FIXED! As of v2.6.0-alpha.6, HTTP Streamable uses stateless mode by default.
If you still see this error:
- Make sure you're using version 2.6.0-alpha.6 or later
- Verify you haven't explicitly set
STREAMABLE_STATELESS_MODE=false - Restart the server
For older versions (before v2.6.0-alpha.6): Enable stateless mode manually:
# Windows (Git Bash)
STREAMABLE_STATELESS_MODE=true npx -y mcp-firebird \
--transport-type http \
--http-port 3012 \
--database "F:\\Proyectos\\SAI\\EMPLOYEE.FDB" \
--user SYSDBA \
--password masterkey
Why stateless is now the default:
- MCP Inspector and most clients don't properly implement stateful session management
- Stateless mode works with all clients out of the box
- Each request is independent (simpler, more reliable)
Problem: Session not persisting between requests
Solution:
- Ensure client sends
mcp-session-idheader - Check session timeout:
STREAMABLE_SESSION_TIMEOUT_MS - Verify session is initialized with
initializerequest - Review server logs for session cleanup
- For MCP Inspector: Use stateless mode instead
Problem: "No valid session ID" error (general)
Solution:
- Send
initializerequest first to create session - Include
mcp-session-idheader in subsequent requests - Check if session expired (default 30 minutes)
- Use stateless mode if sessions not needed:
STREAMABLE_STATELESS_MODE=true - Quick fix: Always use stateless mode for testing
Problem: Performance issues with stateful mode
Solution:
- Enable stateless mode:
STREAMABLE_STATELESS_MODE=true - Reduce session timeout to free resources faster
- Monitor active sessions count
- Consider load balancing for high traffic
Unified Transport Issues
Problem: Client connecting to wrong protocol
Solution:
- Use specific endpoints:
/mcpfor HTTP Streamable,/ssefor SSE - Check client MCP SDK version
- Use
/mcp-autofor automatic detection - Review client logs for protocol negotiation
Problem: Mixed protocol errors
Solution:
- Ensure both protocols are enabled in configuration
- Check that HTTP_PORT is accessible
- Verify no port conflicts
- Review unified server logs
Security Considerations
STDIO
- ✅ Secure by default (local only)
- ✅ No network exposure
- ⚠️ Credentials in config file (use environment variables)
Security Level: High (local only)
SSE (Legacy)
- ⚠️ Network exposed (use firewall)
- ⚠️ No built-in authentication (add reverse proxy)
- ⚠️ Use HTTPS in production
- ✅ CORS headers included
- ✅ Session management with timeouts
Security Level: Medium (requires additional security layers)
HTTP Streamable
- ⚠️ Network exposed (use firewall)
- ⚠️ No built-in authentication (add reverse proxy)
- ⚠️ Use HTTPS in production
- ✅ Session management with automatic cleanup
- ✅ Stateful and stateless modes
- ✅ Better session security than SSE
Security Level: Medium-High (modern protocol with better session management)
Unified
- ⚠️ Network exposed (use firewall)
- ⚠️ No built-in authentication (add reverse proxy)
- ⚠️ Use HTTPS in production
- ✅ Supports both SSE and HTTP Streamable security features
- ✅ Protocol-specific security measures
Security Level: Medium-High (inherits security from both protocols)
Security Recommendations by Environment
Development Environment
STDIO:
- ✅ Use for local testing
- ✅ No additional security needed
- ⚠️ Use environment variables for credentials
SSE/HTTP Streamable/Unified:
- ✅ Bind to localhost only:
--host 127.0.0.1 - ✅ Use firewall to block external access
- ⚠️ Don't expose to internet
Production Environment
All Network Transports (SSE/HTTP Streamable/Unified):
-
Use Reverse Proxy:
# nginx example server { listen 443 ssl; server_name mcp.example.com; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; location / { proxy_pass http://localhost:3003; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } -
Add Authentication:
- OAuth 2.0 / OpenID Connect
- JWT tokens
- API keys
- Basic Auth (over HTTPS only)
-
Enable HTTPS:
- Valid SSL/TLS certificates
- Strong cipher suites
- HSTS headers
-
Firewall Configuration:
- Restrict access by IP
- Use VPN for remote access
- Rate limiting
-
Database Security:
- Enable Firebird wire encryption
- Use strong passwords
- Limit database user permissions
- Regular security audits
-
Monitoring:
- Log all access attempts
- Monitor for suspicious activity
- Set up alerts for anomalies
Advanced Configuration
Environment Variables
# Transport Configuration
TRANSPORT_TYPE=stdio|sse # Transport type
SSE_PORT=3003 # SSE server port
SSE_SESSION_TIMEOUT_MS=300000 # Session timeout (5 minutes)
# Database Configuration
FIREBIRD_HOST=localhost # Firebird server host
FIREBIRD_PORT=3050 # Firebird server port
FIREBIRD_DATABASE=/path/to/db # Database file path
FIREBIRD_USER=SYSDBA # Database user
FIREBIRD_PASSWORD=masterkey # Database password
# Security
ENABLE_WIRE_ENCRYPTION=true # Enable wire encryption (Firebird 3.0+)
# Logging
LOG_LEVEL=info # Log level: debug, info, warn, error
Performance Tuning
STDIO:
- No tuning needed (direct communication)
SSE:
- Adjust
SSE_SESSION_TIMEOUT_MSbased on usage patterns - Use connection pooling for high-traffic scenarios
- Consider load balancer for multiple instances
- Monitor memory usage with long-running sessions
Examples Repository
For more examples, see:
examples/sse-client.html- Complete HTML/JavaScript clientexamples/sse-client.js- Node.js client exampleexamples/sse_client.py- Python client example
Next Steps
- Choose the appropriate transport type for your use case
- Configure environment variables or command-line parameters
- Test connection with MCP Inspector
- Implement your client application
- Review security considerations for production deployment
For more information, see: