Skip to content

Commit b90d87f

Browse files
committed
Refactor detect_patterns: run all analyses by default, simplify API, improve docstring, handle errors gracefully
1 parent 4c0d85e commit b90d87f

File tree

1 file changed

+54
-27
lines changed

1 file changed

+54
-27
lines changed

src/graphistry_mcp_server/server.py

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -214,24 +214,34 @@ async def apply_layout(graph_id: str, layout: str) -> Dict[str, Any]:
214214
raise
215215

216216
@mcp.tool()
217-
async def detect_patterns(graph_id: str,
218-
analysis_type: str,
219-
options: Optional[Dict[str, Any]] = None,
220-
ctx: Optional[Context] = None) -> Dict[str, Any]:
221-
"""Identify patterns, communities, and anomalies within graphs.
222-
217+
async def detect_patterns(graph_id: str, ctx: Optional[Context] = None) -> Dict[str, Any]:
218+
"""
219+
Identify patterns, communities, and anomalies within graphs. Runs all supported analyses and returns a combined report.
220+
223221
Args:
224222
graph_id: ID of the graph to analyze
225-
analysis_type: Type of pattern analysis to perform
226-
options: Additional options for the analysis
227223
ctx: MCP context for progress reporting
224+
225+
Returns:
226+
Dictionary with results from all analyses that succeeded. Keys may include:
227+
- degree_centrality
228+
- betweenness_centrality
229+
- closeness_centrality
230+
- communities (if community detection is available)
231+
- shortest_path (if path finding is possible)
232+
- path_length
233+
- anomalies (if anomaly detection is available)
234+
- errors (dict of analysis_type -> error message)
235+
236+
Example:
237+
result = await mcp.call_tool("detect_patterns", {"graph_id": "graph_1"})
228238
"""
229239
try:
230240
if graph_id not in graph_cache:
231241
raise ValueError(f"Graph not found: {graph_id}")
232242

233243
if ctx:
234-
await ctx.info(f"Starting {analysis_type} analysis...")
244+
await ctx.info("Starting pattern detection (all analyses)...")
235245

236246
graph_data = graph_cache[graph_id]
237247
nx_graph = graph_data["nx_graph"]
@@ -245,30 +255,47 @@ async def detect_patterns(graph_id: str,
245255
raise ValueError("Graph data not available for analysis")
246256

247257
results = {}
248-
if analysis_type == "community_detection":
249-
# Implement community detection
250-
pass
251-
elif analysis_type == "centrality":
258+
errors = {}
259+
260+
# Centrality
261+
try:
252262
results["degree_centrality"] = nx.degree_centrality(nx_graph)
253263
results["betweenness_centrality"] = nx.betweenness_centrality(nx_graph)
254264
results["closeness_centrality"] = nx.closeness_centrality(nx_graph)
255-
elif analysis_type == "path_finding":
256-
if not options or "source" not in options or "target" not in options:
257-
raise ValueError("source and target nodes required for path finding")
258-
try:
259-
path = nx.shortest_path(nx_graph, options["source"], options["target"])
265+
except Exception as e:
266+
errors["centrality"] = str(e)
267+
268+
# Community detection
269+
try:
270+
import community as community_louvain
271+
partition = community_louvain.best_partition(nx_graph)
272+
results["communities"] = partition
273+
except Exception as e:
274+
errors["community_detection"] = str(e)
275+
276+
# Path finding (try between first two nodes if possible)
277+
try:
278+
nodes = list(nx_graph.nodes())
279+
if len(nodes) >= 2:
280+
path = nx.shortest_path(nx_graph, nodes[0], nodes[1])
260281
results["shortest_path"] = path
261282
results["path_length"] = len(path) - 1
262-
except nx.NetworkXNoPath:
263-
results["error"] = "No path exists between specified nodes"
264-
elif analysis_type == "anomaly_detection":
265-
# Implement anomaly detection
266-
pass
267-
else:
268-
raise ValueError(f"Unsupported analysis type: {analysis_type}")
269-
283+
except Exception as e:
284+
errors["path_finding"] = str(e)
285+
286+
# Anomaly detection (placeholder)
287+
try:
288+
# Example: nodes with degree 1 as "anomalies"
289+
anomalies = [n for n, d in nx_graph.degree() if d == 1]
290+
results["anomalies"] = anomalies
291+
except Exception as e:
292+
errors["anomaly_detection"] = str(e)
293+
294+
if errors:
295+
results["errors"] = errors
296+
270297
if ctx:
271-
await ctx.info("Analysis complete!")
298+
await ctx.info("Pattern detection complete!")
272299

273300
return results
274301
except Exception as e:

0 commit comments

Comments
 (0)