Skip to main content
Glama

build-knowledge-graph

Analyze code repositories to create dependency graphs and visualize relationships for better understanding of project structure and external dependencies.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
repositoryUrlYes
depthNo
includeExternalDependenciesNo

Implementation Reference

  • Registration of the MCP tool 'build-knowledge-graph', including Zod input schema validation and thin handler wrapper that calls the core buildKnowledgeGraph function and formats response.
    server.tool( "build-knowledge-graph", { repositoryUrl: z.string(), depth: z.number().default(2), includeExternalDependencies: z.boolean().default(true) }, async ({ repositoryUrl, depth, includeExternalDependencies }) => { try { const result = await buildKnowledgeGraph( repositoryUrl, depth, includeExternalDependencies ); return { content: [{ type: "text", text: `Knowledge graph built successfully. Nodes: ${result.nodes}, Relationships: ${result.relationships}` }] }; } catch (error) { return { content: [{ type: "text", text: `Error building knowledge graph: ${(error as Error).message}` }], isError: true }; } } );
  • Input schema for the tool using Zod: repository URL (required), analysis depth (default 2), include external deps (default true).
    { repositoryUrl: z.string(), depth: z.number().default(2), includeExternalDependencies: z.boolean().default(true) },
  • Core handler logic for building the knowledge graph: initializes SQLite DB, clones repository, lists files, analyzes each file's code to extract imports/classes/functions, creates corresponding graph nodes and relationships (contains, imports, defines), commits transaction.
    export async function buildKnowledgeGraph( repositoryUrl: string, depth: number = 2, includeExternalDependencies: boolean = true ): Promise<{ nodes: number, relationships: number }> { // Initialize db if needed if (!db) { db = await createDatabase("knowledge"); } if (!db) { throw new Error("Database not initialized"); } // Get repository const repoPath = await getRepository(repositoryUrl); const files = listFiles(repoPath); let nodesCount = 0; let relationshipsCount = 0; await db.exec('BEGIN TRANSACTION'); try { // Add repository node const repoId = `repo:${uuidv4()}`; addNode({ id: repoId, type: "repository", name: path.basename(repositoryUrl), attributes: { url: repositoryUrl, fileCount: files.length } }); nodesCount++; // Process each file for (const file of files) { const fullPath = path.join(repoPath, file); try { const code = fs.readFileSync(fullPath, 'utf8'); const fileLanguage = path.extname(file).slice(1); // Create file node const fileId = `file:${uuidv4()}`; addNode({ id: fileId, type: "file", name: file, attributes: { language: fileLanguage, size: code.length, path: file } }); nodesCount++; // Link file to repository addRelationship({ id: `rel:${uuidv4()}`, type: "contains", sourceId: repoId, targetId: fileId, attributes: {} }); relationshipsCount++; // Analyze code to get dependencies, classes, functions const analysis = analyzeCode(code, fileLanguage); // Process imports/dependencies for (const importItem of analysis.imports) { let targetId: string; // Check if the import already exists as a node const existingNode = await findNodeByName(importItem); if (existingNode) { targetId = existingNode.id; } else { // Create a new node for the import targetId = `dep:${uuidv4()}`; addNode({ id: targetId, type: "dependency", name: importItem, attributes: { isExternal: !files.some(f => f.endsWith(importItem) || f.includes(importItem)) } }); nodesCount++; } // Link file to dependency addRelationship({ id: `rel:${uuidv4()}`, type: "imports", sourceId: fileId, targetId: targetId, attributes: {} }); relationshipsCount++; } // Process classes for (const className of analysis.classes) { const classId = `class:${uuidv4()}`; addNode({ id: classId, type: "class", name: className, attributes: { file: file } }); nodesCount++; // Link class to file addRelationship({ id: `rel:${uuidv4()}`, type: "defines", sourceId: fileId, targetId: classId, attributes: {} }); relationshipsCount++; } // Process functions for (const funcName of analysis.functions) { const funcId = `func:${uuidv4()}`; addNode({ id: funcId, type: "function", name: funcName, attributes: { file: file } }); nodesCount++; // Link function to file addRelationship({ id: `rel:${uuidv4()}`, type: "defines", sourceId: fileId, targetId: funcId, attributes: {} }); relationshipsCount++; } } catch (error) { console.warn(`Error processing file ${file}: ${(error as Error).message}`); } } await db.exec('COMMIT'); return { nodes: nodesCount, relationships: relationshipsCount }; } catch (error) { await db.exec('ROLLBACK'); throw error; } }
  • Helper function to add or update a node in the knowledge graph database.
    async function addNode(node: GraphNode): Promise<void> { if (!db) { db = await createDatabase("knowledge"); } if (!db) { throw new Error("Database not initialized"); } await db.run( `INSERT OR REPLACE INTO nodes (id, type, name, attributes) VALUES (?, ?, ?, ?)`, [node.id, node.type, node.name, JSON.stringify(node.attributes)] ); }
  • Helper function to add or update a relationship in the knowledge graph database.
    async function addRelationship(relationship: GraphRelationship): Promise<void> { if (!db) { db = await createDatabase("knowledge"); } if (!db) { throw new Error("Database not initialized"); } await db.run( `INSERT OR REPLACE INTO relationships (id, type, sourceId, targetId, attributes) VALUES (?, ?, ?, ?, ?)`, [ relationship.id, relationship.type, relationship.sourceId, relationship.targetId, JSON.stringify(relationship.attributes) ] ); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/0xjcf/MCP_CodeAnalysis'

If you have feedback or need assistance with the MCP directory API, please join our Discord server