rag-memory-epf-mcp 3.2.1 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -128,6 +128,9 @@ storeDocument(id, content, metadata)
128
128
 
129
129
  ## Changelog
130
130
 
131
+ ### v3.2.1
132
+ - **Fix: `autoLinkEntities` silent failure** — was JOINing a non-existent `observations` table (observations are stored as JSON array column in `entities`). Changed to direct column select + `JSON.parse()`.
133
+
131
134
  ### v3.2.0
132
135
  - **Chunk-level entity linking in `linkEntitiesToDocument`** — entities are now linked only to chunks where they actually appear (using `buildEntityMatcher` word-boundary/CJK matching), instead of blanket-linking to all chunks. Fixes search result domination by heavily-linked documents.
133
136
  - **Graph boost decay + hard cap** — per-entity scores are sorted descending and decayed geometrically (0.5^i): 1st entity 100%, 2nd 50%, 3rd 25%, etc. Hard cap at 0.4 prevents graph signal from overwhelming vector similarity.
package/dist/index.js CHANGED
@@ -9,6 +9,14 @@ import fsSync from 'fs';
9
9
  import path from 'path';
10
10
  import { fileURLToPath } from 'url';
11
11
  import { pipeline, env } from '@huggingface/transformers';
12
+ // Import graphology for graph analytics
13
+ import Graph from 'graphology';
14
+ import louvain from 'graphology-communities-louvain';
15
+ import degree from 'graphology-metrics/centrality/degree.js';
16
+ import betweennessCentrality from 'graphology-metrics/centrality/betweenness.js';
17
+ import closenessCentrality from 'graphology-metrics/centrality/closeness.js';
18
+ import pagerank from 'graphology-metrics/centrality/pagerank.js';
19
+ import modularity from 'graphology-metrics/graph/modularity.js';
12
20
  // Import our new structured tool system
13
21
  import { getAllMCPTools, validateToolArgs, getSystemInfo } from './src/tools/tool-registry.js';
14
22
  // Import migration system
@@ -2079,6 +2087,246 @@ class RAGKnowledgeGraphManager {
2079
2087
  chunks: chunkCount.count
2080
2088
  };
2081
2089
  }
