mcp-bridge.js•5.99 kB
#!/usr/bin/env node
const http = require('http');
const https = require('https');
class McpHttpBridge {
constructor() {
this.baseUrl = process.env.MCP_SERVER_URL || 'http://localhost:5000';
this.auth = Buffer.from(`${process.env.MCP_USERNAME || 'admin'}:${process.env.MCP_PASSWORD || 'password123'}`).toString('base64');
}
async makeHttpRequest(path, method = 'GET', body = null) {
return new Promise((resolve, reject) => {
const url = new URL(this.baseUrl + path);
const options = {
hostname: url.hostname,
port: url.port || (url.protocol === 'https:' ? 443 : 80),
path: url.pathname + url.search,
method: method,
headers: {
'Authorization': `Basic ${this.auth}`,
'Content-Type': 'application/json'
}
};
const req = (url.protocol === 'https:' ? https : http).request(options, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
try {
const parsed = JSON.parse(data);
resolve(parsed);
} catch (e) {
resolve(data);
}
});
});
req.on('error', reject);
if (body) {
req.write(JSON.stringify(body));
}
req.end();
});
}
async handleMessage(message) {
try {
switch (message.method) {
case 'initialize':
return await this.handleInitialize(message);
case 'tools/list':
return await this.handleToolsList(message);
case 'tools/call':
return await this.handleToolsCall(message);
case 'resources/list':
return await this.handleResourcesList(message);
default:
// Forward the message to the HTTP API
const response = await this.makeHttpRequest('/api/mcp/message', 'POST', message);
return response;
}
} catch (error) {
return {
jsonrpc: "2.0",
id: message.id,
error: {
code: -32603,
message: "Internal error",
data: error.message
}
};
}
}
async handleInitialize(message) {
return {
jsonrpc: "2.0",
id: message.id,
result: {
protocolVersion: "2024-11-05",
capabilities: {
tools: {
listChanged: false
},
resources: {
subscribe: false,
listChanged: false
}
},
serverInfo: {
name: "MCP Demo HTTP Bridge",
version: "1.0.0"
}
}
};
}
async handleToolsList(message) {
try {
const response = await this.makeHttpRequest('/api/mcp/tools', 'GET');
return {
jsonrpc: "2.0",
id: message.id,
result: response
};
} catch (error) {
return {
jsonrpc: "2.0",
id: message.id,
error: {
code: -32603,
message: "Failed to get tools",
data: error.message
}
};
}
}
async handleToolsCall(message) {
try {
const response = await this.makeHttpRequest('/api/mcp/message', 'POST', message);
return response;
} catch (error) {
return {
jsonrpc: "2.0",
id: message.id,
error: {
code: -32603,
message: "Tool call failed",
data: error.message
}
};
}
}
async handleResourcesList(message) {
try {
const response = await this.makeHttpRequest('/api/mcp/resources', 'GET');
return {
jsonrpc: "2.0",
id: message.id,
result: response
};
} catch (error) {
return {
jsonrpc: "2.0",
id: message.id,
error: {
code: -32603,
message: "Failed to get resources",
data: error.message
}
};
}
}
}
// Main execution
const bridge = new McpHttpBridge();
process.stdin.setEncoding('utf8');
process.stdin.on('readable', async () => {
const chunk = process.stdin.read();
if (chunk !== null) {
const lines = chunk.trim().split('\n');
for (const line of lines) {
if (line.trim()) {
try {
const message = JSON.parse(line);
const response = await bridge.handleMessage(message);
process.stdout.write(JSON.stringify(response) + '\n');
} catch (error) {
const errorResponse = {
jsonrpc: "2.0",
id: null,
error: {
code: -32700,
message: "Parse error",
data: error.message
}
};
process.stdout.write(JSON.stringify(errorResponse) + '\n');
}
}
}
}
});
process.stdin.on('end', () => {
process.exit(0);
});