giga-code
Version:
A personal AI CLI assistant powered by Grok for local development.
211 lines • 6.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.HttpMcpClient = void 0;
class HttpMcpClient {
constructor(server) {
this.messageId = 0;
this.isConnected = false;
this.serverInfo = null;
this.server = server;
}
async connect() {
if (this.server.type !== 'http') {
throw new Error('HttpMcpClient can only connect to HTTP servers');
}
try {
// Test connection by calling initialize
await this.initialize();
this.isConnected = true;
}
catch (error) {
throw new Error(`Failed to connect to HTTP MCP server ${this.server.name}: ${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 (for HTTP servers that need it)
try {
await this.sendRequest('initialized', {});
}
catch (error) {
// Some servers may not implement initialized, ignore errors
}
// 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) {
this.serverInfo.resources = [];
}
}
async sendRequest(method, params) {
if (!this.server.httpUrl) {
throw new Error('HTTP URL not configured for server');
}
const id = ++this.messageId;
const request = {
jsonrpc: '2.0',
id,
method,
params,
};
try {
const response = await fetch(this.server.httpUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json, text/event-stream',
},
body: JSON.stringify(request),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
// Handle Server-Sent Events response
if (response.headers.get('content-type')?.includes('text/event-stream')) {
return await this.parseServerSentEvents(response);
}
// Handle regular JSON response
const jsonResponse = await response.json();
if (jsonResponse.error) {
throw new Error(`JSON-RPC Error: ${jsonResponse.error.message}`);
}
return jsonResponse.result;
}
catch (error) {
if (error instanceof Error) {
throw error;
}
throw new Error(`Request failed: ${String(error)}`);
}
}
async parseServerSentEvents(response) {
const reader = response.body?.getReader();
if (!reader) {
throw new Error('No response body available');
}
const decoder = new TextDecoder();
let buffer = '';
let result = null;
try {
while (true) {
const { done, value } = await reader.read();
if (done)
break;
buffer += decoder.decode(value, { stream: true });
// Process complete events
const lines = buffer.split('\n');
buffer = lines.pop() || ''; // Keep incomplete line in buffer
for (const line of lines) {
if (line.startsWith('data: ')) {
try {
const data = JSON.parse(line.slice(6));
if (data.jsonrpc === '2.0') {
if (data.error) {
throw new Error(`JSON-RPC Error: ${data.error.message}`);
}
result = data.result;
}
}
catch (error) {
}
}
}
}
}
finally {
reader.releaseLock();
}
return result;
}
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 HTTP MCP 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() {
this.isConnected = false;
this.serverInfo = null;
}
isConnectedToServer() {
return this.isConnected;
}
async healthCheck() {
if (!this.server.httpUrl) {
return false;
}
try {
const response = await fetch(this.server.httpUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'ping',
params: {},
}),
});
return response.ok;
}
catch (error) {
return false;
}
}
}
exports.HttpMcpClient = HttpMcpClient;
//# sourceMappingURL=http-mcp-client.js.map