2090
+ // === GRAPH ANALYTICS TOOLS (graphology) ===
2091
+ _buildGraphologyGraph() {
2092
+ if (!this.db)
2093
+ throw new Error('Database not initialized');
2094
+ const graph = new Graph({ type: 'undirected', allowSelfLoops: false });
2095
+ // Load entities as nodes
2096
+ const entities = this.db.prepare('SELECT id, name, entityType FROM entities').all();
2097
+ for (const entity of entities) {
2098
+ graph.addNode(entity.id, { name: entity.name, entityType: entity.entityType });
2099
+ }
2100
+ // Load relationships as edges
2101
+ const relations = this.db.prepare('SELECT id, source_entity, target_entity, relationType FROM relationships').all();
2102
+ for (const rel of relations) {
2103
+ if (graph.hasNode(rel.source_entity) && graph.hasNode(rel.target_entity)) {
2104
+ try {
2105
+ graph.addEdge(rel.source_entity, rel.target_entity, {
2106
+ relationType: rel.relationType,
2107
+ id: rel.id,
2108
+ });
2109
+ }
2110
+ catch (e) {
2111
+ // Skip duplicate edges (graphology undirected merges A→B and B→A)
2112
+ }
2113
+ }
2114
+ }
2115
+ return { graph, entities };
2116
+ }
2117
+ async getGraphMetrics(entityNames, metrics, limit = 10) {
2118
+ if (!this.db)
2119
+ throw new Error('Database not initialized');
2120
+ const { graph } = this._buildGraphologyGraph();
2121
+ if (graph.order === 0) {
2122
+ return { metrics: {}, message: 'Knowledge graph is empty' };
2123
+ }
2124
+ const allMetrics = metrics || ['degree', 'betweenness', 'closeness', 'pagerank'];
2125
+ const result = {};
2126
+ if (allMetrics.includes('degree')) {
2127
+ result.degree = degree.degreeCentrality(graph);
2128
+ }
2129
+ if (allMetrics.includes('betweenness')) {
2130
+ result.betweenness = betweennessCentrality(graph);
2131
+ }
2132
+ if (allMetrics.includes('closeness')) {
2133
+ result.closeness = closenessCentrality(graph);
2134
+ }
2135
+ if (allMetrics.includes('pagerank')) {
2136
+ result.pagerank = pagerank(graph);
2137
+ }
2138
+ // Build id→name map
2139
+ const idToName = new Map();
2140
+ graph.forEachNode((id, attrs) => {
2141
+ idToName.set(id, attrs.name);
2142
+ });
2143
+ // If specific entities requested, filter to those
2144
+ if (entityNames && entityNames.length > 0) {
2145
+ const targetIds = new Set();
2146
+ for (const name of entityNames) {
2147
+ const id = `entity_${name.toLowerCase().replace(/[^a-z0-9]/g, '_')}`;
2148
+ if (graph.hasNode(id))
2149
+ targetIds.add(id);
2150
+ }
2151
+ const filtered = {};
2152
+ for (const [metricName, scores] of Object.entries(result)) {
2153
+ filtered[metricName] = {};
2154
+ for (const id of targetIds) {
2155
+ const name = idToName.get(id) || id;
2156
+ filtered[metricName][name] = scores[id] ?? null;
2157
+ }
2158
+ }
2159
+ return { metrics: filtered, entityCount: graph.order, edgeCount: graph.size };
2160
+ }
2161
+ // Otherwise return top-N per metric
2162
+ const topResults = {};
2163
+ for (const [metricName, scores] of Object.entries(result)) {
2164
+ const sorted = Object.entries(scores)
2165
+ .sort((a, b) => b[1] - a[1])
2166
+ .slice(0, limit)
2167
+ .map(([id, score]) => ({
2168
+ name: idToName.get(id) || id,
2169
+ score: Math.round(score * 10000) / 10000,
2170
+ }));
2171
+ topResults[metricName] = sorted;
2172
+ }
2173
+ return { metrics: topResults, entityCount: graph.order, edgeCount: graph.size };
2174
+ }
2175
+ async detectCommunities(resolution = 1.0) {
2176
+ if (!this.db)
2177
+ throw new Error('Database not initialized');
2178
+ const { graph } = this._buildGraphologyGraph();
2179
+ if (graph.order === 0) {
2180
+ return { communities: [], modularity: 0, message: 'Knowledge graph is empty' };
2181
+ }
2182
+ // Run Louvain community detection — assign to node attributes
2183
+ louvain.assign(graph, { resolution });
2184
+ // Assign isolated nodes (Louvain skips degree-0 nodes)
2185
+ let maxCommunityId = -1;
2186
+ graph.forEachNode((id, attrs) => {
2187
+ if (typeof attrs.community === 'number' && attrs.community > maxCommunityId) {
2188
+ maxCommunityId = attrs.community;
2189
+ }
2190
+ });
2191
+ graph.forEachNode((id, attrs) => {
2192
+ if (attrs.community === undefined) {
2193
+ graph.setNodeAttribute(id, 'community', ++maxCommunityId);
2194
+ }
2195
+ });
2196
+ // Build id→name map
2197
+ const idToName = new Map();
2198
+ graph.forEachNode((id, attrs) => {
2199
+ idToName.set(id, attrs.name);
2200
+ });
2201
+ // Group entities by community
2202
+ const communityMap = new Map();
2203
+ graph.forEachNode((nodeId, attrs) => {
2204
+ const communityId = attrs.community;
2205
+ if (!communityMap.has(communityId)) {
2206
+ communityMap.set(communityId, []);
2207
+ }
2208
+ communityMap.get(communityId).push({
2209
+ name: idToName.get(nodeId) || nodeId,
2210
+ entityType: attrs.entityType,
2211
+ });
2212
+ });
2213
+ // Sort communities by size (largest first)
2214
+ const sortedCommunities = [...communityMap.entries()]
2215
+ .sort((a, b) => b[1].length - a[1].length)
2216
+ .map(([_id, members], index) => ({
2217
+ communityId: index,
2218
+ size: members.length,
2219
+ members: members.sort((a, b) => a.name.localeCompare(b.name)),
2220
+ }));
2221
+ // Calculate modularity (reads 'community' attribute from nodes)
2222
+ const modularityScore = modularity(graph);
2223
+ // Cross-community edges
2224
+ let crossEdges = 0;
2225
+ graph.forEachEdge((_edge, _attrs, source, target) => {
2226
+ const srcCommunity = graph.getNodeAttribute(source, 'community');
2227
+ const tgtCommunity = graph.getNodeAttribute(target, 'community');
2228
+ if (srcCommunity !== tgtCommunity)
2229
+ crossEdges++;
2230
+ });
2231
+ return {
2232
+ communities: sortedCommunities,
2233
+ totalCommunities: sortedCommunities.length,
2234
+ modularity: Math.round(modularityScore * 10000) / 10000,
2235
+ crossCommunityEdges: crossEdges,
2236
+ entityCount: graph.order,
2237
+ edgeCount: graph.size,
2238
+ };
2239
+ }
2240
+ async analyzeGraphStructure() {
2241
+ if (!this.db)
2242
+ throw new Error('Database not initialized');
2243
+ const { graph } = this._buildGraphologyGraph();
2244
+ if (graph.order === 0) {
2245
+ return { message: 'Knowledge graph is empty', entityCount: 0, edgeCount: 0 };
2246
+ }
2247
+ // Density
2248
+ const density = graph.size > 0
2249
+ ? (2 * graph.size) / (graph.order * (graph.order - 1))
2250
+ : 0;
2251
+ // Degree distribution
2252
+ const degrees = [];
2253
+ const isolatedNodes = [];
2254
+ graph.forEachNode((id, attrs) => {
2255
+ const deg = graph.degree(id);
2256
+ degrees.push(deg);
2257
+ if (deg === 0)
2258
+ isolatedNodes.push(attrs.name);
2259
+ });
2260
+ degrees.sort((a, b) => a - b);
2261
+ const avgDegree = degrees.reduce((s, d) => s + d, 0) / degrees.length;
2262
+ const medianDegree = degrees[Math.floor(degrees.length / 2)];
2263
+ // Connected components (BFS)
2264
+ const visited = new Set();
2265
+ const components = [];
2266
+ graph.forEachNode((startId) => {
2267
+ if (visited.has(startId))
2268
+ return;
2269
+ const component = [];
2270
+ const queue = [startId];
2271
+ visited.add(startId);
2272
+ while (queue.length > 0) {
2273
+ const nodeId = queue.shift();
2274
+ component.push(graph.getNodeAttribute(nodeId, 'name'));
2275
+ graph.forEachNeighbor(nodeId, (neighbor) => {
2276
+ if (!visited.has(neighbor)) {
2277
+ visited.add(neighbor);
2278
+ queue.push(neighbor);
2279
+ }
2280
+ });
2281
+ }
2282
+ components.push(component);
2283
+ });
2284
+ components.sort((a, b) => b.length - a.length);
2285
+ // Relationship type distribution
2286
+ const relTypeCount = {};
2287
+ graph.forEachEdge((_edge, attrs) => {
2288
+ const type = attrs.relationType || 'UNKNOWN';
2289
+ relTypeCount[type] = (relTypeCount[type] || 0) + 1;
2290
+ });
2291
+ // Average clustering coefficient
2292
+ let totalClustering = 0;
2293
+ let clusterableNodes = 0;
2294
+ graph.forEachNode((nodeId) => {
2295
+ const neighbors = graph.neighbors(nodeId);
2296
+ if (neighbors.length < 2)
2297
+ return;
2298
+ let triangles = 0;
2299
+ for (let i = 0; i < neighbors.length; i++) {
2300
+ for (let j = i + 1; j < neighbors.length; j++) {
2301
+ if (graph.hasEdge(neighbors[i], neighbors[j]))
2302
+ triangles++;
2303
+ }
2304
+ }
2305
+ const possibleTriangles = (neighbors.length * (neighbors.length - 1)) / 2;
2306
+ totalClustering += triangles / possibleTriangles;
2307
+ clusterableNodes++;
2308
+ });
2309
+ const avgClustering = clusterableNodes > 0 ? totalClustering / clusterableNodes : 0;
2310
+ return {
2311
+ entityCount: graph.order,
2312
+ edgeCount: graph.size,
2313
+ density: Math.round(density * 10000) / 10000,
2314
+ connectedComponents: {
2315
+ count: components.length,
2316
+ largest: components[0]?.length || 0,
2317
+ sizes: components.map(c => c.length),
2318
+ isolatedNodes,
2319
+ },
2320
+ degreeDistribution: {
2321
+ min: degrees[0],
2322
+ max: degrees[degrees.length - 1],
2323
+ avg: Math.round(avgDegree * 100) / 100,
2324
+ median: medianDegree,
2325
+ },
2326
+ averageClusteringCoefficient: Math.round(avgClustering * 10000) / 10000,
2327
+ relationshipTypes: relTypeCount,
2328
+ };
2329
+ }
2082
2330
  // === MIGRATION TOOLS ===
