import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ListResourcesRequestSchema,
ReadResourceRequestSchema,
ListPromptsRequestSchema,
GetPromptRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
async function main() {
const HTTP_ENDPOINT = "http://localhost:4000/mcp";
// Create custom fetch with auth headers
const authFetch = async (url, options) => {
return fetch(url, {
...options,
headers: {
...options?.headers,
'Authorization': process.env.MCP_BEARER_TOKEN
? `Bearer ${process.env.MCP_BEARER_TOKEN}`
: 'Bearer 1234',
'Content-Type': 'application/json',
},
});
};
// Create HTTP transport with custom fetch
const httpTransport = new StreamableHTTPClientTransport(
HTTP_ENDPOINT,
authFetch
);
const httpClient = new Client(
{
name: "stdio-http-bridge",
version: "1.0.0",
},
{
capabilities: {},
}
);
console.error("Connecting to HTTP MCP server...");
await httpClient.connect(httpTransport);
console.error("✓ Connected to HTTP MCP server at", HTTP_ENDPOINT);
// Verify connection by listing tools
try {
const tools = await httpClient.listTools();
console.error(`✓ Found ${tools.tools?.length || 0} tools`);
} catch (error) {
console.error("Warning: Could not list tools:", error.message);
}
// Create stdio server for Claude Desktop
const stdioServer = new Server(
{
name: "stdio-bridge",
version: "1.0.0",
},
{
capabilities: {
tools: {},
resources: {},
prompts: {},
},
}
);
// Forward all requests
stdioServer.setRequestHandler(ListToolsRequestSchema, async () => {
console.error("Forwarding ListTools request");
return await httpClient.listTools();
});
stdioServer.setRequestHandler(CallToolRequestSchema, async (request) => {
console.error("Forwarding CallTool request:", request.params.name);
return await httpClient.callTool(request.params);
});
stdioServer.setRequestHandler(ListResourcesRequestSchema, async () => {
console.error("Forwarding ListResources request");
return await httpClient.listResources();
});
stdioServer.setRequestHandler(ReadResourceRequestSchema, async (request) => {
console.error("Forwarding ReadResource request:", request.params.uri);
return await httpClient.readResource(request.params);
});
stdioServer.setRequestHandler(ListPromptsRequestSchema, async () => {
console.error("Forwarding ListPrompts request");
return await httpClient.listPrompts();
});
stdioServer.setRequestHandler(GetPromptRequestSchema, async (request) => {
console.error("Forwarding GetPrompt request:", request.params.name);
return await httpClient.getPrompt(request.params);
});
const stdioTransport = new StdioServerTransport();
await stdioServer.connect(stdioTransport);
console.error("✓ Stdio bridge running - ready for Claude Desktop");
}
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});