Files
vibn-frontend/mcp-zed-adapter.js

160 lines
4.0 KiB
JavaScript
Executable File

#!/usr/bin/env node
/**
* Vibn MCP Adapter for Zed
*
* This script runs locally as a standard stdio MCP server for Zed.
* It intercepts tool calls and forwards them over HTTP to the Vibn API
* using the proprietary format that Vibn expects.
*/
const { Server } = require("@modelcontextprotocol/sdk/server/index.js");
const { StdioServerTransport } = require("@modelcontextprotocol/sdk/server/stdio.js");
const { CallToolRequestSchema, ListToolsRequestSchema } = require("@modelcontextprotocol/sdk/types.js");
// Configuration from environment variables
const VIBN_API_URL = process.env.VIBN_API_URL || "https://vibnai.com/api/mcp";
const VIBN_API_KEY = process.env.VIBN_API_KEY;
if (!VIBN_API_KEY) {
console.error("Missing VIBN_API_KEY environment variable.");
process.exit(1);
}
// Create the MCP server
const server = new Server(
{
name: "vibn-zed-adapter",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
let cachedTools = null;
// Fetch the tool list from the Vibn API
async function fetchTools() {
if (cachedTools) return cachedTools;
try {
const response = await fetch(VIBN_API_URL, {
method: "GET",
headers: {
Authorization: \`Bearer \${VIBN_API_KEY}\`,
},
});
if (!response.ok) {
throw new Error(\`Failed to fetch tools: \${response.statusText}\`);
}
const data = await response.json();
// We need to fetch the actual tool schemas since the GET endpoint
// only returns a string array of tool names.
// For this adapter, we define the schema passthrough.
// Note: Since Vibn's GET /api/mcp only returns an array of names:
// "available": ["workspace.describe", "gitea.credentials", ...]
// We will construct basic MCP tool definitions for them.
// In a production scenario, you would expose the JSON schemas on the GET endpoint.
const available = data.capabilities?.tools?.available || [];
cachedTools = available.map(name => ({
name: name,
description: \`Vibn workspace tool: \${name}\`,
inputSchema: {
type: "object",
properties: {
// Accept any parameters generically for the proxy
projectId: { type: "string", description: "Vibn project ID" },
},
additionalProperties: true
}
}));
return cachedTools;
} catch (error) {
console.error("Error fetching tools:", error);
return [];
}
}
// Handle List Tools Request
server.setRequestHandler(ListToolsRequestSchema, async () => {
const tools = await fetchTools();
return {
tools: tools,
};
});
// Handle Call Tool Request
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
// Forward the request to Vibn API
const response = await fetch(VIBN_API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: \`Bearer \${VIBN_API_KEY}\`,
},
body: JSON.stringify({
tool: name, // Vibn's expected format
params: args || {},
}),
});
const data = await response.json();
if (!response.ok) {
return {
content: [
{
type: "text",
text: \`Error (\${response.status}): \${JSON.stringify(data.error || data)}\`,
},
],
isError: true,
};
}
return {
content: [
{
type: "text",
text: JSON.stringify(data.result || data, null, 2),
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: \`Internal Adapter Error: \${error.message}\`,
},
],
isError: true,
};
}
});
// Start the server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Vibn Zed MCP Adapter running on stdio");
}
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});