2083
2331
  async getMigrationStatus() {
2084
2332
  if (!this.db)
@@ -2218,6 +2466,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
2218
2466
  return { content: [{ type: "text", text: JSON.stringify(await ragKgManager.runMigrations(), null, 2) }] };
2219
2467
  case "rollbackMigration":
2220
2468
  return { content: [{ type: "text", text: JSON.stringify(await ragKgManager.rollbackMigration(validatedArgs.targetVersion), null, 2) }] };
2469
+ // Graph Analytics tools (graphology)
2470
+ case "getGraphMetrics":
2471
+ return { content: [{ type: "text", text: JSON.stringify(await ragKgManager.getGraphMetrics(validatedArgs.entityNames, validatedArgs.metrics, validatedArgs.limit || 10), null, 2) }] };
2472
+ case "detectCommunities":
2473
+ return { content: [{ type: "text", text: JSON.stringify(await ragKgManager.detectCommunities(validatedArgs.resolution || 1.0), null, 2) }] };
2474
+ case "analyzeGraphStructure":
2475
+ return { content: [{ type: "text", text: JSON.stringify(await ragKgManager.analyzeGraphStructure(), null, 2) }] };
2221
2476
  default:
2222
2477
  throw new Error(`Unknown tool: ${name}`);
2223
2478
  }
