giga-code
Version:
A personal AI CLI assistant powered by Grok for local development.
207 lines • 7.27 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.McpClient = void 0;
const child_process_1 = require("child_process");
class McpClient {
constructor(server) {
this.process = null;
this.messageId = 0;
this.pendingRequests = new Map();
this.isConnected = false;
this.serverInfo = null;
this.server = server;
}
async connect() {
return new Promise((resolve, reject) => {
try {
// Parse command and args
const commandParts = this.server.command.split(' ');
const command = commandParts[0];
const args = [...commandParts.slice(1), ...(this.server.args || [])];
// Spawn the MCP server process
this.process = (0, child_process_1.spawn)(command, args, {
stdio: ['pipe', 'pipe', 'pipe'],
env: { ...process.env, ...this.server.env },
});
this.process.on('error', (error) => {
reject(new Error(`Failed to start MCP server: ${error.message}`));
});
// Set up message handling
let buffer = '';
this.process.stdout?.on('data', (data) => {
buffer += data.toString();
// Process complete JSON-RPC messages
let newlineIndex;
while ((newlineIndex = buffer.indexOf('\n')) !== -1) {
const line = buffer.slice(0, newlineIndex).trim();
buffer = buffer.slice(newlineIndex + 1);
if (line) {
try {
const message = JSON.parse(line);
this.handleMessage(message);
}
catch (error) {
}
}
}
});
this.process.stderr?.on('data', (data) => {
// Suppress MCP server stderr logs
});
this.process.on('close', (code) => {
this.isConnected = false;
if (code !== 0) {
}
});
// Initialize the connection
this.initialize().then(() => {
this.isConnected = true;
resolve();
}).catch(reject);
}
catch (error) {
reject(error);
}
});
}
async initialize() {
// Send initialize request
const initResponse = await this.sendRequest('initialize', {
protocolVersion: '2024-11-05',
capabilities: {
tools: {},
},
clientInfo: {
name: 'giga-code',
version: '1.0.0',
},
});
this.serverInfo = {
name: initResponse.serverInfo?.name || this.server.name,
version: initResponse.serverInfo?.version || '1.0.0',
};
// Send initialized notification
this.sendNotification('initialized', {});
// Get available tools
try {
const toolsResponse = await this.sendRequest('tools/list', {});
if (toolsResponse.tools) {
this.serverInfo.tools = toolsResponse.tools;
}
}
catch (error) {
this.serverInfo.tools = [];
}
// Get available resources
try {
const resourcesResponse = await this.sendRequest('resources/list', {});
if (resourcesResponse.resources) {
this.serverInfo.resources = resourcesResponse.resources;
}
}
catch (error) {
// Many MCP servers don't implement resources/list - silently ignore "Method not found" errors
const errorMessage = error instanceof Error ? error.message : String(error);
if (!errorMessage.includes('Method not found')) {
}
this.serverInfo.resources = [];
}
}
handleMessage(message) {
if (message.id !== undefined && this.pendingRequests.has(message.id)) {
// This is a response to a request
const { resolve, reject } = this.pendingRequests.get(message.id);
this.pendingRequests.delete(message.id);
if (message.error) {
reject(new Error(message.error.message || 'MCP error'));
}
else {
resolve(message.result);
}
}
else {
// This is a notification or request from the server
}
}
sendRequest(method, params) {
return new Promise((resolve, reject) => {
if (!this.process) {
reject(new Error('MCP client process not started'));
return;
}
const id = ++this.messageId;
const message = {
jsonrpc: '2.0',
id,
method,
params,
};
this.pendingRequests.set(id, { resolve, reject });
const messageStr = JSON.stringify(message) + '\n';
this.process.stdin?.write(messageStr);
// Set timeout for requests
setTimeout(() => {
if (this.pendingRequests.has(id)) {
this.pendingRequests.delete(id);
reject(new Error('MCP request timeout'));
}
}, 30000); // 30 second timeout
});
}
sendNotification(method, params) {
if (!this.process) {
return;
}
const message = {
jsonrpc: '2.0',
method,
params,
};
const messageStr = JSON.stringify(message) + '\n';
this.process.stdin?.write(messageStr);
}
async callTool(name, arguments_) {
try {
const response = await this.sendRequest('tools/call', {
name,
arguments: arguments_,
});
return {
content: response.content || [],
isError: response.isError || false,
_meta: response._meta,
};
}
catch (error) {
return {
content: [{
type: 'text',
text: `Error calling tool: ${error instanceof Error ? error.message : String(error)}`,
}],
isError: true,
};
}
}
getServerInfo() {
return this.serverInfo;
}
getTools() {
return this.serverInfo?.tools || [];
}
getResources() {
return this.serverInfo?.resources || [];
}
async disconnect() {
if (this.process) {
this.process.kill();
this.process = null;
}
this.isConnected = false;
this.pendingRequests.clear();
}
isConnectedToServer() {
return this.isConnected;
}
}
exports.McpClient = McpClient;
//# sourceMappingURL=mcp-client.js.map