remcode
Version:
Turn your AI assistant into a codebase expert. Intelligent code analysis, semantic search, and software engineering guidance through MCP integration.
171 lines (170 loc) • 7.44 kB
JavaScript
/**
* Pinecone MCP Handler
*
* Handles Pinecone-related MCP requests, allowing AI assistants
* to interact with vector embeddings stored in Pinecone.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.PineconeMCPHandler = void 0;
const logger_1 = require("../../utils/logger");
const pinecone_1 = require("../../vectorizers/storage/pinecone");
const logger = (0, logger_1.getLogger)('Pinecone-MCP');
class PineconeMCPHandler {
constructor(options) {
this.pineconeStorage = null;
this.options = options;
}
async initialize() {
try {
if (!this.options.apiKey) {
logger.warn('Pinecone API key not provided. Pinecone MCP handler will not be fully functional.');
return;
}
// Initialize Pinecone storage with the default index
this.pineconeStorage = new pinecone_1.PineconeStorage({
apiKey: this.options.apiKey,
indexName: 'remcode-default'
});
await this.pineconeStorage.initialize();
logger.info('Pinecone MCP handler initialized successfully');
}
catch (error) {
logger.error(`Failed to initialize Pinecone MCP handler: ${error instanceof Error ? error.message : String(error)}`);
throw error;
}
}
async handleRequest(req, res) {
const action = req.params.action;
try {
if (!this.pineconeStorage) {
res.status(500).json({ error: 'Pinecone storage not initialized' });
return;
}
switch (action) {
case 'query':
await this.handleQuery(req, res);
break;
case 'upsert':
await this.handleUpsert(req, res);
break;
case 'delete':
await this.handleDelete(req, res);
break;
case 'list-indexes':
await this.handleListIndexes(req, res);
break;
default:
res.status(400).json({ error: `Unknown action: ${action}` });
}
}
catch (error) {
logger.error(`Error handling Pinecone MCP request: ${error instanceof Error ? error.message : String(error)}`);
res.status(500).json({ error: error instanceof Error ? error.message : 'Unknown error' });
}
}
async handleToolRequest(req, res) {
const { tool, parameters } = req.body;
try {
if (!this.pineconeStorage) {
res.status(500).json({ error: 'Pinecone storage not initialized' });
return;
}
switch (tool) {
case 'pinecone_query':
await this.handleQuery(req, res, parameters);
break;
case 'pinecone_upsert':
await this.handleUpsert(req, res, parameters);
break;
case 'pinecone_delete':
await this.handleDelete(req, res, parameters);
break;
case 'pinecone_list_indexes':
await this.handleListIndexes(req, res);
break;
default:
res.status(400).json({ error: `Unknown tool: ${tool}` });
}
}
catch (error) {
logger.error(`Error handling Pinecone tool request: ${error instanceof Error ? error.message : String(error)}`);
res.status(500).json({ error: error instanceof Error ? error.message : 'Unknown error' });
}
}
async handleQuery(req, res, params) {
const queryParams = params || req.body;
const { text, topK = 10, filter, namespace = '' } = queryParams;
if (!text) {
res.status(400).json({ error: 'Query text is required' });
return;
}
try {
// In a complete implementation, we would:
// 1. Generate embeddings from the text using an embedding model
// 2. Query Pinecone with those embeddings
// For now, we'll use a mock embedding
const mockEmbedding = new Array(768).fill(0).map(() => Math.random() - 0.5);
// Use our enhanced PineconeStorage to perform the query
const matches = await this.pineconeStorage.queryVectors(mockEmbedding, topK, filter, namespace);
res.status(200).json({ matches });
}
catch (error) {
logger.error(`Error querying Pinecone: ${error instanceof Error ? error.message : String(error)}`);
res.status(500).json({ error: error instanceof Error ? error.message : 'Unknown error' });
}
}
async handleUpsert(req, res, params) {
const upsertParams = params || req.body;
const { vectors, namespace = '' } = upsertParams;
if (!vectors || !Array.isArray(vectors)) {
res.status(400).json({ error: 'Vectors array is required' });
return;
}
try {
// In a real implementation, we would upsert the vectors to Pinecone
// For now, we'll return a stub response
res.status(200).json({ upsertedCount: vectors.length });
}
catch (error) {
logger.error(`Error upserting to Pinecone: ${error instanceof Error ? error.message : String(error)}`);
res.status(500).json({ error: error instanceof Error ? error.message : 'Unknown error' });
}
}
async handleDelete(req, res, params) {
const deleteParams = params || req.body;
const { ids, deleteAll = false, filter, namespace = '' } = deleteParams;
if (!deleteAll && (!ids || !Array.isArray(ids))) {
res.status(400).json({ error: 'Either ids array or deleteAll flag is required' });
return;
}
try {
// Use our enhanced PineconeStorage to perform the delete operation
const deletedCount = await this.pineconeStorage.deleteVectors(ids, deleteAll, filter, namespace);
res.status(200).json({
deletedCount: deletedCount === -1 ? (deleteAll ? 'all' : 'unknown') : deletedCount
});
}
catch (error) {
logger.error(`Error deleting from Pinecone: ${error instanceof Error ? error.message : String(error)}`);
res.status(500).json({ error: error instanceof Error ? error.message : 'Unknown error' });
}
}
async handleListIndexes(req, res) {
try {
// In a real implementation, we would list all available Pinecone indexes
// For now, we'll return a stub response
res.status(200).json({
indexes: [
{ name: 'remcode-default', dimension: 768, metric: 'cosine', status: 'Ready' },
{ name: 'remcode-test', dimension: 768, metric: 'cosine', status: 'Ready' }
]
});
}
catch (error) {
logger.error(`Error listing Pinecone indexes: ${error instanceof Error ? error.message : String(error)}`);
res.status(500).json({ error: error instanceof Error ? error.message : 'Unknown error' });
}
}
}
exports.PineconeMCPHandler = PineconeMCPHandler;
;