@@ -0,0 +1,9 @@
1
+ import { ToolDefinition } from './types.js';
2
+ export declare const getGraphMetricsTool: ToolDefinition;
3
+ export declare const detectCommunitiesTool: ToolDefinition;
4
+ export declare const analyzeGraphStructureTool: ToolDefinition;
5
+ export declare const graphAnalyticsTools: {
6
+ getGraphMetrics: ToolDefinition;
7
+ detectCommunities: ToolDefinition;
8
+ analyzeGraphStructure: ToolDefinition;
9
+ };
@@ -0,0 +1,221 @@
1
+ import { z } from 'zod';
2
+ // === GET GRAPH METRICS TOOL ===
3
+ const getGraphMetricsCapability = {
4
+ description: 'Calculate centrality metrics for entities using graphology graph analysis',
5
+ parameters: {
6
+ type: 'object',
7
+ properties: {
8
+ entityNames: {
9
+ type: 'array',
10
+ description: 'Entity names to calculate metrics for. If empty, returns top entities by each metric.',
11
+ items: { type: 'string' },
12
+ },
13
+ metrics: {
14
+ type: 'array',
15
+ description: 'Which metrics to compute: degree, betweenness, closeness, pagerank',
16
+ items: { type: 'string' },
17
+ },
18
+ limit: {
19
+ type: 'number',
20
+ description: 'Max entities to return when entityNames is empty (default 10)',
21
+ default: 10,
22
+ },
23
+ },
24
+ required: [],
25
+ },
26
+ };
27
+ const getGraphMetricsDescription = () => `<description>
28
+ Calculate centrality metrics for entities using graphology graph analysis algorithms.
29
+ **Identifies the most important, influential, and bridging entities in your knowledge graph.**
30
+ Supports degree, betweenness, closeness centrality and PageRank.
31
+ </description>
32
+
33
+ <importantNotes>
34
+ - (!important!) **Builds in-memory graph** from SQLite data — lightweight for typical knowledge graphs
35
+ - (!important!) Returns centrality scores normalized to 0-1 range
36
+ - (!important!) When no entityNames provided, returns top entities ranked by each metric
37
+ - (!important!) Useful for identifying knowledge hubs, bridges, and peripheral entities
38
+ </importantNotes>
39
+
40
+ <whenToUseThisTool>
41
+ - To find the most connected/important entities in your knowledge graph
42
+ - To identify bridge entities that connect different knowledge domains
43
+ - To discover peripheral entities that may need more connections
44
+ - For knowledge graph health analysis and optimization
45
+ - Before consolidation — to identify which entities are structurally important
46
+ </whenToUseThisTool>
47
+
48
+ <features>
49
+ - Degree centrality: most connected entities (hub detection)
50
+ - Betweenness centrality: entities bridging different clusters
51
+ - Closeness centrality: entities with shortest average distance to all others
52
+ - PageRank: recursive importance based on connections to important entities
53
+ - Supports both targeted (specific entities) and discovery (top-N) modes
54
+ </features>
55
+
56
+ <bestPractices>
57
+ - Use without entityNames first to discover important entities
58
+ - Combine with detectCommunities for deeper structural analysis
59
+ - High betweenness + low degree = critical bridge (fragile point)
60
+ - High degree + high PageRank = knowledge hub
61
+ - Run periodically to track how graph structure evolves
62
+ </bestPractices>
63
+
64
+ <parameters>
65
+ - entityNames: (optional) Specific entities to analyze. If omitted, returns top entities by each metric.
66
+ - metrics: (optional) Array of metrics to compute: "degree", "betweenness", "closeness", "pagerank". Default: all.
67
+ - limit: (optional) Max results per metric when entityNames is empty. Default: 10.
68
+ </parameters>
69
+
70
+ <examples>
71
+ - Top entities: {} (returns top 10 by all metrics)
72
+ - Specific entities: {"entityNames": ["Entity A", "Entity B"]}
73
+ - PageRank only: {"metrics": ["pagerank"], "limit": 20}
74
+ </examples>`;
75
+ const getGraphMetricsSchema = {
76
+ entityNames: z.array(z.string().describe('Entity name')).optional().describe('Entity names to analyze'),
77
+ metrics: z.array(z.string().describe('Metric name')).optional().describe('Metrics to compute: degree, betweenness, closeness, pagerank'),
78
+ limit: z.number().optional().default(10).describe('Max results per metric'),
79
+ };
80
+ export const getGraphMetricsTool = {
81
+ capability: getGraphMetricsCapability,
82
+ description: getGraphMetricsDescription,
83
+ schema: getGraphMetricsSchema,
84
+ annotations: { readOnlyHint: true },
85
+ };
86
+ // === DETECT COMMUNITIES TOOL ===
87
+ const detectCommunitiesCapability = {
88
+ description: 'Detect communities/clusters in the knowledge graph using Louvain algorithm',
89
+ parameters: {
90
+ type: 'object',
91
+ properties: {
92
+ resolution: {
93
+ type: 'number',
94
+ description: 'Resolution parameter for Louvain (higher = more communities). Default: 1.0',
95
+ default: 1.0,
96
+ },
97
+ },
98
+ required: [],
99
+ },
100
+ };
101
+ const detectCommunitiesDescription = () => `<description>
102
+ Detect communities (clusters) in the knowledge graph using the Louvain modularity algorithm.
103
+ **Reveals natural groupings and topic clusters within your knowledge base.**
104
+ Automatically identifies which entities belong together based on connection patterns.
105
+ </description>
106
+
107
+ <importantNotes>
108
+ - (!important!) Uses Louvain algorithm — fast and effective for modularity optimization
109
+ - (!important!) Returns community assignments for every entity
110
+ - (!important!) Higher resolution parameter produces more, smaller communities
111
+ - (!important!) Modularity score indicates clustering quality (0-1, higher = better defined clusters)
112
+ </importantNotes>
113
+
114
+ <whenToUseThisTool>
115
+ - To discover natural topic clusters in your knowledge graph
116
+ - To understand how your knowledge is organized structurally
117
+ - Before reorganization — to see which entities naturally group together
118
+ - For identifying isolated clusters that may need cross-linking
119
+ - To validate that related entities are actually well-connected
120
+ </whenToUseThisTool>
121
+
122
+ <features>
123
+ - Louvain community detection with configurable resolution
124
+ - Returns named communities with member entities
125
+ - Modularity score for clustering quality assessment
126
+ - Community size distribution for balance analysis
127
+ - Cross-community relationship identification
128
+ </features>
129
+
130
+ <bestPractices>
131
+ - Start with default resolution (1.0), adjust if clusters are too large/small
132
+ - Resolution < 1.0 = fewer, larger communities; > 1.0 = more, smaller communities
133
+ - Single-entity communities may indicate orphaned or poorly connected entities
134
+ - Compare community structure over time to track knowledge evolution
135
+ - Use with getGraphMetrics to find important entities within each community
136
+ </bestPractices>
137
+
138
+ <parameters>
139
+ - resolution: (optional) Louvain resolution. Default: 1.0. Lower = fewer clusters, Higher = more clusters.
140
+ </parameters>
141
+
142
+ <examples>
143
+ - Default clustering: {}
144
+ - Fine-grained: {"resolution": 2.0}
145
+ - Coarse: {"resolution": 0.5}
146
+ </examples>`;
147
+ const detectCommunitiesSchema = {
148
+ resolution: z.number().optional().default(1.0).describe('Louvain resolution parameter'),
149
+ };
150
+ export const detectCommunitiesTool = {
151
+ capability: detectCommunitiesCapability,
152
+ description: detectCommunitiesDescription,
153
+ schema: detectCommunitiesSchema,
154
+ annotations: { readOnlyHint: true },
155
+ };
156
+ // === ANALYZE GRAPH STRUCTURE TOOL ===
157
+ const analyzeGraphStructureCapability = {
158
+ description: 'Analyze overall knowledge graph structure: density, components, diameter, clustering',
159
+ parameters: {
160
+ type: 'object',
161
+ properties: {},
162
+ required: [],
163
+ },
164
+ };
165
+ const analyzeGraphStructureDescription = () => `<description>
166
+ Analyze the overall structural properties of your knowledge graph.
167
+ **Provides a health dashboard for graph connectivity, density, and structure.**
168
+ Complements getKnowledgeGraphStats (which counts entities/relations) with structural analysis.
169
+ </description>
170
+
171
+ <importantNotes>
172
+ - (!important!) Returns graph-theoretic metrics: density, components, diameter, clustering coefficient
173
+ - (!important!) Identifies disconnected components (isolated subgraphs)
174
+ - (!important!) Detects structural issues: low density, fragmentation, bottlenecks
175
+ - (!important!) Computationally heavier than stats — use periodically, not every session
176
+ </importantNotes>
177
+
178
+ <whenToUseThisTool>
179
+ - For periodic graph health assessment (weekly or after major changes)
180
+ - To detect fragmentation — disconnected components that should be linked
181
+ - To measure graph density — is the knowledge well-interconnected?
182
+ - Before and after consolidation — to measure structural improvement
183
+ - When graph feels "sparse" and you want to quantify it
184
+ </whenToUseThisTool>
185
+
186
+ <features>
187
+ - Graph density (actual edges / possible edges)
188
+ - Connected component analysis with sizes
189
+ - Average clustering coefficient (local connectivity)
190
+ - Degree distribution statistics (min, max, avg, median)
191
+ - Isolated node detection
192
+ - Relationship type distribution
193
+ </features>
194
+
195
+ <bestPractices>
196
+ - Run after major entity additions to check integration
197
+ - Compare density over time — decreasing density may indicate growing but disconnected knowledge
198
+ - Multiple small components suggest domain silos that need cross-linking
199
+ - Use alongside detectCommunities for complete structural understanding
200
+ </bestPractices>
201
+
202
+ <parameters>
203
+ - None required — analyzes the entire graph structure
204
+ </parameters>
205
+
206
+ <examples>
207
+ - Full analysis: {} (no parameters needed)
208
+ </examples>`;
209
+ const analyzeGraphStructureSchema = {};
210
+ export const analyzeGraphStructureTool = {
211
+ capability: analyzeGraphStructureCapability,
212
+ description: analyzeGraphStructureDescription,
213
+ schema: analyzeGraphStructureSchema,
214
+ annotations: { readOnlyHint: true },
215
+ };
216
+ // === EXPORT ===
217
+ export const graphAnalyticsTools = {
218
+ getGraphMetrics: getGraphMetricsTool,
219
+ detectCommunities: detectCommunitiesTool,
220
+ analyzeGraphStructure: analyzeGraphStructureTool,
221
+ };
@@ -1,5 +1,8 @@
1
1
  import { ToolDefinition, MCPTool } from './types.js';
