UNPKG

zrald

Version:

Advanced Graph RAG MCP Server with sophisticated graph structures, operators, and agentic capabilities for AI agents

217 lines 8.1 kB
import neo4j from 'neo4j-driver'; export class GraphDatabase { driver; session = null; constructor(uri, username, password) { this.driver = neo4j.driver(uri, neo4j.auth.basic(username, password)); } async connect() { try { await this.driver.verifyConnectivity(); this.session = this.driver.session(); console.log('Connected to Neo4j database'); } catch (error) { console.error('Failed to connect to Neo4j:', error); throw error; } } async disconnect() { if (this.session) { await this.session.close(); } await this.driver.close(); } getSession() { if (!this.session) { throw new Error('Database not connected. Call connect() first.'); } return this.session; } // Node Operations async createNode(node) { const session = this.getSession(); const query = ` CREATE (n:${node.type} { id: $id, label: $label, properties: $properties, embedding: $embedding, metadata: $metadata, created_at: datetime($created_at), updated_at: datetime($updated_at) }) `; await session.run(query, { id: node.id, label: node.label, properties: node.properties, embedding: node.embedding || [], metadata: node.metadata || {}, created_at: node.created_at.toISOString(), updated_at: node.updated_at.toISOString() }); } async getNode(id) { const session = this.getSession(); const query = 'MATCH (n {id: $id}) RETURN n'; const result = await session.run(query, { id }); if (result.records.length === 0) { return null; } const record = result.records[0]; const node = record.get('n'); return { id: node.properties.id, type: node.labels[0].toLowerCase(), label: node.properties.label, properties: node.properties.properties || {}, embedding: node.properties.embedding || undefined, metadata: node.properties.metadata || undefined, created_at: new Date(node.properties.created_at), updated_at: new Date(node.properties.updated_at) }; } async getNodesByType(type) { const session = this.getSession(); const query = `MATCH (n:${type}) RETURN n`; const result = await session.run(query); return result.records.map(record => { const node = record.get('n'); return { id: node.properties.id, type: node.labels[0].toLowerCase(), label: node.properties.label, properties: node.properties.properties || {}, embedding: node.properties.embedding || undefined, metadata: node.properties.metadata || undefined, created_at: new Date(node.properties.created_at), updated_at: new Date(node.properties.updated_at) }; }); } // Relationship Operations async createRelationship(relationship) { const session = this.getSession(); const query = ` MATCH (a {id: $source_id}), (b {id: $target_id}) CREATE (a)-[r:${relationship.type} { id: $id, properties: $properties, weight: $weight, confidence: $confidence, metadata: $metadata, created_at: datetime($created_at) }]->(b) `; await session.run(query, { source_id: relationship.source_id, target_id: relationship.target_id, id: relationship.id, properties: relationship.properties, weight: relationship.weight, confidence: relationship.confidence, metadata: relationship.metadata || {}, created_at: relationship.created_at.toISOString() }); } async getRelationships(nodeId, direction = 'both') { const session = this.getSession(); let query; switch (direction) { case 'incoming': query = 'MATCH (n)-[r]->(m {id: $nodeId}) RETURN r, n.id as source_id, m.id as target_id'; break; case 'outgoing': query = 'MATCH (n {id: $nodeId})-[r]->(m) RETURN r, n.id as source_id, m.id as target_id'; break; default: query = 'MATCH (n)-[r]-(m) WHERE n.id = $nodeId OR m.id = $nodeId RETURN r, n.id as source_id, m.id as target_id'; } const result = await session.run(query, { nodeId }); return result.records.map(record => { const rel = record.get('r'); return { id: rel.properties.id, source_id: record.get('source_id'), target_id: record.get('target_id'), type: rel.type, properties: rel.properties.properties || {}, weight: rel.properties.weight || 1.0, confidence: rel.properties.confidence || 1.0, metadata: rel.properties.metadata || {}, created_at: new Date(rel.properties.created_at) }; }); } // Path Finding async findPaths(sourceId, targetId, maxHops = 3) { const session = this.getSession(); const query = ` MATCH path = (start {id: $sourceId})-[*1..${maxHops}]-(end {id: $targetId}) RETURN path LIMIT 10 `; const result = await session.run(query, { sourceId, targetId }); return result.records.map(record => { const path = record.get('path'); const nodes = path.segments.flatMap((segment) => [ this.convertNeo4jNode(segment.start), this.convertNeo4jNode(segment.end) ]); const relationships = path.segments.map((segment) => this.convertNeo4jRelationship(segment.relationship)); return { nodes: [...new Map(nodes.map(n => [n.id, n])).values()], relationships }; }); } // Utility methods convertNeo4jNode(neo4jNode) { return { id: neo4jNode.properties.id, type: neo4jNode.labels[0].toLowerCase(), label: neo4jNode.properties.label, properties: neo4jNode.properties.properties || {}, embedding: neo4jNode.properties.embedding || undefined, metadata: neo4jNode.properties.metadata || undefined, created_at: new Date(neo4jNode.properties.created_at), updated_at: new Date(neo4jNode.properties.updated_at) }; } convertNeo4jRelationship(neo4jRel) { return { id: neo4jRel.properties.id, source_id: neo4jRel.start.toString(), target_id: neo4jRel.end.toString(), type: neo4jRel.type, properties: neo4jRel.properties.properties || {}, weight: neo4jRel.properties.weight || 1.0, confidence: neo4jRel.properties.confidence || 1.0, metadata: neo4jRel.properties.metadata || {}, created_at: new Date(neo4jRel.properties.created_at) }; } // Batch operations async createGraph(graph) { const session = this.getSession(); const tx = session.beginTransaction(); try { // Create nodes for (const node of graph.nodes) { await this.createNode(node); } // Create relationships for (const relationship of graph.relationships) { await this.createRelationship(relationship); } await tx.commit(); } catch (error) { await tx.rollback(); throw error; } } async clearGraph() { const session = this.getSession(); await session.run('MATCH (n) DETACH DELETE n'); } } //# sourceMappingURL=graph-database.js.map