2
2
  export declare const allTools: {
3
+ getGraphMetrics: ToolDefinition;
4
+ detectCommunities: ToolDefinition;
5
+ analyzeGraphStructure: ToolDefinition;
3
6
  readGraph: ToolDefinition;
4
7
  searchNodes: ToolDefinition;
5
8
  openNodes: ToolDefinition;
@@ -53,6 +56,7 @@ export declare function getToolsByCategory(): {
53
56
  knowledgeGraph: string[];
54
57
  rag: string[];
55
58
  graphQuery: string[];
59
+ graphAnalytics: string[];
56
60
  migration: string[];
57
61
  all: string[];
58
62
  };
@@ -73,12 +77,14 @@ export declare function getSystemInfo(): {
73
77
  knowledgeGraph: number;
74
78
  rag: number;
75
79
  graphQuery: number;
80
+ graphAnalytics: number;
76
81
  total: number;
77
82
  };
78
83
  availableTools: {
79
84
  knowledgeGraph: string[];
80
85
  rag: string[];
81
86
  graphQuery: string[];
87
+ graphAnalytics: string[];
82
88
  migration: string[];
83
89
  all: string[];
84
90
  };
@@ -2,14 +2,15 @@ import { z } from 'zod';
2
2
  import { knowledgeGraphTools } from './knowledge-graph-tools.js';
3
3
  import { ragTools } from './rag-tools.js';
4
4
  import { graphQueryTools } from './graph-query-tools.js';
5
+ import { graphAnalyticsTools } from './graph-analytics-tools.js';
5
6
  import { migrationTools } from './migration-tools.js';
6
7
  // Central registry of all tools
7
8
  export const allTools = {
8
9
  ...knowledgeGraphTools,
9
10
  ...ragTools,
10
11
  ...graphQueryTools,
12
+ ...graphAnalyticsTools,
11
13
  ...migrationTools,
12
- // Add other tool categories here as needed
13
14
  };
14
15
  // Global settings for tool descriptions
15
16
  export const globalSettings = {
@@ -153,6 +154,7 @@ export function getToolsByCategory() {
153
154
  knowledgeGraph: Object.keys(knowledgeGraphTools),
154
155
  rag: Object.keys(ragTools),
155
156
  graphQuery: Object.keys(graphQueryTools),
157
+ graphAnalytics: Object.keys(graphAnalyticsTools),
156
158
  migration: Object.keys(migrationTools),
157
159
  all: Object.keys(allTools),
158
160
  };
@@ -178,6 +180,7 @@ export function getSystemInfo() {
178
180
  knowledgeGraph: categories.knowledgeGraph.length,
179
181
  rag: categories.rag.length,
180
182
  graphQuery: categories.graphQuery.length,
183
+ graphAnalytics: categories.graphAnalytics.length,
181
184
  total: categories.all.length,
182
185
  },
183
186
  availableTools: categories,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rag-memory-epf-mcp",
3
- "version": "3.2.1",
3
+ "version": "3.3.0",
4
4
  "description": "MCP server for project-local RAG memory with knowledge graph and multilingual vector search",
5
5
  "license": "MIT",
6
6
  "author": "bripin123",
@@ -27,6 +27,11 @@
27
27
  "@huggingface/transformers": "^3.5.1",
28
28
  "@modelcontextprotocol/sdk": "^1.27.1",
29
29
  "better-sqlite3": "^12.8.0",
30
+ "graphology": "^0.26.0",
31
+ "graphology-communities-louvain": "^2.0.2",
32
+ "graphology-metrics": "^2.4.0",
33
+ "graphology-shortest-path": "^2.1.0",
34
+ "graphology-types": "^0.24.8",
30
35
  "sqlite-vec": "^0.1.7",
31
36
  "tiktoken": "^1.0.17",
32
37
  "zod": "^3.25.28"