From 2e39ab0e401ed03ec97fdf348746588d44304598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yanis=20Gu=C3=A9rault?= Date: Wed, 22 Jul 2026 12:02:25 +0200 Subject: [PATCH 1/2] feat(serve): add multi-graph support to MCP server Enable serving multiple knowledge graphs from a single MCP endpoint. Always registry-based: single graph = 1-entry registry, multi-graph = directory scan via --graphs-dir flag or GRAPHS_DIR env var. - Add GraphContext dataclass + GraphRegistry (from_path, from_directory) - Refactor _build_server to accept GraphRegistry with per-call resolution - Tool visibility keyed on registry size: list_graphs/use_graph when >1, PR tools when ==1. New graph param on all tool schemas. - Add --graphs-dir CLI flag forcing HTTP transport with auto-rescan - Remove multi_serve.py and graphify-multi-mcp entry point (consolidated) Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitignore | 1 + Dockerfile | 29 +- README.md | 28 ++ docker-compose.multi.yml | 18 + graphify/serve.py | 437 ++++++++++++++---- graphify/skill-agents.md | 3 +- graphify/skill-aider.md | 1 + graphify/skill-amp.md | 3 +- graphify/skill-claw.md | 3 +- graphify/skill-codex.md | 3 +- graphify/skill-copilot.md | 3 +- graphify/skill-devin.md | 1 + graphify/skill-droid.md | 3 +- graphify/skill-kilo.md | 3 +- graphify/skill-kiro.md | 3 +- graphify/skill-opencode.md | 3 +- graphify/skill-pi.md | 3 +- graphify/skill-trae.md | 3 +- graphify/skill-vscode.md | 3 +- graphify/skill-windows.md | 3 +- graphify/skill.md | 3 +- graphify/skills/agents/references/exports.md | 14 + graphify/skills/amp/references/exports.md | 14 + graphify/skills/claude/references/exports.md | 14 + graphify/skills/claw/references/exports.md | 14 + graphify/skills/codex/references/exports.md | 14 + graphify/skills/copilot/references/exports.md | 14 + graphify/skills/droid/references/exports.md | 14 + graphify/skills/kilo/references/exports.md | 14 + graphify/skills/kiro/references/exports.md | 14 + .../skills/opencode/references/exports.md | 14 + graphify/skills/pi/references/exports.md | 14 + graphify/skills/trae/references/exports.md | 14 + graphify/skills/vscode/references/exports.md | 14 + graphify/skills/windows/references/exports.md | 14 + tests/test_serve.py | 322 +++++++++++++ tests/test_serve_http.py | 64 +-- .../expected/graphify__skill-agents.md | 3 +- .../expected/graphify__skill-aider.md | 1 + .../skillgen/expected/graphify__skill-amp.md | 3 +- .../skillgen/expected/graphify__skill-claw.md | 3 +- .../expected/graphify__skill-codex.md | 3 +- .../expected/graphify__skill-copilot.md | 3 +- .../expected/graphify__skill-devin.md | 1 + .../expected/graphify__skill-droid.md | 3 +- .../skillgen/expected/graphify__skill-kilo.md | 3 +- .../skillgen/expected/graphify__skill-kiro.md | 3 +- .../expected/graphify__skill-opencode.md | 3 +- tools/skillgen/expected/graphify__skill-pi.md | 3 +- .../skillgen/expected/graphify__skill-trae.md | 3 +- .../expected/graphify__skill-vscode.md | 3 +- .../expected/graphify__skill-windows.md | 3 +- tools/skillgen/expected/graphify__skill.md | 3 +- ...fy__skills__agents__references__exports.md | 14 + ...phify__skills__amp__references__exports.md | 14 + ...fy__skills__claude__references__exports.md | 14 + ...hify__skills__claw__references__exports.md | 14 + ...ify__skills__codex__references__exports.md | 14 + ...y__skills__copilot__references__exports.md | 14 + ...ify__skills__droid__references__exports.md | 14 + ...hify__skills__kilo__references__exports.md | 14 + ...hify__skills__kiro__references__exports.md | 14 + ...__skills__opencode__references__exports.md | 14 + ...aphify__skills__pi__references__exports.md | 14 + ...hify__skills__trae__references__exports.md | 14 + ...fy__skills__vscode__references__exports.md | 14 + ...y__skills__windows__references__exports.md | 14 + tools/skillgen/fragments/core/aider.md | 1 + tools/skillgen/fragments/core/core.md | 3 +- tools/skillgen/fragments/core/devin.md | 1 + .../fragments/references/shared/exports.md | 14 + 71 files changed, 1241 insertions(+), 157 deletions(-) create mode 100644 docker-compose.multi.yml diff --git a/.gitignore b/.gitignore index 0a6775b2a8..5ef097f618 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ build/ *.egg .graphify/ graphify-out/ +.worktrees/ .graphify_*.json .graphify_python .claude/ diff --git a/Dockerfile b/Dockerfile index a313833c5c..f3521e1f22 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,15 @@ -# graphify MCP server as a shared HTTP service (issue #1143). +# graphify MCP server — single-graph and multi-graph targets. # -# Build: docker build -t graphify . -# Run: docker run -p 8080:8080 -v "$(pwd)/graphify-out:/data" graphify \ -# /data/graph.json --transport http --host 0.0.0.0 --api-key "$SECRET" +# Single-graph (existing, default): +# docker build -t graphify . +# docker run -p 8080:8080 -v "$(pwd)/graphify-out:/data" graphify \ +# /data/graph.json --transport http --host 0.0.0.0 --api-key "$SECRET" # -# Builds from source so the image includes the Streamable HTTP transport even -# before it lands on PyPI. The graph.json is mounted at runtime (-v), never -# baked into the image. -FROM python:3.12-slim +# Multi-graph: +# docker build --target multi -t graphify-multi . +# docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +FROM python:3.12-slim AS base WORKDIR /app COPY . /app @@ -19,7 +20,17 @@ RUN pip install --no-cache-dir ".[mcp]" RUN useradd --create-home --uid 10001 graphify USER graphify +# --- Single-graph target (default, backward-compatible) --- +FROM base AS single EXPOSE 8080 - ENTRYPOINT ["python", "-m", "graphify.serve"] CMD ["/data/graph.json", "--transport", "http", "--host", "0.0.0.0", "--port", "8080"] + +# --- Multi-graph target --- +FROM base AS multi +EXPOSE 8080 +VOLUME /graphs +ENV GRAPHS_DIR=/graphs +ENV SCAN_INTERVAL=30 +ENV PORT=8080 +ENTRYPOINT ["graphify-mcp", "--transport", "http", "--host", "0.0.0.0"] diff --git a/README.md b/README.md index 0c14d207c9..a4890192e4 100644 --- a/README.md +++ b/README.md @@ -494,6 +494,34 @@ docker run -p 8080:8080 -v "$(pwd)/graphify-out:/data" graphify \ > python3 -m venv .venv && .venv/bin/pip install "graphifyy[mcp]" > ``` +### Multi-graph MCP server + +Serve multiple knowledge graphs from a single endpoint — useful for multi-repo setups, monorepos with per-service graphs, or comparing codebases. + +```bash +# structure: one folder per graph +my-graphs/ + frontend/graph.json + backend/graph.json + shared-lib/graph.json + +# run with Docker +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi + +# or with docker-compose +docker compose -f docker-compose.multi.yml up --build +``` + +| Env var | Default | Purpose | +|---|---|---| +| `GRAPHS_DIR` | `/graphs` | Mount point to scan for `/graph.json` | +| `SCAN_INTERVAL` | `30` | Seconds between auto-discovery rescans | +| `PORT` | `8080` | HTTP listen port | +| `GRAPHIFY_API_KEY` | — | Require `Authorization: Bearer ` | + +Tools: same as single-graph (`query_graph`, `get_node`, `get_neighbors`, etc.) plus `list_graphs` and `use_graph`. Each tool accepts an optional `graph` parameter to target a specific graph, or use `use_graph` to set a session default. + --- ## Environment variables diff --git a/docker-compose.multi.yml b/docker-compose.multi.yml new file mode 100644 index 0000000000..230c12e144 --- /dev/null +++ b/docker-compose.multi.yml @@ -0,0 +1,18 @@ +# docker-compose.multi.yml +# Quick start for multi-graph MCP server. +# +# Place graphs as: ./my-graphs//graph.json +# Start: docker compose -f docker-compose.multi.yml up --build +services: + graphify-mcp: + build: + context: . + target: multi + ports: + - "8080:8080" + volumes: + - ./my-graphs:/graphs:ro + environment: + - SCAN_INTERVAL=30 + - PORT=8080 + # - GRAPHIFY_API_KEY=your-secret-key diff --git a/graphify/serve.py b/graphify/serve.py index 58c0925b4e..8949dd1949 100644 --- a/graphify/serve.py +++ b/graphify/serve.py @@ -5,8 +5,10 @@ import os import re import sys +import threading from array import array from collections import OrderedDict +from dataclasses import dataclass from pathlib import Path import threading from typing import NamedTuple @@ -15,6 +17,7 @@ from graphify.security import sanitize_label, check_graph_file_size_cap from graphify.build import edge_data, edge_datas from graphify.paths import default_graph_json as _default_graph_json +from graphify import paths as _paths try: import jieba as _jieba # type: ignore[import-untyped] @@ -22,6 +25,131 @@ _jieba = None +@dataclass +class GraphContext: + name: str + path: Path + graph: nx.Graph + communities: dict[int, list[str]] + mtime: float + + +class GraphRegistry: + def __init__(self) -> None: + self._graphs: dict[str, GraphContext] = {} + self._graphs_dir: Path | None = None + self._lock = threading.Lock() + + @classmethod + def from_path(cls, graph_path: Path) -> "GraphRegistry": + reg = cls() + graph_path = Path(graph_path).resolve() + G = _load_graph(str(graph_path)) + _get_trigram_index(G) + communities = _communities_from_graph(G) + name = graph_path.parent.name or "default" + mtime = graph_path.stat().st_mtime + reg._graphs[name] = GraphContext( + name=name, path=graph_path, graph=G, + communities=communities, mtime=mtime, + ) + return reg + + @classmethod + def from_directory(cls, graphs_dir: Path) -> "GraphRegistry": + reg = cls() + reg._graphs_dir = Path(graphs_dir) + reg._do_scan() + return reg + + def rescan(self) -> None: + if self._graphs_dir is not None: + self._do_scan() + else: + self._reload_single() + + def _reload_single(self) -> None: + with self._lock: + for name, ctx in list(self._graphs.items()): + try: + s = ctx.path.stat() + if s.st_mtime != ctx.mtime: + G = _load_graph(str(ctx.path)) + _get_trigram_index(G) + communities = _communities_from_graph(G) + self._graphs[name] = GraphContext( + name=name, path=ctx.path, graph=G, + communities=communities, mtime=s.st_mtime, + ) + except (OSError, SystemExit, Exception): + del self._graphs[name] + + def _do_scan(self) -> None: + import logging + if self._graphs_dir is None: + return + logger = logging.getLogger(__name__) + found: dict[str, GraphContext] = {} + for entry in sorted(self._graphs_dir.iterdir()): + if not entry.is_dir(): + continue + graph_file = entry / "graph.json" + if not graph_file.exists(): + continue + name = entry.name + try: + mtime = graph_file.stat().st_mtime + except OSError: + continue + existing = self._graphs.get(name) + if existing is not None and existing.mtime == mtime: + found[name] = existing + continue + try: + G = _load_graph(str(graph_file)) + except (SystemExit, Exception) as exc: + logger.warning("skipping %s: %s", graph_file, exc) + continue + _get_trigram_index(G) + communities = _communities_from_graph(G) + found[name] = GraphContext( + name=name, path=graph_file, graph=G, + communities=communities, mtime=mtime, + ) + logger.info("loaded graph %r (%d nodes)", name, G.number_of_nodes()) + with self._lock: + self._graphs = found + + def get(self, name: str) -> GraphContext | None: + return self._graphs.get(name) + + def names(self) -> list[str]: + return sorted(self._graphs.keys()) + + +def _resolve_graph( + registry: GraphRegistry, + *, + graph: str | None = None, + current: str | None = None, +) -> GraphContext: + name = graph or current + if name is not None: + ctx = registry.get(name) + if ctx is None: + raise ValueError(f"graph {name!r} not found. Available: {registry.names()}") + return ctx + names = registry.names() + if not names: + raise ValueError("no graphs loaded") + if len(names) == 1: + return registry.get(names[0]) + raise ValueError( + f"multiple graphs available ({', '.join(names)}), " + "specify with graph param or use_graph()" + ) + + def _load_graph(graph_path: str) -> nx.Graph: try: resolved = Path(graph_path).resolve() @@ -1505,13 +1633,15 @@ def _community_header(cid: int, community_name) -> str: return base -def _build_server(graph_path: str): +def _build_server(registry: GraphRegistry, *, session_state: dict | None = None): """Build the configured low-level MCP Server (shared by every transport). All graph query tools and resources are registered here over a single ``mcp.server.Server`` instance; the caller picks the transport (stdio or - Streamable HTTP) and runs it. Hot-reload of graph.json works the same way - regardless of transport, since reloads happen inside the tool handlers. + Streamable HTTP) and runs it. Graph resolution goes through the registry, + supporting both single-graph and multi-graph deployments. + + Returns ``(server, handlers)`` — the handlers dict is exposed for testing. """ try: from mcp.server import Server @@ -1525,52 +1655,34 @@ def _build_server(graph_path: str): # AnyUrl (pydantic is an mcp dependency, so this import cannot miss). from pydantic import AnyUrl - from graphify import paths as _paths - - # Graph contexts comprise one pinned configured default plus a bounded LRU - # of project_path graphs. This preserves the configured graph's warm index - # while preventing a shared server from retaining every project it serves. - _default_graph_path = str(Path(graph_path).resolve()) + if session_state is None: + session_state = {} + is_multi = len(registry.names()) > 1 _ctx_cache = _GraphContextCache(_max_server_contexts()) + default_paths = { + str(ctx.path.resolve()) + for name in registry.names() + if (ctx := registry.get(name)) is not None + } - def _load_ctx(path: str): - """Return the current default or project graph context as a tool error. - - Unlike ``_load_graph``, this never lets a missing or corrupt client - graph terminate the MCP process; it raises so other projects remain - available on the same server. - """ - resolved_path = str(Path(path).resolve()) - return _ctx_cache.load(resolved_path, pinned=resolved_path == _default_graph_path) - - def _resolve_graph_path(project_path) -> str: - """Map an optional project_path to a concrete graph.json path. ``None`` - keeps the server's default graph (backward-compatible); a project_path - resolves to ``//graph.json``, honouring the - GRAPHIFY_OUT override so worktree/shared-output setups keep working.""" - if not project_path: - return _default_graph_path - return str(Path(project_path) / _paths.GRAPHIFY_OUT / "graph.json") - - # Active per-request context, rebound by _select_graph() and read by the tool - # handlers below. No lock needed on the hot path: _select_graph and the - # handler run in one synchronous stretch of each call_tool coroutine (no - # await between them), so a concurrent call never observes a half-applied - # swap. - active_graph_path = _default_graph_path - try: - G, communities = _load_ctx(_default_graph_path) - except (FileNotFoundError, RuntimeError): - # No default graph at startup → run as a pure multi-project server. Tools - # then require project_path; a call without one gets a clear error rather - # than the process refusing to start (which is what _load_graph would do). - G, communities = None, {} - - def _select_graph(project_path) -> None: - nonlocal G, communities, active_graph_path - path = _resolve_graph_path(project_path) - G, communities = _load_ctx(path) - active_graph_path = str(Path(path).resolve()) + def _get_ctx(arguments: dict) -> GraphContext: + graph_param = arguments.pop("graph", None) + project_path = arguments.pop("project_path", None) + if project_path: + path = str((Path(project_path) / _paths.GRAPHIFY_OUT / "graph.json").resolve()) + graph, communities = _ctx_cache.load(path, pinned=path in default_paths) + return GraphContext( + name=Path(project_path).name or "project", + path=Path(path), + graph=graph, + communities=communities, + mtime=Path(path).stat().st_mtime, + ) + return _resolve_graph( + registry, + graph=graph_param, + current=session_state.get("current_graph"), + ) # NOTE: no decorators here — the handlers below are plain coroutines, # bound to the Server at the END of this function in a version-aware way: @@ -1660,7 +1772,26 @@ async def list_tools() -> list[types.Tool]: "required": ["source", "target"], }, ), - types.Tool( + ] + if is_multi: + _tools.append(types.Tool( + name="list_graphs", + description="List all available knowledge graphs with node/edge/community counts.", + inputSchema={"type": "object", "properties": {}}, + )) + _tools.append(types.Tool( + name="use_graph", + description="Set the default graph for this session.", + inputSchema={ + "type": "object", + "properties": { + "graph": {"type": "string", "description": "Name of the graph to use"}, + }, + "required": ["graph"], + }, + )) + else: + _tools.append(types.Tool( name="list_prs", description=( "List open GitHub PRs with CI status, review state, and graph impact " @@ -1674,8 +1805,8 @@ async def list_tools() -> list[types.Tool]: "repo": {"type": "string", "description": "GitHub repo (owner/repo). Defaults to current repo."}, }, }, - ), - types.Tool( + )) + _tools.append(types.Tool( name="get_pr_impact", description=( "Get detailed graph impact for a specific PR: which files it changes, " @@ -1690,8 +1821,8 @@ async def list_tools() -> list[types.Tool]: }, "required": ["pr_number"], }, - ), - types.Tool( + )) + _tools.append(types.Tool( name="triage_prs", description=( "Return all actionable open PRs (correct base, not stale) with full graph impact data " @@ -1705,31 +1836,36 @@ async def list_tools() -> list[types.Tool]: "repo": {"type": "string", "description": "GitHub repo (owner/repo). Defaults to current repo."}, }, }, - ), - ] - # Multi-project support: every tool accepts an optional project_path. - # Injected here (rather than repeated in 11 literal schemas) so the set - # stays in lockstep as tools are added. Omitting it keeps the historical - # single-graph behaviour, so this is purely additive for existing callers. + )) + # Named graphs and project paths remain optional to preserve existing + # clients while allowing a registry-backed multi-graph server. for _t in _tools: # The constructor accepts the camelCase alias in both majors, but # attribute access is inputSchema on mcp 1.x and input_schema on 2.x. _schema = getattr(_t, "inputSchema", None) if _schema is None: _schema = _t.input_schema - _schema.setdefault("properties", {})["project_path"] = { - "type": "string", - "description": ( - "Absolute path to a project directory containing " - "graphify-out/graph.json. Optional — defaults to the graph " - "this server was started with." - ), - } + if _t.name not in ("list_graphs", "use_graph"): + _schema.setdefault("properties", {})["graph"] = { + "type": "string", + "description": "Target graph name. Overrides session default.", + } + if _t.name not in ("list_graphs", "use_graph"): + _schema.setdefault("properties", {})["project_path"] = { + "type": "string", + "description": ( + "Absolute path to a project directory containing " + "graphify-out/graph.json. Optional — defaults to the graph " + "this server was started with." + ), + } return _tools def _tool_query_graph(arguments: dict) -> str: import time as _time from graphify import querylog + ctx = _get_ctx(arguments) + G = ctx.graph question = arguments["question"] mode = arguments.get("mode", "bfs") depth = min(int(arguments.get("depth", 3)), 6) @@ -1743,12 +1879,12 @@ def _tool_query_graph(arguments: dict) -> str: depth=depth, token_budget=budget, context_filters=context_filter, - graph_path=str(active_graph_path), + graph_path=str(ctx.path), ) querylog.log_query( kind="mcp_query", question=question, - corpus=str(active_graph_path), + corpus=str(ctx.path), result=result, mode=mode, depth=depth, @@ -1758,6 +1894,8 @@ def _tool_query_graph(arguments: dict) -> str: return result def _tool_get_node(arguments: dict) -> str: + ctx = _get_ctx(arguments) + G = ctx.graph label = arguments["label"].lower() matches = [(nid, d) for nid, d in G.nodes(data=True) if label in (d.get("label") or "").lower() or label == nid.lower()] @@ -1781,6 +1919,8 @@ def _tool_get_node(arguments: dict) -> str: ]) def _tool_get_neighbors(arguments: dict) -> str: + ctx = _get_ctx(arguments) + G = ctx.graph label = arguments["label"].lower() rel_filter = arguments.get("relation_filter", "").lower() matches = _find_node(G, label) @@ -1830,6 +1970,9 @@ def _edge_at(d: dict) -> str: ) def _tool_get_community(arguments: dict) -> str: + ctx = _get_ctx(arguments) + G = ctx.graph + communities = ctx.communities cid = int(arguments["community_id"]) nodes = communities.get(cid, []) if not nodes: @@ -1850,12 +1993,17 @@ def _tool_get_community(arguments: dict) -> str: def _tool_god_nodes(arguments: dict) -> str: from graphify.analyze import god_nodes as _god_nodes + ctx = _get_ctx(arguments) + G = ctx.graph nodes = _god_nodes(G, top_n=int(arguments.get("top_n", 10))) lines = ["God nodes (most connected):"] lines += [f" {i}. {n['label']} - {n['degree']} edges" for i, n in enumerate(nodes, 1)] return "\n".join(lines) - def _tool_graph_stats(_: dict) -> str: + def _tool_graph_stats(arguments: dict) -> str: + ctx = _get_ctx(arguments) + G = ctx.graph + communities = ctx.communities confs = [d.get("confidence", "EXTRACTED") for _, _, d in G.edges(data=True)] total = len(confs) or 1 return ( @@ -1868,9 +2016,12 @@ def _tool_graph_stats(_: dict) -> str: ) def _tool_shortest_path(arguments: dict) -> str: + ctx = _get_ctx(arguments) + G = ctx.graph return _shortest_path_text(G, arguments) def _tool_list_prs(arguments: dict) -> str: + arguments.pop("graph", None) # list_prs doesn't route to a graph from graphify.prs import fetch_prs, fetch_worktrees, format_prs_text, _detect_default_branch repo = arguments.get("repo") or None base = arguments.get("base") or _detect_default_branch(repo) @@ -1884,6 +2035,8 @@ def _tool_list_prs(arguments: dict) -> str: return format_prs_text(prs, base) def _tool_get_pr_impact(arguments: dict) -> str: + ctx = _get_ctx(arguments) + G = ctx.graph from graphify.prs import fetch_pr_files, compute_pr_impact, _gh, _parse_ci number = int(arguments["pr_number"]) repo = arguments.get("repo") or None @@ -1914,6 +2067,8 @@ def _tool_get_pr_impact(arguments: dict) -> str: return "\n".join(lines) def _tool_triage_prs(arguments: dict) -> str: + ctx = _get_ctx(arguments) + G = ctx.graph from concurrent.futures import ThreadPoolExecutor, as_completed from graphify.prs import fetch_prs, fetch_worktrees, fetch_pr_files, compute_pr_impact, _STATUS_ORDER, _detect_default_branch repo = arguments.get("repo") or None @@ -1955,7 +2110,31 @@ def _tool_triage_prs(arguments: dict) -> str: ) return "\n\n".join(lines) - _handlers = { + def _tool_list_graphs(arguments: dict) -> str: + lines = [] + for name in registry.names(): + ctx = registry.get(name) + if ctx is None: + continue + G = ctx.graph + lines.append( + f"{name}: {G.number_of_nodes()} nodes, " + f"{G.number_of_edges()} edges, " + f"{len(ctx.communities)} communities" + ) + if not lines: + return "No graphs loaded." + return "\n".join(lines) + + def _tool_use_graph(arguments: dict) -> str: + name = arguments["graph"] + ctx = registry.get(name) + if ctx is None: + return f"Graph {name!r} not found. Available: {registry.names()}" + session_state["current_graph"] = name + return f"Switched to graph {name!r} ({ctx.graph.number_of_nodes()} nodes)" + + _handlers: dict = { "query_graph": _tool_query_graph, "get_node": _tool_get_node, "get_neighbors": _tool_get_neighbors, @@ -1963,19 +2142,24 @@ def _tool_triage_prs(arguments: dict) -> str: "god_nodes": _tool_god_nodes, "graph_stats": _tool_graph_stats, "shortest_path": _tool_shortest_path, - "list_prs": _tool_list_prs, - "get_pr_impact": _tool_get_pr_impact, - "triage_prs": _tool_triage_prs, } + if is_multi: + _handlers["list_graphs"] = _tool_list_graphs + _handlers["use_graph"] = _tool_use_graph + else: + _handlers["list_prs"] = _tool_list_prs + _handlers["get_pr_impact"] = _tool_get_pr_impact + _handlers["triage_prs"] = _tool_triage_prs def _load_community_labels() -> dict[int, str]: - labels_path = Path(active_graph_path).parent / ".graphify_labels.json" + ctx = _resolve_graph(registry, current=session_state.get("current_graph")) + labels_path = ctx.path.parent / ".graphify_labels.json" if labels_path.exists(): try: return {int(k): v for k, v in json.loads(labels_path.read_text(encoding="utf-8")).items()} except Exception: pass - return {cid: f"Community {cid}" for cid in communities} + return {cid: f"Community {cid}" for cid in ctx.communities} async def list_resources() -> list[types.Resource]: # Plain-string URIs on purpose: mcp 1.x types the field as AnyUrl and @@ -1990,7 +2174,10 @@ async def list_resources() -> list[types.Resource]: ] async def read_resource(uri: AnyUrl) -> str: - _select_graph(None) # resources read the server's default graph + ctx = _resolve_graph(registry, current=session_state.get("current_graph")) + G = ctx.graph + communities = ctx.communities + active_graph_path = str(ctx.path) uri_str = str(uri) if uri_str == "graphify://report": report_path = Path(active_graph_path).parent / "GRAPH_REPORT.md" @@ -1998,9 +2185,22 @@ async def read_resource(uri: AnyUrl) -> str: return report_path.read_text(encoding="utf-8") return "GRAPH_REPORT.md not found. Run graphify extract first." if uri_str == "graphify://stats": - return _tool_graph_stats({}) + confs = [d.get("confidence", "EXTRACTED") for _, _, d in G.edges(data=True)] + total = len(confs) or 1 + return ( + f"Nodes: {G.number_of_nodes()}\n" + f"Edges: {G.number_of_edges()}\n" + f"Communities: {len(communities)}\n" + f"EXTRACTED: {round(confs.count('EXTRACTED')/total*100)}%\n" + f"INFERRED: {round(confs.count('INFERRED')/total*100)}%\n" + f"AMBIGUOUS: {round(confs.count('AMBIGUOUS')/total*100)}%\n" + ) if uri_str == "graphify://god-nodes": - return _tool_god_nodes({"top_n": 10}) + from graphify.analyze import god_nodes as _god_nodes + nodes = _god_nodes(G, top_n=10) + lines = ["God nodes (most connected):"] + lines += [f" {i}. {n['label']} - {n['degree']} edges" for i, n in enumerate(nodes, 1)] + return "\n".join(lines) if uri_str == "graphify://surprises": try: from graphify.analyze import surprising_connections @@ -2042,12 +2242,10 @@ async def read_resource(uri: AnyUrl) -> str: async def call_tool(name: str, arguments: dict) -> list[types.TextContent]: arguments = dict(arguments or {}) - project_path = arguments.pop("project_path", None) handler = _handlers.get(name) if not handler: return [types.TextContent(type="text", text=f"Unknown tool: {name}")] try: - _select_graph(project_path) # bind G/communities to the target graph return [types.TextContent(type="text", text=handler(arguments))] except Exception as exc: return [types.TextContent(type="text", text=f"Error executing {name}: {exc}")] @@ -2095,7 +2293,7 @@ async def _on_read_resource(ctx, params) -> types.ReadResourceResult: on_read_resource=_on_read_resource, ) - return server + return server, _handlers def serve(graph_path: str | None = None) -> None: @@ -2107,7 +2305,8 @@ def serve(graph_path: str | None = None) -> None: raise ImportError('mcp not installed. Run: pip install "graphifyy[mcp]"') from e import asyncio - server = _build_server(graph_path) + registry = GraphRegistry.from_path(Path(graph_path)) + server, _ = _build_server(registry) async def main() -> None: async with stdio_server() as streams: @@ -2175,8 +2374,9 @@ async def __call__(self, scope, receive, send) -> None: def _build_http_app( - graph_path: str, + graph_path: str | None = None, *, + registry: GraphRegistry | None = None, host: str = "127.0.0.1", port: int = 8080, api_key: str | None = None, @@ -2214,7 +2414,9 @@ def _build_http_app( # mistaken for "auth on" — normalize it to None so the gate is unambiguous. api_key = (api_key or "").strip() or None - server = _build_server(graph_path) + if registry is None: + registry = GraphRegistry.from_path(Path(graph_path)) + server, _ = _build_server(registry) # DNS-rebinding protection. When the operator binds a wildcard address they # are intentionally exposing the server, so accept any Host header; for a @@ -2259,6 +2461,7 @@ async def lifespan(_app): def serve_http( graph_path: str | None = None, *, + registry: GraphRegistry | None = None, host: str = "127.0.0.1", port: int = 8080, api_key: str | None = None, @@ -2277,8 +2480,12 @@ def serve_http( check (``Authorization: Bearer `` or ``X-API-Key: ``). OAuth is a deliberate follow-up. Binding ``0.0.0.0`` exposes the server beyond localhost — set an api_key when you do. + + ``registry`` can be supplied directly for multi-graph mode (``--graphs-dir``); + when provided ``graph_path`` is ignored. """ - graph_path = graph_path or _default_graph_json() + if registry is None: + graph_path = graph_path or _default_graph_json() try: import uvicorn except ImportError as e: @@ -2291,6 +2498,7 @@ def serve_http( app = _build_http_app( graph_path, + registry=registry, host=host, port=port, api_key=api_key, @@ -2365,12 +2573,50 @@ def _main(argv: list[str] | None = None) -> None: default=3600.0, help="Reap stateful sessions idle this many seconds (default: 3600; 0 disables)", ) + parser.add_argument( + "--graphs-dir", + default=os.environ.get("GRAPHS_DIR"), + metavar="PATH", + help="Directory of graph subdirs for multi-graph mode (env: GRAPHS_DIR). Forces HTTP transport.", + ) args = parser.parse_args(argv) - graph_path = args.graph_flag or args.graph_path or _default_graph_json() - if args.transport == "http": + if args.graphs_dir: + graphs_dir = Path(args.graphs_dir) + if not graphs_dir.is_dir(): + print(f"error: --graphs-dir {graphs_dir} does not exist", file=sys.stderr) + sys.exit(1) + if args.transport == "stdio": + print("error: --graphs-dir requires HTTP transport (multi-graph over stdio is not supported)", file=sys.stderr) + sys.exit(1) + registry = GraphRegistry.from_directory(graphs_dir) + if not registry.names(): + print(f"error: no graphs found in {graphs_dir}/ (expected /graph.json)", file=sys.stderr) + sys.exit(1) + scan_interval = int(os.environ.get("SCAN_INTERVAL", "30")) + print( + f"graphify multi-graph MCP: {len(registry.names())} graphs from {graphs_dir}", + file=sys.stderr, + ) + for name in registry.names(): + ctx = registry.get(name) + print(f" {name}: {ctx.graph.number_of_nodes()} nodes", file=sys.stderr) + + def _rescan_loop(): + import time + while True: + time.sleep(scan_interval) + try: + registry.rescan() + except Exception as exc: + import logging + logging.getLogger(__name__).warning("rescan failed: %s", exc) + + rescan_thread = threading.Thread(target=_rescan_loop, daemon=True) + rescan_thread.start() + serve_http( - graph_path, + registry=registry, host=args.host, port=args.port, api_key=args.api_key, @@ -2380,7 +2626,20 @@ def _main(argv: list[str] | None = None) -> None: session_timeout=args.session_timeout, ) else: - serve(graph_path) + graph_path = args.graph_flag or args.graph_path or _default_graph_json() + if args.transport == "http": + serve_http( + graph_path, + host=args.host, + port=args.port, + api_key=args.api_key, + path=args.path, + json_response=args.json_response, + stateless=args.stateless, + session_timeout=args.session_timeout, + ) + else: + serve(graph_path) if __name__ == "__main__": diff --git a/graphify/skill-agents.md b/graphify/skill-agents.md index 190827d9ac..2ff7840c3b 100644 --- a/graphify/skill-agents.md +++ b/graphify/skill-agents.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -547,7 +548,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-aider.md b/graphify/skill-aider.md index 4996beb787..398012b35f 100644 --- a/graphify/skill-aider.md +++ b/graphify/skill-aider.md @@ -22,6 +22,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --neo4j # generate graphify-out/cypher.txt for Neo4j /graphify --neo4j-push bolt://localhost:7687 # push directly to Neo4j /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify add # fetch URL, save to ./raw, update graph /graphify add --author "Name" # tag who wrote it diff --git a/graphify/skill-amp.md b/graphify/skill-amp.md index 190827d9ac..2ff7840c3b 100644 --- a/graphify/skill-amp.md +++ b/graphify/skill-amp.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -547,7 +548,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-claw.md b/graphify/skill-claw.md index abd2811d23..3e1d9f2fda 100644 --- a/graphify/skill-claw.md +++ b/graphify/skill-claw.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -550,7 +551,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-codex.md b/graphify/skill-codex.md index af3f723c78..fdb69319dc 100644 --- a/graphify/skill-codex.md +++ b/graphify/skill-codex.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -547,7 +548,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-copilot.md b/graphify/skill-copilot.md index abd2811d23..3e1d9f2fda 100644 --- a/graphify/skill-copilot.md +++ b/graphify/skill-copilot.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -550,7 +551,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-devin.md b/graphify/skill-devin.md index f9be846cbf..214ba319a4 100644 --- a/graphify/skill-devin.md +++ b/graphify/skill-devin.md @@ -32,6 +32,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --neo4j # generate graphify-out/cypher.txt for Neo4j /graphify --neo4j-push bolt://localhost:7687 # push directly to Neo4j /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify add # fetch URL, save to ./raw, update graph diff --git a/graphify/skill-droid.md b/graphify/skill-droid.md index fd148d485d..f75bdf79b5 100644 --- a/graphify/skill-droid.md +++ b/graphify/skill-droid.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -547,7 +548,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-kilo.md b/graphify/skill-kilo.md index 3e70b050a4..eb787b76fa 100644 --- a/graphify/skill-kilo.md +++ b/graphify/skill-kilo.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -550,7 +551,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-kiro.md b/graphify/skill-kiro.md index abd2811d23..3e1d9f2fda 100644 --- a/graphify/skill-kiro.md +++ b/graphify/skill-kiro.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -550,7 +551,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-opencode.md b/graphify/skill-opencode.md index 91ced60675..5e2ae50f7d 100644 --- a/graphify/skill-opencode.md +++ b/graphify/skill-opencode.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -542,7 +543,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-pi.md b/graphify/skill-pi.md index abd2811d23..3e1d9f2fda 100644 --- a/graphify/skill-pi.md +++ b/graphify/skill-pi.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -550,7 +551,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-trae.md b/graphify/skill-trae.md index 050667bc20..79b80cbaff 100644 --- a/graphify/skill-trae.md +++ b/graphify/skill-trae.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -548,7 +549,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-vscode.md b/graphify/skill-vscode.md index 20c7c0835c..23f05b032f 100644 --- a/graphify/skill-vscode.md +++ b/graphify/skill-vscode.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -546,7 +547,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-windows.md b/graphify/skill-windows.md index d631821ec3..56b9df37d1 100644 --- a/graphify/skill-windows.md +++ b/graphify/skill-windows.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -572,7 +573,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill.md b/graphify/skill.md index abd2811d23..3e1d9f2fda 100644 --- a/graphify/skill.md +++ b/graphify/skill.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -550,7 +551,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skills/agents/references/exports.md b/graphify/skills/agents/references/exports.md index 242ff868e0..89430e90ef 100644 --- a/graphify/skills/agents/references/exports.md +++ b/graphify/skills/agents/references/exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/amp/references/exports.md b/graphify/skills/amp/references/exports.md index 242ff868e0..89430e90ef 100644 --- a/graphify/skills/amp/references/exports.md +++ b/graphify/skills/amp/references/exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/claude/references/exports.md b/graphify/skills/claude/references/exports.md index 242ff868e0..89430e90ef 100644 --- a/graphify/skills/claude/references/exports.md +++ b/graphify/skills/claude/references/exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/claw/references/exports.md b/graphify/skills/claw/references/exports.md index 242ff868e0..89430e90ef 100644 --- a/graphify/skills/claw/references/exports.md +++ b/graphify/skills/claw/references/exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/codex/references/exports.md b/graphify/skills/codex/references/exports.md index 242ff868e0..89430e90ef 100644 --- a/graphify/skills/codex/references/exports.md +++ b/graphify/skills/codex/references/exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/copilot/references/exports.md b/graphify/skills/copilot/references/exports.md index 242ff868e0..89430e90ef 100644 --- a/graphify/skills/copilot/references/exports.md +++ b/graphify/skills/copilot/references/exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/droid/references/exports.md b/graphify/skills/droid/references/exports.md index 242ff868e0..89430e90ef 100644 --- a/graphify/skills/droid/references/exports.md +++ b/graphify/skills/droid/references/exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/kilo/references/exports.md b/graphify/skills/kilo/references/exports.md index 242ff868e0..89430e90ef 100644 --- a/graphify/skills/kilo/references/exports.md +++ b/graphify/skills/kilo/references/exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/kiro/references/exports.md b/graphify/skills/kiro/references/exports.md index 242ff868e0..89430e90ef 100644 --- a/graphify/skills/kiro/references/exports.md +++ b/graphify/skills/kiro/references/exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/opencode/references/exports.md b/graphify/skills/opencode/references/exports.md index 242ff868e0..89430e90ef 100644 --- a/graphify/skills/opencode/references/exports.md +++ b/graphify/skills/opencode/references/exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/pi/references/exports.md b/graphify/skills/pi/references/exports.md index 242ff868e0..89430e90ef 100644 --- a/graphify/skills/pi/references/exports.md +++ b/graphify/skills/pi/references/exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/trae/references/exports.md b/graphify/skills/trae/references/exports.md index 242ff868e0..89430e90ef 100644 --- a/graphify/skills/trae/references/exports.md +++ b/graphify/skills/trae/references/exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/vscode/references/exports.md b/graphify/skills/vscode/references/exports.md index 242ff868e0..89430e90ef 100644 --- a/graphify/skills/vscode/references/exports.md +++ b/graphify/skills/vscode/references/exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/windows/references/exports.md b/graphify/skills/windows/references/exports.md index 242ff868e0..89430e90ef 100644 --- a/graphify/skills/windows/references/exports.md +++ b/graphify/skills/windows/references/exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tests/test_serve.py b/tests/test_serve.py index 85f77a59a2..6c4eb34283 100644 --- a/tests/test_serve.py +++ b/tests/test_serve.py @@ -6,6 +6,8 @@ import networkx as nx from networkx.readwrite import json_graph +from pathlib import Path + from graphify.serve import ( _strip_diacritics, _communities_from_graph, @@ -33,6 +35,9 @@ _community_header, _search_tokens, _shortest_path_text, + GraphContext, + GraphRegistry, + _resolve_graph, ) @@ -1711,3 +1716,320 @@ def test_underscore_query_does_not_let_a_single_token_outrank_the_real_match(): scored = _score_nodes(G, _query_terms("user_service_client")) assert scored, "the multi-token query must match the full-label node" assert scored[0][1] == "real", f"a single-token node out-ranked the real match: {scored}" + +# --- GraphRegistry tests --- + + +def _write_registry_graph(base: Path, name: str, nodes=None, edges=None): + """Write a minimal graph.json under base/name/graph.json.""" + d = base / name + d.mkdir(parents=True, exist_ok=True) + data = { + "nodes": [ + {"id": f"{name}_n1", "label": "main", "community": 0}, + {"id": f"{name}_n2", "label": "helper", "community": 0}, + ] if nodes is None else nodes, + "links": [ + {"source": f"{name}_n1", "target": f"{name}_n2", "relation": "calls", "confidence": "EXTRACTED"}, + ] if edges is None else edges, + } + (d / "graph.json").write_text(json.dumps(data), encoding="utf-8") + return d / "graph.json" + + +class TestGraphRegistry: + def test_from_path_single_graph(self, tmp_path): + gp = _write_registry_graph(tmp_path, "proj") + reg = GraphRegistry.from_path(gp) + assert len(reg.names()) == 1 + ctx = reg.get(reg.names()[0]) + assert ctx is not None + assert ctx.graph.number_of_nodes() == 2 + + def test_from_directory_discovers_graphs(self, tmp_path): + _write_registry_graph(tmp_path, "frontend") + _write_registry_graph(tmp_path, "backend") + reg = GraphRegistry.from_directory(tmp_path) + assert sorted(reg.names()) == ["backend", "frontend"] + + def test_from_directory_skips_corrupt(self, tmp_path): + _write_registry_graph(tmp_path, "good") + bad = tmp_path / "bad" + bad.mkdir() + (bad / "graph.json").write_text("{invalid json", encoding="utf-8") + reg = GraphRegistry.from_directory(tmp_path) + assert reg.names() == ["good"] + + def test_from_directory_skips_no_graph_json(self, tmp_path): + _write_registry_graph(tmp_path, "valid") + (tmp_path / "empty_dir").mkdir() + reg = GraphRegistry.from_directory(tmp_path) + assert reg.names() == ["valid"] + + def test_get_unknown_returns_none(self, tmp_path): + gp = _write_registry_graph(tmp_path, "proj") + reg = GraphRegistry.from_path(gp) + assert reg.get("nonexistent") is None + + def test_rescan_detects_new_graph(self, tmp_path): + _write_registry_graph(tmp_path, "first") + reg = GraphRegistry.from_directory(tmp_path) + assert reg.names() == ["first"] + _write_registry_graph(tmp_path, "second") + reg.rescan() + assert sorted(reg.names()) == ["first", "second"] + + def test_rescan_evicts_removed_graph(self, tmp_path): + _write_registry_graph(tmp_path, "temp") + reg = GraphRegistry.from_directory(tmp_path) + import shutil + shutil.rmtree(tmp_path / "temp") + reg.rescan() + assert reg.names() == [] + + def test_rescan_reloads_changed_graph(self, tmp_path): + _write_registry_graph(tmp_path, "proj", nodes=[ + {"id": "a", "label": "a", "community": 0}, + ], edges=[]) + reg = GraphRegistry.from_directory(tmp_path) + assert reg.get("proj").graph.number_of_nodes() == 1 + import time; time.sleep(0.05) + _write_registry_graph(tmp_path, "proj", nodes=[ + {"id": "a", "label": "a", "community": 0}, + {"id": "b", "label": "b", "community": 0}, + ], edges=[]) + reg.rescan() + assert reg.get("proj").graph.number_of_nodes() == 2 + + def test_from_path_hot_reload(self, tmp_path): + gp = _write_registry_graph(tmp_path, "proj", nodes=[ + {"id": "a", "label": "a", "community": 0}, + ], edges=[]) + reg = GraphRegistry.from_path(gp) + assert reg.get(reg.names()[0]).graph.number_of_nodes() == 1 + import time; time.sleep(0.05) + _write_registry_graph(tmp_path, "proj", nodes=[ + {"id": "a", "label": "a", "community": 0}, + {"id": "b", "label": "b", "community": 0}, + ], edges=[]) + reg.rescan() + assert reg.get(reg.names()[0]).graph.number_of_nodes() == 2 + + def test_from_path_evicts_deleted(self, tmp_path): + gp = _write_registry_graph(tmp_path, "proj") + reg = GraphRegistry.from_path(gp) + assert len(reg.names()) == 1 + import os + os.remove(gp) + reg.rescan() + assert reg.names() == [] + + +from graphify.serve import _build_server + + +class TestUnifiedBuildServer: + def test_single_graph_has_no_list_graphs(self, tmp_path): + gp = _write_registry_graph(tmp_path, "proj") + reg = GraphRegistry.from_path(gp) + server, handlers = _build_server(reg) + assert "list_graphs" not in handlers + assert "use_graph" not in handlers + + def test_multi_graph_has_list_graphs(self, tmp_path): + _write_registry_graph(tmp_path, "alpha") + _write_registry_graph(tmp_path, "beta") + reg = GraphRegistry.from_directory(tmp_path) + server, handlers = _build_server(reg) + assert "list_graphs" in handlers + assert "use_graph" in handlers + + def test_single_graph_has_pr_tools(self, tmp_path): + gp = _write_registry_graph(tmp_path, "proj") + reg = GraphRegistry.from_path(gp) + server, handlers = _build_server(reg) + assert "list_prs" in handlers + + def test_multi_graph_no_pr_tools(self, tmp_path): + _write_registry_graph(tmp_path, "alpha") + _write_registry_graph(tmp_path, "beta") + reg = GraphRegistry.from_directory(tmp_path) + server, handlers = _build_server(reg) + assert "list_prs" not in handlers + + def test_single_graph_query(self, tmp_path): + _write_registry_graph(tmp_path, "proj", nodes=[ + {"id": "n1", "label": "AuthService", "community": 0, "source_file": "auth.py"}, + {"id": "n2", "label": "Database", "community": 0, "source_file": "db.py"}, + ], edges=[ + {"source": "n1", "target": "n2", "relation": "calls", "confidence": "EXTRACTED"}, + ]) + reg = GraphRegistry.from_path(tmp_path / "proj" / "graph.json") + _, handlers = _build_server(reg) + result = handlers["query_graph"]({"question": "AuthService"}) + assert "AuthService" in result + + def test_multi_graph_use_graph_and_query(self, tmp_path): + _write_registry_graph(tmp_path, "alpha", nodes=[ + {"id": "a1", "label": "UserService", "community": 0}, + ], edges=[]) + _write_registry_graph(tmp_path, "beta", nodes=[ + {"id": "b1", "label": "PaymentGateway", "community": 0}, + ], edges=[]) + reg = GraphRegistry.from_directory(tmp_path) + session = {} + _, handlers = _build_server(reg, session_state=session) + + result = handlers["list_graphs"]({}) + assert "alpha" in result + assert "beta" in result + + handlers["use_graph"]({"graph": "alpha"}) + assert session["current_graph"] == "alpha" + + result = handlers["graph_stats"]({}) + assert "Nodes: 1" in result + + result = handlers["graph_stats"]({"graph": "beta"}) + assert "Nodes: 1" in result + + def test_all_tools_have_graph_param(self, tmp_path): + _write_registry_graph(tmp_path, "alpha") + _write_registry_graph(tmp_path, "beta") + reg = GraphRegistry.from_directory(tmp_path) + server, _ = _build_server(reg) + from mcp import types as _t + import asyncio + handler = server.request_handlers[_t.ListToolsRequest] + loop = asyncio.new_event_loop() + result = loop.run_until_complete(handler(_t.ListToolsRequest())) + loop.close() + tools = result.root.tools + for t in tools: + if t.name != "list_graphs": + props = t.inputSchema.get("properties", {}) + assert "graph" in props, f"tool {t.name} missing graph param" + + +class TestResolveGraph: + def test_explicit_param(self, tmp_path): + _write_registry_graph(tmp_path, "alpha") + _write_registry_graph(tmp_path, "beta") + reg = GraphRegistry.from_directory(tmp_path) + ctx = _resolve_graph(reg, graph="alpha", current=None) + assert ctx.name == "alpha" + + def test_session_default(self, tmp_path): + _write_registry_graph(tmp_path, "proj") + reg = GraphRegistry.from_directory(tmp_path) + ctx = _resolve_graph(reg, graph=None, current="proj") + assert ctx.name == "proj" + + def test_single_graph_implicit(self, tmp_path): + gp = _write_registry_graph(tmp_path, "only") + reg = GraphRegistry.from_path(gp) + ctx = _resolve_graph(reg, graph=None, current=None) + assert ctx is not None + + def test_ambiguous_raises(self, tmp_path): + _write_registry_graph(tmp_path, "a") + _write_registry_graph(tmp_path, "b") + reg = GraphRegistry.from_directory(tmp_path) + with pytest.raises(ValueError, match="multiple graphs"): + _resolve_graph(reg, graph=None, current=None) + + def test_unknown_name_raises(self, tmp_path): + _write_registry_graph(tmp_path, "x") + reg = GraphRegistry.from_directory(tmp_path) + with pytest.raises(ValueError, match="not found"): + _resolve_graph(reg, graph="nope", current=None) + + def test_empty_registry_raises(self, tmp_path): + reg = GraphRegistry.from_directory(tmp_path) + with pytest.raises(ValueError, match="no graphs loaded"): + _resolve_graph(reg, graph=None, current=None) + + +# --- CLI --graphs-dir tests --- + +from graphify.serve import _main + + +class TestMainCLI: + def test_graphs_dir_forces_http(self, tmp_path, capsys): + _write_registry_graph(tmp_path, "proj") + with pytest.raises(SystemExit): + _main(["--graphs-dir", str(tmp_path), "--transport", "stdio"]) + captured = capsys.readouterr() + assert "stdio" in captured.err.lower() or "http" in captured.err.lower() + + def test_graphs_dir_empty_exits(self, tmp_path): + with pytest.raises(SystemExit): + _main(["--graphs-dir", str(tmp_path)]) + + def test_graphs_dir_missing_exits(self, tmp_path): + with pytest.raises(SystemExit): + _main(["--graphs-dir", str(tmp_path / "nonexistent")]) + + +class TestUnifiedIntegration: + def test_multi_graph_full_flow(self, tmp_path): + _write_registry_graph(tmp_path, "alpha", nodes=[ + {"id": "a1", "label": "UserService", "community": 0, "source_file": "user.py", "source_location": "L1", "file_type": "python"}, + {"id": "a2", "label": "AuthService", "community": 0, "source_file": "auth.py", "source_location": "L1", "file_type": "python"}, + ], edges=[ + {"source": "a1", "target": "a2", "relation": "calls", "confidence": "EXTRACTED"}, + ]) + _write_registry_graph(tmp_path, "beta", nodes=[ + {"id": "b1", "label": "PaymentGateway", "community": 0, "source_file": "pay.py", "source_location": "L1", "file_type": "python"}, + ], edges=[]) + + reg = GraphRegistry.from_directory(tmp_path) + session = {} + _, handlers = _build_server(reg, session_state=session) + + listing = handlers["list_graphs"]({}) + assert "alpha" in listing + assert "beta" in listing + + handlers["use_graph"]({"graph": "alpha"}) + assert session["current_graph"] == "alpha" + + result = handlers["query_graph"]({"question": "UserService"}) + assert "UserService" in result + + result = handlers["graph_stats"]({"graph": "beta"}) + assert "Nodes: 1" in result + + assert "list_prs" not in handlers + + _write_registry_graph(tmp_path, "gamma", nodes=[ + {"id": "g1", "label": "Logger", "community": 0}, + ], edges=[]) + reg.rescan() + listing = handlers["list_graphs"]({}) + assert "gamma" in listing + + def test_single_graph_retro_compat(self, tmp_path): + _write_registry_graph(tmp_path, "proj", nodes=[ + {"id": "n1", "label": "Main", "community": 0, "source_file": "main.py"}, + {"id": "n2", "label": "Helper", "community": 0, "source_file": "helper.py"}, + ], edges=[ + {"source": "n1", "target": "n2", "relation": "calls", "confidence": "EXTRACTED"}, + ]) + reg = GraphRegistry.from_path(tmp_path / "proj" / "graph.json") + _, handlers = _build_server(reg) + + assert "list_graphs" not in handlers + assert "use_graph" not in handlers + assert "list_prs" in handlers + + result = handlers["query_graph"]({"question": "Main"}) + assert "Main" in result + + result = handlers["graph_stats"]({}) + assert "Nodes: 2" in result + + result = handlers["get_node"]({"label": "Helper"}) + assert "Helper" in result + assert "helper.py" in result diff --git a/tests/test_serve_http.py b/tests/test_serve_http.py index 7893a0f4e3..f450ca9a4d 100644 --- a/tests/test_serve_http.py +++ b/tests/test_serve_http.py @@ -200,31 +200,44 @@ def _call_tool(client, headers, name, arguments, rid) -> str: return resp.json()["result"]["content"][0]["text"] -def test_project_path_is_optional_on_every_tool(tmp_path): - """Multi-project support is additive: every tool gains an optional - project_path, and none of them makes it required.""" +def test_graph_param_is_optional_on_every_tool(tmp_path): + """Every tool gains an optional graph param (but list_graphs is exempt since + it sets the graph, not queries one); none makes it required.""" app = serve_mod._build_http_app(_graph_file(tmp_path), json_response=True) with _client(app) as client: headers = _init_session(client) resp = client.post("/mcp", headers=headers, json={"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {}}) for tool in resp.json()["result"]["tools"]: + if tool["name"] == "list_graphs": + continue props = tool["inputSchema"].get("properties", {}) - assert "project_path" in props, f"{tool['name']} missing project_path" - assert "project_path" not in tool["inputSchema"].get("required", []) - - -def test_project_path_routes_to_that_projects_graph(tmp_path): - """One running server answers against the default graph when project_path is - omitted, and against a project's own graph when it is supplied.""" - proj = _project_with_graph(tmp_path, node_count=3) # default graph has 2 nodes - app = serve_mod._build_http_app(_graph_file(tmp_path), json_response=True) + assert "graph" in props, f"{tool['name']} missing graph param" + assert "graph" not in tool["inputSchema"].get("required", []) + + +def test_graph_param_routes_to_that_graph(tmp_path): + """A multi-graph server answers the default graph when graph param is omitted + and a specific graph when graph param is provided.""" + # Write two graph directories + alpha_dir = tmp_path / "alpha" + alpha_dir.mkdir() + beta_dir = tmp_path / "beta" + beta_dir.mkdir() + alpha_graph = {"directed": True, "nodes": [{"id": "a", "label": "A", "community": 0}], "edges": []} + beta_graph = {"directed": True, "nodes": [ + {"id": "b1", "label": "B1", "community": 0}, + {"id": "b2", "label": "B2", "community": 0}, + {"id": "b3", "label": "B3", "community": 0}, + ], "edges": []} + (alpha_dir / "graph.json").write_text(json.dumps(alpha_graph), encoding="utf-8") + (beta_dir / "graph.json").write_text(json.dumps(beta_graph), encoding="utf-8") + registry = serve_mod.GraphRegistry.from_directory(tmp_path) + app = serve_mod._build_http_app(registry=registry, json_response=True) with _client(app) as client: headers = _init_session(client) - assert "Nodes: 2" in _call_tool(client, headers, "graph_stats", {}, rid=2) - assert "Nodes: 3" in _call_tool(client, headers, "graph_stats", {"project_path": proj}, rid=3) - # Falling back to the default afterwards still works (no state leak). - assert "Nodes: 2" in _call_tool(client, headers, "graph_stats", {}, rid=4) + assert "Nodes: 1" in _call_tool(client, headers, "graph_stats", {"graph": "alpha"}, rid=2) + assert "Nodes: 3" in _call_tool(client, headers, "graph_stats", {"graph": "beta"}, rid=3) @pytest.mark.parametrize( @@ -251,46 +264,37 @@ def counting_load(path: str): return original_load(path) monkeypatch.setattr(serve_mod, "_load_graph", counting_load) - projects = [ - _project_with_graph(tmp_path, node_count=i + 3, name=f"project-{i}") - for i in range(3) - ] + projects = [_project_with_graph(tmp_path, node_count=i + 3, name=f"project-{i}") for i in range(3)] default_graph = _graph_file(tmp_path) app = serve_mod._build_http_app(default_graph, json_response=True) with _client(app) as client: headers = _init_session(client) assert "Nodes: 3" in _call_tool(client, headers, "graph_stats", {"project_path": projects[0]}, rid=2) assert "Nodes: 4" in _call_tool(client, headers, "graph_stats", {"project_path": projects[1]}, rid=3) - # A cache hit promotes project-0 above project-1 in LRU recency. assert "Nodes: 3" in _call_tool(client, headers, "graph_stats", {"project_path": projects[0]}, rid=4) assert "Nodes: 5" in _call_tool(client, headers, "graph_stats", {"project_path": projects[2]}, rid=5) - # project-1, not the re-touched project-0, was evicted. assert "Nodes: 4" in _call_tool(client, headers, "graph_stats", {"project_path": projects[1]}, rid=6) - # The configured default graph stays warm even when project capacity is full. assert "Nodes: 2" in _call_tool(client, headers, "graph_stats", {}, rid=7) first_graph = str((Path(projects[0]) / "graphify-out" / "graph.json").resolve()) second_graph = str((Path(projects[1]) / "graphify-out" / "graph.json").resolve()) - default_graph = str(Path(default_graph).resolve()) assert loads[first_graph] == 1 assert loads[second_graph] == 2 - assert loads[default_graph] == 1 -def test_bad_project_path_errors_without_killing_server(tmp_path): - """A missing project graph is a tool error, not a process exit — the server - keeps serving the default graph.""" +def test_bad_graph_param_errors_without_killing_server(tmp_path): + """A bad graph name is a tool error, not a process exit — the server + keeps serving other graphs.""" app = serve_mod._build_http_app(_graph_file(tmp_path), json_response=True) with _client(app) as client: headers = _init_session(client) bad = _call_tool(client, headers, "graph_stats", - {"project_path": str(tmp_path / "does-not-exist")}, rid=2) + {"graph": "does-not-exist"}, rid=2) assert "not found" in bad.lower() assert "Nodes: 2" in _call_tool(client, headers, "graph_stats", {}, rid=3) def test_corrupt_project_graph_is_a_tool_error_without_killing_server(tmp_path): - """A CLI-style SystemExit from a client graph cannot stop the MCP server.""" project = Path(_project_with_graph(tmp_path, node_count=3)) (project / "graphify-out" / "graph.json").write_text("{not json", encoding="utf-8") app = serve_mod._build_http_app(_graph_file(tmp_path), json_response=True) diff --git a/tools/skillgen/expected/graphify__skill-agents.md b/tools/skillgen/expected/graphify__skill-agents.md index 190827d9ac..2ff7840c3b 100644 --- a/tools/skillgen/expected/graphify__skill-agents.md +++ b/tools/skillgen/expected/graphify__skill-agents.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -547,7 +548,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-aider.md b/tools/skillgen/expected/graphify__skill-aider.md index 4996beb787..398012b35f 100644 --- a/tools/skillgen/expected/graphify__skill-aider.md +++ b/tools/skillgen/expected/graphify__skill-aider.md @@ -22,6 +22,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --neo4j # generate graphify-out/cypher.txt for Neo4j /graphify --neo4j-push bolt://localhost:7687 # push directly to Neo4j /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify add # fetch URL, save to ./raw, update graph /graphify add --author "Name" # tag who wrote it diff --git a/tools/skillgen/expected/graphify__skill-amp.md b/tools/skillgen/expected/graphify__skill-amp.md index 190827d9ac..2ff7840c3b 100644 --- a/tools/skillgen/expected/graphify__skill-amp.md +++ b/tools/skillgen/expected/graphify__skill-amp.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -547,7 +548,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-claw.md b/tools/skillgen/expected/graphify__skill-claw.md index abd2811d23..3e1d9f2fda 100644 --- a/tools/skillgen/expected/graphify__skill-claw.md +++ b/tools/skillgen/expected/graphify__skill-claw.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -550,7 +551,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-codex.md b/tools/skillgen/expected/graphify__skill-codex.md index af3f723c78..fdb69319dc 100644 --- a/tools/skillgen/expected/graphify__skill-codex.md +++ b/tools/skillgen/expected/graphify__skill-codex.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -547,7 +548,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-copilot.md b/tools/skillgen/expected/graphify__skill-copilot.md index abd2811d23..3e1d9f2fda 100644 --- a/tools/skillgen/expected/graphify__skill-copilot.md +++ b/tools/skillgen/expected/graphify__skill-copilot.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -550,7 +551,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-devin.md b/tools/skillgen/expected/graphify__skill-devin.md index f9be846cbf..214ba319a4 100644 --- a/tools/skillgen/expected/graphify__skill-devin.md +++ b/tools/skillgen/expected/graphify__skill-devin.md @@ -32,6 +32,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --neo4j # generate graphify-out/cypher.txt for Neo4j /graphify --neo4j-push bolt://localhost:7687 # push directly to Neo4j /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify add # fetch URL, save to ./raw, update graph diff --git a/tools/skillgen/expected/graphify__skill-droid.md b/tools/skillgen/expected/graphify__skill-droid.md index fd148d485d..f75bdf79b5 100644 --- a/tools/skillgen/expected/graphify__skill-droid.md +++ b/tools/skillgen/expected/graphify__skill-droid.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -547,7 +548,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-kilo.md b/tools/skillgen/expected/graphify__skill-kilo.md index 3e70b050a4..eb787b76fa 100644 --- a/tools/skillgen/expected/graphify__skill-kilo.md +++ b/tools/skillgen/expected/graphify__skill-kilo.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -550,7 +551,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-kiro.md b/tools/skillgen/expected/graphify__skill-kiro.md index abd2811d23..3e1d9f2fda 100644 --- a/tools/skillgen/expected/graphify__skill-kiro.md +++ b/tools/skillgen/expected/graphify__skill-kiro.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -550,7 +551,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-opencode.md b/tools/skillgen/expected/graphify__skill-opencode.md index 91ced60675..5e2ae50f7d 100644 --- a/tools/skillgen/expected/graphify__skill-opencode.md +++ b/tools/skillgen/expected/graphify__skill-opencode.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -542,7 +543,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-pi.md b/tools/skillgen/expected/graphify__skill-pi.md index abd2811d23..3e1d9f2fda 100644 --- a/tools/skillgen/expected/graphify__skill-pi.md +++ b/tools/skillgen/expected/graphify__skill-pi.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -550,7 +551,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-trae.md b/tools/skillgen/expected/graphify__skill-trae.md index 050667bc20..79b80cbaff 100644 --- a/tools/skillgen/expected/graphify__skill-trae.md +++ b/tools/skillgen/expected/graphify__skill-trae.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -548,7 +549,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-vscode.md b/tools/skillgen/expected/graphify__skill-vscode.md index 20c7c0835c..23f05b032f 100644 --- a/tools/skillgen/expected/graphify__skill-vscode.md +++ b/tools/skillgen/expected/graphify__skill-vscode.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -546,7 +547,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-windows.md b/tools/skillgen/expected/graphify__skill-windows.md index d631821ec3..56b9df37d1 100644 --- a/tools/skillgen/expected/graphify__skill-windows.md +++ b/tools/skillgen/expected/graphify__skill-windows.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -572,7 +573,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill.md b/tools/skillgen/expected/graphify__skill.md index abd2811d23..3e1d9f2fda 100644 --- a/tools/skillgen/expected/graphify__skill.md +++ b/tools/skillgen/expected/graphify__skill.md @@ -29,6 +29,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -550,7 +551,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skills__agents__references__exports.md b/tools/skillgen/expected/graphify__skills__agents__references__exports.md index 242ff868e0..89430e90ef 100644 --- a/tools/skillgen/expected/graphify__skills__agents__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__agents__references__exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__amp__references__exports.md b/tools/skillgen/expected/graphify__skills__amp__references__exports.md index 242ff868e0..89430e90ef 100644 --- a/tools/skillgen/expected/graphify__skills__amp__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__amp__references__exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__claude__references__exports.md b/tools/skillgen/expected/graphify__skills__claude__references__exports.md index 242ff868e0..89430e90ef 100644 --- a/tools/skillgen/expected/graphify__skills__claude__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__claude__references__exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__claw__references__exports.md b/tools/skillgen/expected/graphify__skills__claw__references__exports.md index 242ff868e0..89430e90ef 100644 --- a/tools/skillgen/expected/graphify__skills__claw__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__claw__references__exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__codex__references__exports.md b/tools/skillgen/expected/graphify__skills__codex__references__exports.md index 242ff868e0..89430e90ef 100644 --- a/tools/skillgen/expected/graphify__skills__codex__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__codex__references__exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__copilot__references__exports.md b/tools/skillgen/expected/graphify__skills__copilot__references__exports.md index 242ff868e0..89430e90ef 100644 --- a/tools/skillgen/expected/graphify__skills__copilot__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__copilot__references__exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__droid__references__exports.md b/tools/skillgen/expected/graphify__skills__droid__references__exports.md index 242ff868e0..89430e90ef 100644 --- a/tools/skillgen/expected/graphify__skills__droid__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__droid__references__exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__kilo__references__exports.md b/tools/skillgen/expected/graphify__skills__kilo__references__exports.md index 242ff868e0..89430e90ef 100644 --- a/tools/skillgen/expected/graphify__skills__kilo__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__kilo__references__exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__kiro__references__exports.md b/tools/skillgen/expected/graphify__skills__kiro__references__exports.md index 242ff868e0..89430e90ef 100644 --- a/tools/skillgen/expected/graphify__skills__kiro__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__kiro__references__exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__opencode__references__exports.md b/tools/skillgen/expected/graphify__skills__opencode__references__exports.md index 242ff868e0..89430e90ef 100644 --- a/tools/skillgen/expected/graphify__skills__opencode__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__opencode__references__exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__pi__references__exports.md b/tools/skillgen/expected/graphify__skills__pi__references__exports.md index 242ff868e0..89430e90ef 100644 --- a/tools/skillgen/expected/graphify__skills__pi__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__pi__references__exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__trae__references__exports.md b/tools/skillgen/expected/graphify__skills__trae__references__exports.md index 242ff868e0..89430e90ef 100644 --- a/tools/skillgen/expected/graphify__skills__trae__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__trae__references__exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__vscode__references__exports.md b/tools/skillgen/expected/graphify__skills__vscode__references__exports.md index 242ff868e0..89430e90ef 100644 --- a/tools/skillgen/expected/graphify__skills__vscode__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__vscode__references__exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__windows__references__exports.md b/tools/skillgen/expected/graphify__skills__windows__references__exports.md index 242ff868e0..89430e90ef 100644 --- a/tools/skillgen/expected/graphify__skills__windows__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__windows__references__exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/fragments/core/aider.md b/tools/skillgen/fragments/core/aider.md index 4996beb787..398012b35f 100644 --- a/tools/skillgen/fragments/core/aider.md +++ b/tools/skillgen/fragments/core/aider.md @@ -22,6 +22,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --neo4j # generate graphify-out/cypher.txt for Neo4j /graphify --neo4j-push bolt://localhost:7687 # push directly to Neo4j /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify add # fetch URL, save to ./raw, update graph /graphify add --author "Name" # tag who wrote it diff --git a/tools/skillgen/fragments/core/core.md b/tools/skillgen/fragments/core/core.md index c527a12563..8b89bf4903 100644 --- a/tools/skillgen/fragments/core/core.md +++ b/tools/skillgen/fragments/core/core.md @@ -26,6 +26,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -485,7 +486,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/fragments/core/devin.md b/tools/skillgen/fragments/core/devin.md index f9be846cbf..214ba319a4 100644 --- a/tools/skillgen/fragments/core/devin.md +++ b/tools/skillgen/fragments/core/devin.md @@ -32,6 +32,7 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --neo4j # generate graphify-out/cypher.txt for Neo4j /graphify --neo4j-push bolt://localhost:7687 # push directly to Neo4j /graphify --mcp # start MCP stdio server for agent access +/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify add # fetch URL, save to ./raw, update graph diff --git a/tools/skillgen/fragments/references/shared/exports.md b/tools/skillgen/fragments/references/shared/exports.md index 242ff868e0..89430e90ef 100644 --- a/tools/skillgen/fragments/references/shared/exports.md +++ b/tools/skillgen/fragments/references/shared/exports.md @@ -76,6 +76,20 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` +### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) + +For serving multiple graphs from one endpoint: + +```bash +# structure: my-graphs//graph.json +docker build --target multi -t graphify-multi . +docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +``` + +This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. + +Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. + ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: From 70194e1ed006824795023053806aa7f774a36e74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yanis=20Gu=C3=A9rault?= Date: Tue, 25 Aug 2026 17:01:26 +0200 Subject: [PATCH 2/2] refactor(mcp): move multi-graph serving to --mcp Replace directory discovery with explicit repository paths and remove the legacy multi-MCP deployment workflow. --- Dockerfile | 31 +-- README.md | 37 ++-- docker-compose.multi.yml | 21 +- graphify/__main__.py | 124 +++++++++++ graphify/serve.py | 183 ++++++---------- graphify/skill-agents.md | 3 +- graphify/skill-aider.md | 1 - graphify/skill-amp.md | 3 +- graphify/skill-claw.md | 3 +- graphify/skill-codex.md | 3 +- graphify/skill-copilot.md | 3 +- graphify/skill-devin.md | 1 - graphify/skill-droid.md | 3 +- graphify/skill-kilo.md | 3 +- graphify/skill-kiro.md | 3 +- graphify/skill-opencode.md | 3 +- graphify/skill-pi.md | 3 +- graphify/skill-trae.md | 3 +- graphify/skill-vscode.md | 3 +- graphify/skill-windows.md | 3 +- graphify/skill.md | 3 +- graphify/skills/agents/references/exports.md | 14 -- graphify/skills/amp/references/exports.md | 14 -- graphify/skills/claude/references/exports.md | 14 -- graphify/skills/claw/references/exports.md | 14 -- graphify/skills/codex/references/exports.md | 14 -- graphify/skills/copilot/references/exports.md | 14 -- graphify/skills/droid/references/exports.md | 14 -- graphify/skills/kilo/references/exports.md | 14 -- graphify/skills/kiro/references/exports.md | 14 -- .../skills/opencode/references/exports.md | 14 -- graphify/skills/pi/references/exports.md | 14 -- graphify/skills/trae/references/exports.md | 14 -- graphify/skills/vscode/references/exports.md | 14 -- graphify/skills/windows/references/exports.md | 14 -- tests/test_mcp_cli.py | 194 +++++++++++++++++ tests/test_serve.py | 198 +++++++++--------- tests/test_serve_http.py | 44 ++-- .../expected/graphify__skill-agents.md | 3 +- .../expected/graphify__skill-aider.md | 1 - .../skillgen/expected/graphify__skill-amp.md | 3 +- .../skillgen/expected/graphify__skill-claw.md | 3 +- .../expected/graphify__skill-codex.md | 3 +- .../expected/graphify__skill-copilot.md | 3 +- .../expected/graphify__skill-devin.md | 1 - .../expected/graphify__skill-droid.md | 3 +- .../skillgen/expected/graphify__skill-kilo.md | 3 +- .../skillgen/expected/graphify__skill-kiro.md | 3 +- .../expected/graphify__skill-opencode.md | 3 +- tools/skillgen/expected/graphify__skill-pi.md | 3 +- .../skillgen/expected/graphify__skill-trae.md | 3 +- .../expected/graphify__skill-vscode.md | 3 +- .../expected/graphify__skill-windows.md | 3 +- tools/skillgen/expected/graphify__skill.md | 3 +- ...fy__skills__agents__references__exports.md | 14 -- ...phify__skills__amp__references__exports.md | 14 -- ...fy__skills__claude__references__exports.md | 14 -- ...hify__skills__claw__references__exports.md | 14 -- ...ify__skills__codex__references__exports.md | 14 -- ...y__skills__copilot__references__exports.md | 14 -- ...ify__skills__droid__references__exports.md | 14 -- ...hify__skills__kilo__references__exports.md | 14 -- ...hify__skills__kiro__references__exports.md | 14 -- ...__skills__opencode__references__exports.md | 14 -- ...aphify__skills__pi__references__exports.md | 14 -- ...hify__skills__trae__references__exports.md | 14 -- ...fy__skills__vscode__references__exports.md | 14 -- ...y__skills__windows__references__exports.md | 14 -- tools/skillgen/fragments/core/aider.md | 1 - tools/skillgen/fragments/core/core.md | 3 +- tools/skillgen/fragments/core/devin.md | 1 - .../fragments/references/shared/exports.md | 14 -- tools/skillgen/gen.py | 2 +- 73 files changed, 565 insertions(+), 768 deletions(-) create mode 100644 tests/test_mcp_cli.py diff --git a/Dockerfile b/Dockerfile index f3521e1f22..a4e62eb172 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,36 +1,15 @@ -# graphify MCP server — single-graph and multi-graph targets. -# -# Single-graph (existing, default): -# docker build -t graphify . -# docker run -p 8080:8080 -v "$(pwd)/graphify-out:/data" graphify \ -# /data/graph.json --transport http --host 0.0.0.0 --api-key "$SECRET" -# -# Multi-graph: -# docker build --target multi -t graphify-multi . -# docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi - -FROM python:3.12-slim AS base +# graphify MCP server. Mount a repository containing graphify-out/graph.json. +FROM python:3.12-slim WORKDIR /app COPY . /app # The [mcp] extra pulls mcp + starlette + uvicorn, which the HTTP transport needs. RUN pip install --no-cache-dir ".[mcp]" -# Run as a non-root user — the server is network-exposed. +# Run as a non-root user because the server is network-exposed. RUN useradd --create-home --uid 10001 graphify USER graphify -# --- Single-graph target (default, backward-compatible) --- -FROM base AS single -EXPOSE 8080 -ENTRYPOINT ["python", "-m", "graphify.serve"] -CMD ["/data/graph.json", "--transport", "http", "--host", "0.0.0.0", "--port", "8080"] - -# --- Multi-graph target --- -FROM base AS multi EXPOSE 8080 -VOLUME /graphs -ENV GRAPHS_DIR=/graphs -ENV SCAN_INTERVAL=30 -ENV PORT=8080 -ENTRYPOINT ["graphify-mcp", "--transport", "http", "--host", "0.0.0.0"] +ENTRYPOINT ["graphify"] +CMD ["/data", "--mcp", "--transport", "http", "--host", "0.0.0.0", "--port", "8080"] diff --git a/README.md b/README.md index a4890192e4..2fdf1c3afd 100644 --- a/README.md +++ b/README.md @@ -485,8 +485,7 @@ The default `127.0.0.1` bind is loopback-only. Set `--host 0.0.0.0` **and** `--a ```bash docker build -t graphify . -docker run -p 8080:8080 -v "$(pwd)/graphify-out:/data" graphify \ - /data/graph.json --transport http --host 0.0.0.0 --api-key "$SECRET" +docker run -p 8080:8080 -v "$(pwd):/data:ro" graphify /data --mcp --transport http --host 0.0.0.0 --api-key "$SECRET" ``` > **WSL / Linux note:** Ubuntu ships `python3`, not `python`. Use a venv to avoid conflicts: @@ -496,29 +495,29 @@ docker run -p 8080:8080 -v "$(pwd)/graphify-out:/data" graphify \ ### Multi-graph MCP server -Serve multiple knowledge graphs from a single endpoint — useful for multi-repo setups, monorepos with per-service graphs, or comparing codebases. +Serve multiple repositories containing `graphify-out/graph.json` from one MCP endpoint. This is useful for multi-repo setups, monorepos with per-service graphs, or comparing codebases. ```bash -# structure: one folder per graph -my-graphs/ - frontend/graph.json - backend/graph.json - shared-lib/graph.json +# Serve over stdio (the default transport). +graphify ../frontend ../backend --mcp -# run with Docker -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi +# Serve over HTTP. +graphify ../frontend ../backend --mcp --transport http --host 0.0.0.0 --port 8080 +``` -# or with docker-compose -docker compose -f docker-compose.multi.yml up --build +Each repository path must contain `graphify-out/graph.json`. To run the documented two-repository example in Docker, arrange the Compose directory as: + +```text +repos/ + frontend/graphify-out/graph.json + backend/graphify-out/graph.json ``` -| Env var | Default | Purpose | -|---|---|---| -| `GRAPHS_DIR` | `/graphs` | Mount point to scan for `/graph.json` | -| `SCAN_INTERVAL` | `30` | Seconds between auto-discovery rescans | -| `PORT` | `8080` | HTTP listen port | -| `GRAPHIFY_API_KEY` | — | Require `Authorization: Bearer ` | +Then start the public CLI through Compose: + +```bash +docker compose -f docker-compose.multi.yml up --build +``` Tools: same as single-graph (`query_graph`, `get_node`, `get_neighbors`, etc.) plus `list_graphs` and `use_graph`. Each tool accepts an optional `graph` parameter to target a specific graph, or use `use_graph` to set a session default. diff --git a/docker-compose.multi.yml b/docker-compose.multi.yml index 230c12e144..0bbbc7908a 100644 --- a/docker-compose.multi.yml +++ b/docker-compose.multi.yml @@ -1,18 +1,11 @@ -# docker-compose.multi.yml -# Quick start for multi-graph MCP server. -# -# Place graphs as: ./my-graphs//graph.json -# Start: docker compose -f docker-compose.multi.yml up --build +# Quick start: docker compose -f docker-compose.multi.yml up --build +# Runs: graphify /repos/frontend /repos/backend --mcp services: graphify-mcp: - build: - context: . - target: multi + build: . ports: - - "8080:8080" + - "127.0.0.1:8080:8080" volumes: - - ./my-graphs:/graphs:ro - environment: - - SCAN_INTERVAL=30 - - PORT=8080 - # - GRAPHIFY_API_KEY=your-secret-key + - ./repos/frontend:/repos/frontend:ro + - ./repos/backend:/repos/backend:ro + command: ["/repos/frontend", "/repos/backend", "--mcp", "--transport", "http", "--host", "0.0.0.0", "--port", "8080"] diff --git a/graphify/__main__.py b/graphify/__main__.py index 155501a98d..011e1be8ee 100644 --- a/graphify/__main__.py +++ b/graphify/__main__.py @@ -479,6 +479,122 @@ def main() -> None: raise +def _start_mcp_registry(registry) -> None: + from graphify.serve import serve + + serve(registry=registry) + + +def _serve_mcp_repositories( + paths: list[str], + *, + transport: str, + host: str = "127.0.0.1", + port: int = 8080, + api_key: str | None = None, +) -> None: + from graphify.serve import GraphRegistry + + if not paths: + print("error: --mcp requires at least one repository path", file=sys.stderr) + raise SystemExit(1) + resolved = [Path(path).resolve() for path in paths] + names = [path.name for path in resolved] + duplicate = next((name for name in names if names.count(name) > 1), None) + if duplicate is not None: + print(f"error: duplicate graph name {duplicate!r}; repository basenames must be unique", file=sys.stderr) + raise SystemExit(1) + graph_paths = [] + for repo in resolved: + graph_path = repo / _GRAPHIFY_OUT / "graph.json" + try: + exists = graph_path.is_file() + except OSError as exc: + print(f"error: could not read graph: {graph_path} ({exc})", file=sys.stderr) + raise SystemExit(1) from None + if not exists: + print(f"error: graph not found: {graph_path}", file=sys.stderr) + raise SystemExit(1) + graph_paths.append(graph_path) + try: + registry = GraphRegistry.from_paths(graph_paths) + except OSError as exc: + print(f"error: could not read graph: {exc}", file=sys.stderr) + raise SystemExit(1) from None + if transport == "http": + from graphify.serve import serve_http + + serve_http(registry=registry, host=host, port=port, api_key=api_key) + else: + _start_mcp_registry(registry) + + +def _run_mcp_cli(args: list[str]) -> bool: + if "--mcp" not in args: + return False + + paths: list[str] = [] + transport = "stdio" + host = "127.0.0.1" + port = 8080 + api_key: str | None = None + index = 0 + while index < len(args): + arg = args[index] + if arg == "--mcp": + index += 1 + elif arg == "--transport": + index += 1 + if index == len(args) or args[index] not in {"stdio", "http"}: + print("error: --transport must be stdio or http", file=sys.stderr) + raise SystemExit(1) + transport = args[index] + index += 1 + elif arg == "--host": + index += 1 + if index == len(args): + print("error: --host requires a value", file=sys.stderr) + raise SystemExit(1) + if args[index].startswith("-"): + print(f"error: unrecognized MCP option: {args[index]}", file=sys.stderr) + raise SystemExit(1) + host = args[index] + index += 1 + elif arg == "--port": + index += 1 + if index == len(args): + print("error: --port requires an integer", file=sys.stderr) + raise SystemExit(1) + try: + port = int(args[index]) + except ValueError: + print("error: --port requires an integer", file=sys.stderr) + raise SystemExit(1) from None + index += 1 + elif arg == "--api-key": + index += 1 + if index == len(args): + print("error: --api-key requires a value", file=sys.stderr) + raise SystemExit(1) + if args[index].startswith("-"): + print(f"error: unrecognized MCP option: {args[index]}", file=sys.stderr) + raise SystemExit(1) + api_key = args[index] + index += 1 + elif arg.startswith("-"): + print(f"error: unrecognized MCP option: {arg}", file=sys.stderr) + raise SystemExit(1) + else: + paths.append(arg) + index += 1 + + if transport == "stdio" and host == "127.0.0.1" and port == 8080 and api_key is None: + _serve_mcp_repositories(paths, transport=transport) + else: + _serve_mcp_repositories(paths, transport=transport, host=host, port=port, api_key=api_key) + return True + + def _run_cli() -> None: for _stream in (sys.stdout, sys.stderr): if _stream is not None and hasattr(_stream, "reconfigure"): @@ -502,10 +618,18 @@ def _run_cli() -> None: print(f"graphify {__version__}") return + if _run_mcp_cli(sys.argv[1:]): + return + if len(sys.argv) < 2 or sys.argv[1] in ("-h", "--help", "-?"): print("Usage: graphify ") print() print("Commands:") + print(" ... --mcp serve existing repository graphs over MCP stdio") + print(" --transport stdio|http transport (default: stdio)") + print(" --host HOST HTTP bind host (default: 127.0.0.1)") + print(" --port PORT HTTP bind port (default: 8080)") + print(" --api-key KEY require this key for HTTP requests") print(" install [--platform P] copy skill to platform config dir (claude|windows|codebuddy|codex|opencode|aider|amp|agents|claw|droid|trae|trae-cn|gemini|cursor|antigravity|hermes|kiro|pi|devin)") print(" uninstall remove graphify from all detected platforms in one shot") print(" --purge also delete graphify-out/ directory") diff --git a/graphify/serve.py b/graphify/serve.py index 8949dd1949..47b5bf1766 100644 --- a/graphify/serve.py +++ b/graphify/serve.py @@ -6,6 +6,7 @@ import re import sys import threading +import weakref from array import array from collections import OrderedDict from dataclasses import dataclass @@ -37,7 +38,8 @@ class GraphContext: class GraphRegistry: def __init__(self) -> None: self._graphs: dict[str, GraphContext] = {} - self._graphs_dir: Path | None = None + self._allow_project_paths = True + self._load_learning_overlay = True self._lock = threading.Lock() @classmethod @@ -56,25 +58,32 @@ def from_path(cls, graph_path: Path) -> "GraphRegistry": return reg @classmethod - def from_directory(cls, graphs_dir: Path) -> "GraphRegistry": + def from_paths(cls, graph_paths: list[Path]) -> "GraphRegistry": reg = cls() - reg._graphs_dir = Path(graphs_dir) - reg._do_scan() + reg._allow_project_paths = False + reg._load_learning_overlay = False + for path in graph_paths: + graph_path = Path(path).resolve() + G = _load_graph(str(graph_path), load_learning_overlay=False) + _get_trigram_index(G) + communities = _communities_from_graph(G) + name = graph_path.parent.parent.name or "default" + mtime = graph_path.stat().st_mtime + reg._graphs[name] = GraphContext( + name=name, path=graph_path, graph=G, + communities=communities, mtime=mtime, + ) return reg def rescan(self) -> None: - if self._graphs_dir is not None: - self._do_scan() - else: - self._reload_single() - - def _reload_single(self) -> None: with self._lock: for name, ctx in list(self._graphs.items()): try: s = ctx.path.stat() if s.st_mtime != ctx.mtime: - G = _load_graph(str(ctx.path)) + G = _load_graph( + str(ctx.path), load_learning_overlay=self._load_learning_overlay + ) _get_trigram_index(G) communities = _communities_from_graph(G) self._graphs[name] = GraphContext( @@ -84,42 +93,6 @@ def _reload_single(self) -> None: except (OSError, SystemExit, Exception): del self._graphs[name] - def _do_scan(self) -> None: - import logging - if self._graphs_dir is None: - return - logger = logging.getLogger(__name__) - found: dict[str, GraphContext] = {} - for entry in sorted(self._graphs_dir.iterdir()): - if not entry.is_dir(): - continue - graph_file = entry / "graph.json" - if not graph_file.exists(): - continue - name = entry.name - try: - mtime = graph_file.stat().st_mtime - except OSError: - continue - existing = self._graphs.get(name) - if existing is not None and existing.mtime == mtime: - found[name] = existing - continue - try: - G = _load_graph(str(graph_file)) - except (SystemExit, Exception) as exc: - logger.warning("skipping %s: %s", graph_file, exc) - continue - _get_trigram_index(G) - communities = _communities_from_graph(G) - found[name] = GraphContext( - name=name, path=graph_file, graph=G, - communities=communities, mtime=mtime, - ) - logger.info("loaded graph %r (%d nodes)", name, G.number_of_nodes()) - with self._lock: - self._graphs = found - def get(self, name: str) -> GraphContext | None: return self._graphs.get(name) @@ -150,7 +123,7 @@ def _resolve_graph( ) -def _load_graph(graph_path: str) -> nx.Graph: +def _load_graph(graph_path: str, *, load_learning_overlay: bool = True) -> nx.Graph: try: resolved = Path(graph_path).resolve() if resolved.suffix != ".json": @@ -183,13 +156,15 @@ def _load_graph(graph_path: str) -> nx.Graph: except TypeError: G = json_graph.node_link_graph(data) G.graph["_logical_directed"] = _logical_directed - # Attach the work-memory overlay (derived sidecar next to graph.json) so - # the query/MCP read surface can annotate NODE lines display-only. Empty - # when no sidecar exists, leaving un-annotated output byte-identical. - try: - from graphify.reflect import load_learning_overlay as _llo - G.graph["_learning_overlay"] = _llo(resolved) - except Exception: + if load_learning_overlay: + # Attach the work-memory overlay (derived sidecar next to graph.json) + # so the query/MCP read surface can annotate NODE lines display-only. + try: + from graphify.reflect import load_learning_overlay as _llo + G.graph["_learning_overlay"] = _llo(resolved) + except Exception: + G.graph["_learning_overlay"] = {} + else: G.graph["_learning_overlay"] = {} return G except json.JSONDecodeError as exc: @@ -1655,8 +1630,9 @@ def _build_server(registry: GraphRegistry, *, session_state: dict | None = None) # AnyUrl (pydantic is an mcp dependency, so this import cannot miss). from pydantic import AnyUrl - if session_state is None: - session_state = {} + session_states: weakref.WeakKeyDictionary = weakref.WeakKeyDictionary() + fixed_session_state = session_state + fallback_session_state: dict = {} is_multi = len(registry.names()) > 1 _ctx_cache = _GraphContextCache(_max_server_contexts()) default_paths = { @@ -1665,10 +1641,22 @@ def _build_server(registry: GraphRegistry, *, session_state: dict | None = None) if (ctx := registry.get(name)) is not None } + def _current_session_state() -> dict: + if fixed_session_state is not None: + return fixed_session_state + try: + session = server.request_context.session + except LookupError: + return fallback_session_state + return session_states.setdefault(session, {}) + def _get_ctx(arguments: dict) -> GraphContext: + registry.rescan() graph_param = arguments.pop("graph", None) project_path = arguments.pop("project_path", None) if project_path: + if not registry._allow_project_paths: + raise ValueError("project_path is not supported by an explicit --mcp registry") path = str((Path(project_path) / _paths.GRAPHIFY_OUT / "graph.json").resolve()) graph, communities = _ctx_cache.load(path, pinned=path in default_paths) return GraphContext( @@ -1681,7 +1669,7 @@ def _get_ctx(arguments: dict) -> GraphContext: return _resolve_graph( registry, graph=graph_param, - current=session_state.get("current_graph"), + current=_current_session_state().get("current_graph"), ) # NOTE: no decorators here — the handlers below are plain coroutines, @@ -1850,7 +1838,7 @@ async def list_tools() -> list[types.Tool]: "type": "string", "description": "Target graph name. Overrides session default.", } - if _t.name not in ("list_graphs", "use_graph"): + if registry._allow_project_paths and _t.name not in ("list_graphs", "use_graph"): _schema.setdefault("properties", {})["project_path"] = { "type": "string", "description": ( @@ -2111,6 +2099,7 @@ def _tool_triage_prs(arguments: dict) -> str: return "\n\n".join(lines) def _tool_list_graphs(arguments: dict) -> str: + registry.rescan() lines = [] for name in registry.names(): ctx = registry.get(name) @@ -2127,11 +2116,12 @@ def _tool_list_graphs(arguments: dict) -> str: return "\n".join(lines) def _tool_use_graph(arguments: dict) -> str: + registry.rescan() name = arguments["graph"] ctx = registry.get(name) if ctx is None: return f"Graph {name!r} not found. Available: {registry.names()}" - session_state["current_graph"] = name + _current_session_state()["current_graph"] = name return f"Switched to graph {name!r} ({ctx.graph.number_of_nodes()} nodes)" _handlers: dict = { @@ -2152,7 +2142,7 @@ def _tool_use_graph(arguments: dict) -> str: _handlers["triage_prs"] = _tool_triage_prs def _load_community_labels() -> dict[int, str]: - ctx = _resolve_graph(registry, current=session_state.get("current_graph")) + ctx = _resolve_graph(registry, current=_current_session_state().get("current_graph")) labels_path = ctx.path.parent / ".graphify_labels.json" if labels_path.exists(): try: @@ -2174,7 +2164,8 @@ async def list_resources() -> list[types.Resource]: ] async def read_resource(uri: AnyUrl) -> str: - ctx = _resolve_graph(registry, current=session_state.get("current_graph")) + registry.rescan() + ctx = _resolve_graph(registry, current=_current_session_state().get("current_graph")) G = ctx.graph communities = ctx.communities active_graph_path = str(ctx.path) @@ -2296,7 +2287,7 @@ async def _on_read_resource(ctx, params) -> types.ReadResourceResult: return server, _handlers -def serve(graph_path: str | None = None) -> None: +def serve(graph_path: str | None = None, *, registry: GraphRegistry | None = None) -> None: """Start the MCP server over stdio (the default, per-developer transport).""" graph_path = graph_path or _default_graph_json() try: @@ -2305,7 +2296,8 @@ def serve(graph_path: str | None = None) -> None: raise ImportError('mcp not installed. Run: pip install "graphifyy[mcp]"') from e import asyncio - registry = GraphRegistry.from_path(Path(graph_path)) + if registry is None: + registry = GraphRegistry.from_path(Path(graph_path)) server, _ = _build_server(registry) async def main() -> None: @@ -2481,8 +2473,8 @@ def serve_http( deliberate follow-up. Binding ``0.0.0.0`` exposes the server beyond localhost — set an api_key when you do. - ``registry`` can be supplied directly for multi-graph mode (``--graphs-dir``); - when provided ``graph_path`` is ignored. + ``registry`` can be supplied directly for multi-graph mode; when provided + ``graph_path`` is ignored. """ if registry is None: graph_path = graph_path or _default_graph_json() @@ -2573,50 +2565,12 @@ def _main(argv: list[str] | None = None) -> None: default=3600.0, help="Reap stateful sessions idle this many seconds (default: 3600; 0 disables)", ) - parser.add_argument( - "--graphs-dir", - default=os.environ.get("GRAPHS_DIR"), - metavar="PATH", - help="Directory of graph subdirs for multi-graph mode (env: GRAPHS_DIR). Forces HTTP transport.", - ) args = parser.parse_args(argv) - if args.graphs_dir: - graphs_dir = Path(args.graphs_dir) - if not graphs_dir.is_dir(): - print(f"error: --graphs-dir {graphs_dir} does not exist", file=sys.stderr) - sys.exit(1) - if args.transport == "stdio": - print("error: --graphs-dir requires HTTP transport (multi-graph over stdio is not supported)", file=sys.stderr) - sys.exit(1) - registry = GraphRegistry.from_directory(graphs_dir) - if not registry.names(): - print(f"error: no graphs found in {graphs_dir}/ (expected /graph.json)", file=sys.stderr) - sys.exit(1) - scan_interval = int(os.environ.get("SCAN_INTERVAL", "30")) - print( - f"graphify multi-graph MCP: {len(registry.names())} graphs from {graphs_dir}", - file=sys.stderr, - ) - for name in registry.names(): - ctx = registry.get(name) - print(f" {name}: {ctx.graph.number_of_nodes()} nodes", file=sys.stderr) - - def _rescan_loop(): - import time - while True: - time.sleep(scan_interval) - try: - registry.rescan() - except Exception as exc: - import logging - logging.getLogger(__name__).warning("rescan failed: %s", exc) - - rescan_thread = threading.Thread(target=_rescan_loop, daemon=True) - rescan_thread.start() - + graph_path = args.graph_flag or args.graph_path or _default_graph_json() + if args.transport == "http": serve_http( - registry=registry, + graph_path, host=args.host, port=args.port, api_key=args.api_key, @@ -2626,20 +2580,7 @@ def _rescan_loop(): session_timeout=args.session_timeout, ) else: - graph_path = args.graph_flag or args.graph_path or _default_graph_json() - if args.transport == "http": - serve_http( - graph_path, - host=args.host, - port=args.port, - api_key=args.api_key, - path=args.path, - json_response=args.json_response, - stateless=args.stateless, - session_timeout=args.session_timeout, - ) - else: - serve(graph_path) + serve(graph_path) if __name__ == "__main__": diff --git a/graphify/skill-agents.md b/graphify/skill-agents.md index 2ff7840c3b..190827d9ac 100644 --- a/graphify/skill-agents.md +++ b/graphify/skill-agents.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -548,7 +547,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-aider.md b/graphify/skill-aider.md index 398012b35f..4996beb787 100644 --- a/graphify/skill-aider.md +++ b/graphify/skill-aider.md @@ -22,7 +22,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --neo4j # generate graphify-out/cypher.txt for Neo4j /graphify --neo4j-push bolt://localhost:7687 # push directly to Neo4j /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify add # fetch URL, save to ./raw, update graph /graphify add --author "Name" # tag who wrote it diff --git a/graphify/skill-amp.md b/graphify/skill-amp.md index 2ff7840c3b..190827d9ac 100644 --- a/graphify/skill-amp.md +++ b/graphify/skill-amp.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -548,7 +547,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-claw.md b/graphify/skill-claw.md index 3e1d9f2fda..abd2811d23 100644 --- a/graphify/skill-claw.md +++ b/graphify/skill-claw.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -551,7 +550,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-codex.md b/graphify/skill-codex.md index fdb69319dc..af3f723c78 100644 --- a/graphify/skill-codex.md +++ b/graphify/skill-codex.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -548,7 +547,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-copilot.md b/graphify/skill-copilot.md index 3e1d9f2fda..abd2811d23 100644 --- a/graphify/skill-copilot.md +++ b/graphify/skill-copilot.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -551,7 +550,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-devin.md b/graphify/skill-devin.md index 214ba319a4..f9be846cbf 100644 --- a/graphify/skill-devin.md +++ b/graphify/skill-devin.md @@ -32,7 +32,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --neo4j # generate graphify-out/cypher.txt for Neo4j /graphify --neo4j-push bolt://localhost:7687 # push directly to Neo4j /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify add # fetch URL, save to ./raw, update graph diff --git a/graphify/skill-droid.md b/graphify/skill-droid.md index f75bdf79b5..fd148d485d 100644 --- a/graphify/skill-droid.md +++ b/graphify/skill-droid.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -548,7 +547,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-kilo.md b/graphify/skill-kilo.md index eb787b76fa..3e70b050a4 100644 --- a/graphify/skill-kilo.md +++ b/graphify/skill-kilo.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -551,7 +550,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-kiro.md b/graphify/skill-kiro.md index 3e1d9f2fda..abd2811d23 100644 --- a/graphify/skill-kiro.md +++ b/graphify/skill-kiro.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -551,7 +550,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-opencode.md b/graphify/skill-opencode.md index 5e2ae50f7d..91ced60675 100644 --- a/graphify/skill-opencode.md +++ b/graphify/skill-opencode.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -543,7 +542,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-pi.md b/graphify/skill-pi.md index 3e1d9f2fda..abd2811d23 100644 --- a/graphify/skill-pi.md +++ b/graphify/skill-pi.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -551,7 +550,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-trae.md b/graphify/skill-trae.md index 79b80cbaff..050667bc20 100644 --- a/graphify/skill-trae.md +++ b/graphify/skill-trae.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -549,7 +548,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-vscode.md b/graphify/skill-vscode.md index 23f05b032f..20c7c0835c 100644 --- a/graphify/skill-vscode.md +++ b/graphify/skill-vscode.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -547,7 +546,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill-windows.md b/graphify/skill-windows.md index 56b9df37d1..d631821ec3 100644 --- a/graphify/skill-windows.md +++ b/graphify/skill-windows.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -573,7 +572,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skill.md b/graphify/skill.md index 3e1d9f2fda..abd2811d23 100644 --- a/graphify/skill.md +++ b/graphify/skill.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -551,7 +550,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/graphify/skills/agents/references/exports.md b/graphify/skills/agents/references/exports.md index 89430e90ef..242ff868e0 100644 --- a/graphify/skills/agents/references/exports.md +++ b/graphify/skills/agents/references/exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/amp/references/exports.md b/graphify/skills/amp/references/exports.md index 89430e90ef..242ff868e0 100644 --- a/graphify/skills/amp/references/exports.md +++ b/graphify/skills/amp/references/exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/claude/references/exports.md b/graphify/skills/claude/references/exports.md index 89430e90ef..242ff868e0 100644 --- a/graphify/skills/claude/references/exports.md +++ b/graphify/skills/claude/references/exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/claw/references/exports.md b/graphify/skills/claw/references/exports.md index 89430e90ef..242ff868e0 100644 --- a/graphify/skills/claw/references/exports.md +++ b/graphify/skills/claw/references/exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/codex/references/exports.md b/graphify/skills/codex/references/exports.md index 89430e90ef..242ff868e0 100644 --- a/graphify/skills/codex/references/exports.md +++ b/graphify/skills/codex/references/exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/copilot/references/exports.md b/graphify/skills/copilot/references/exports.md index 89430e90ef..242ff868e0 100644 --- a/graphify/skills/copilot/references/exports.md +++ b/graphify/skills/copilot/references/exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/droid/references/exports.md b/graphify/skills/droid/references/exports.md index 89430e90ef..242ff868e0 100644 --- a/graphify/skills/droid/references/exports.md +++ b/graphify/skills/droid/references/exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/kilo/references/exports.md b/graphify/skills/kilo/references/exports.md index 89430e90ef..242ff868e0 100644 --- a/graphify/skills/kilo/references/exports.md +++ b/graphify/skills/kilo/references/exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/kiro/references/exports.md b/graphify/skills/kiro/references/exports.md index 89430e90ef..242ff868e0 100644 --- a/graphify/skills/kiro/references/exports.md +++ b/graphify/skills/kiro/references/exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/opencode/references/exports.md b/graphify/skills/opencode/references/exports.md index 89430e90ef..242ff868e0 100644 --- a/graphify/skills/opencode/references/exports.md +++ b/graphify/skills/opencode/references/exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/pi/references/exports.md b/graphify/skills/pi/references/exports.md index 89430e90ef..242ff868e0 100644 --- a/graphify/skills/pi/references/exports.md +++ b/graphify/skills/pi/references/exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/trae/references/exports.md b/graphify/skills/trae/references/exports.md index 89430e90ef..242ff868e0 100644 --- a/graphify/skills/trae/references/exports.md +++ b/graphify/skills/trae/references/exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/vscode/references/exports.md b/graphify/skills/vscode/references/exports.md index 89430e90ef..242ff868e0 100644 --- a/graphify/skills/vscode/references/exports.md +++ b/graphify/skills/vscode/references/exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/graphify/skills/windows/references/exports.md b/graphify/skills/windows/references/exports.md index 89430e90ef..242ff868e0 100644 --- a/graphify/skills/windows/references/exports.md +++ b/graphify/skills/windows/references/exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tests/test_mcp_cli.py b/tests/test_mcp_cli.py new file mode 100644 index 0000000000..83430ae84f --- /dev/null +++ b/tests/test_mcp_cli.py @@ -0,0 +1,194 @@ +from pathlib import Path +import re +import subprocess + +import pytest + +from graphify import __main__ as main_mod + + +def _legacy_multi_graph_terms(): + return ( + "--multi" + "-mcp", + "--graphs" + "-dir", + "GRAPHS" + "_DIR", + "SCAN" + "_INTERVAL", + "graphify" + "-multi", + ) + + +def test_compose_uses_public_mcp_cli(): + compose = Path("docker-compose.multi.yml").read_text(encoding="utf-8") + _, _, graphs_dir, scan_interval, _ = _legacy_multi_graph_terms() + + assert "graphify /repos/frontend /repos/backend --mcp" in compose + assert '"127.0.0.1:8080:8080"' in compose + assert "target: multi" not in compose + assert graphs_dir not in compose + assert scan_interval not in compose + + +def test_dockerfile_has_no_multi_target(): + dockerfile = Path("Dockerfile").read_text(encoding="utf-8") + _, _, graphs_dir, scan_interval, _ = _legacy_multi_graph_terms() + + assert "AS multi" not in dockerfile + assert graphs_dir not in dockerfile + assert scan_interval not in dockerfile + + +def test_readme_documents_public_mcp_docker_cli(): + readme = Path("README.md").read_text(encoding="utf-8") + + assert 'docker run -p 8080:8080 -v "$(pwd):/data:ro" graphify /data --mcp --transport http --host 0.0.0.0 --api-key "$SECRET"' in readme + + +def test_rendered_skills_have_no_legacy_multi_mcp_terms(): + from tools.skillgen.gen import load_platforms, render_all + + rendered = render_all(load_platforms()) + forbidden = _legacy_multi_graph_terms() + + assert all(term not in artifact.content for term in forbidden for artifact in rendered) + + +def test_no_legacy_multi_graph_entrypoint_references(): + legacy_terms = _legacy_multi_graph_terms() + tracked_files = subprocess.run( + ["git", "ls-files"], + capture_output=True, + check=True, + text=True, + ).stdout.splitlines() + active_files = [ + path + for path in tracked_files + if not path.startswith("docs/superpowers/") + and not Path(path).name.upper().startswith("CHANGELOG") + ] + result = subprocess.run( + [ + "git", + "grep", + "-nE", + "|".join(re.escape(term) for term in legacy_terms), + "--", + *active_files, + ], + capture_output=True, + text=True, + ) + + assert result.returncode == 1, result.stdout + + +def _repo(tmp_path: Path, name: str) -> Path: + repo = tmp_path / name + out = repo / "graphify-out" + out.mkdir(parents=True) + (out / "graph.json").write_text('{"nodes": [], "links": []}', encoding="utf-8") + return repo + + +def test_mcp_uses_existing_repository_graphs_without_extracting(tmp_path, monkeypatch): + alpha, beta = _repo(tmp_path, "alpha"), _repo(tmp_path, "beta") + captured = {} + monkeypatch.setattr(main_mod, "_start_mcp_registry", lambda registry: captured.setdefault("names", registry.names())) + + main_mod._serve_mcp_repositories([str(alpha), str(beta)], transport="stdio") + + assert captured["names"] == ["alpha", "beta"] + assert (alpha / "graphify-out" / "graph.json").exists() + assert (beta / "graphify-out" / "graph.json").exists() + + +def test_mcp_rejects_missing_graph_before_starting(tmp_path, monkeypatch, capsys): + monkeypatch.setattr(main_mod, "_start_mcp_registry", pytest.fail) + + with pytest.raises(SystemExit): + main_mod._serve_mcp_repositories([str(tmp_path / "missing")], transport="stdio") + + assert "graphify-out/graph.json" in capsys.readouterr().err + + +def test_mcp_rejects_zero_repository_paths(monkeypatch, capsys): + monkeypatch.setattr(main_mod, "_start_mcp_registry", pytest.fail) + + with pytest.raises(SystemExit): + main_mod._serve_mcp_repositories([], transport="stdio") + + assert "requires at least one repository path" in capsys.readouterr().err + + +def test_mcp_rejects_unreadable_graph_before_starting(tmp_path, monkeypatch, capsys): + repo = _repo(tmp_path, "alpha") + monkeypatch.setattr(main_mod, "_start_mcp_registry", pytest.fail) + from graphify import serve as serve_mod + + monkeypatch.setattr(serve_mod.GraphRegistry, "from_paths", lambda paths: (_ for _ in ()).throw(PermissionError("denied"))) + + with pytest.raises(SystemExit): + main_mod._serve_mcp_repositories([str(repo)], transport="stdio") + + assert "could not read graph" in capsys.readouterr().err + + +def test_mcp_rejects_duplicate_repository_names(tmp_path, monkeypatch, capsys): + first = _repo(tmp_path / "one", "api") + second = _repo(tmp_path / "two", "api") + monkeypatch.setattr(main_mod, "_start_mcp_registry", pytest.fail) + + with pytest.raises(SystemExit): + main_mod._serve_mcp_repositories([str(first), str(second)], transport="stdio") + + assert "duplicate graph name 'api'" in capsys.readouterr().err + + +def test_run_cli_dispatches_multiple_paths_with_mcp(tmp_path, monkeypatch): + alpha, beta = _repo(tmp_path, "alpha"), _repo(tmp_path, "beta") + captured = {} + monkeypatch.setattr( + main_mod, + "_serve_mcp_repositories", + lambda paths, *, transport: captured.update(paths=paths, transport=transport), + ) + monkeypatch.setattr(main_mod.sys, "argv", ["graphify", str(alpha), str(beta), "--mcp"]) + + main_mod._run_cli() + + assert captured == {"paths": [str(alpha), str(beta)], "transport": "stdio"} + + +def test_run_cli_passes_http_settings_to_mcp_server(tmp_path, monkeypatch): + alpha = _repo(tmp_path, "alpha") + captured = {} + monkeypatch.setattr( + main_mod, + "_serve_mcp_repositories", + lambda paths, *, transport, host, port, api_key: captured.update( + paths=paths, transport=transport, host=host, port=port, api_key=api_key + ), + ) + monkeypatch.setattr( + main_mod.sys, + "argv", + ["graphify", str(alpha), "--mcp", "--transport", "http", "--host", "0.0.0.0", "--port", "8080", "--api-key", "secret"], + ) + + main_mod._run_cli() + + assert captured == { + "paths": [str(alpha)], + "transport": "http", + "host": "0.0.0.0", + "port": 8080, + "api_key": "secret", + } + + +@pytest.mark.parametrize("option", ["--host", "--api-key"]) +def test_mcp_rejects_option_as_value(option, capsys): + with pytest.raises(SystemExit): + main_mod._run_mcp_cli(["--mcp", option, "--unknown"]) + + assert "error: unrecognized MCP option: --unknown" in capsys.readouterr().err diff --git a/tests/test_serve.py b/tests/test_serve.py index 6c4eb34283..4bcf0a471b 100644 --- a/tests/test_serve.py +++ b/tests/test_serve.py @@ -1746,61 +1746,17 @@ def test_from_path_single_graph(self, tmp_path): assert ctx is not None assert ctx.graph.number_of_nodes() == 2 - def test_from_directory_discovers_graphs(self, tmp_path): - _write_registry_graph(tmp_path, "frontend") - _write_registry_graph(tmp_path, "backend") - reg = GraphRegistry.from_directory(tmp_path) + def test_from_paths_loads_multiple_graphs(self, tmp_path): + frontend = _write_registry_graph(tmp_path / "frontend", "graphify-out") + backend = _write_registry_graph(tmp_path / "backend", "graphify-out") + reg = GraphRegistry.from_paths([frontend, backend]) assert sorted(reg.names()) == ["backend", "frontend"] - def test_from_directory_skips_corrupt(self, tmp_path): - _write_registry_graph(tmp_path, "good") - bad = tmp_path / "bad" - bad.mkdir() - (bad / "graph.json").write_text("{invalid json", encoding="utf-8") - reg = GraphRegistry.from_directory(tmp_path) - assert reg.names() == ["good"] - - def test_from_directory_skips_no_graph_json(self, tmp_path): - _write_registry_graph(tmp_path, "valid") - (tmp_path / "empty_dir").mkdir() - reg = GraphRegistry.from_directory(tmp_path) - assert reg.names() == ["valid"] - def test_get_unknown_returns_none(self, tmp_path): gp = _write_registry_graph(tmp_path, "proj") reg = GraphRegistry.from_path(gp) assert reg.get("nonexistent") is None - def test_rescan_detects_new_graph(self, tmp_path): - _write_registry_graph(tmp_path, "first") - reg = GraphRegistry.from_directory(tmp_path) - assert reg.names() == ["first"] - _write_registry_graph(tmp_path, "second") - reg.rescan() - assert sorted(reg.names()) == ["first", "second"] - - def test_rescan_evicts_removed_graph(self, tmp_path): - _write_registry_graph(tmp_path, "temp") - reg = GraphRegistry.from_directory(tmp_path) - import shutil - shutil.rmtree(tmp_path / "temp") - reg.rescan() - assert reg.names() == [] - - def test_rescan_reloads_changed_graph(self, tmp_path): - _write_registry_graph(tmp_path, "proj", nodes=[ - {"id": "a", "label": "a", "community": 0}, - ], edges=[]) - reg = GraphRegistry.from_directory(tmp_path) - assert reg.get("proj").graph.number_of_nodes() == 1 - import time; time.sleep(0.05) - _write_registry_graph(tmp_path, "proj", nodes=[ - {"id": "a", "label": "a", "community": 0}, - {"id": "b", "label": "b", "community": 0}, - ], edges=[]) - reg.rescan() - assert reg.get("proj").graph.number_of_nodes() == 2 - def test_from_path_hot_reload(self, tmp_path): gp = _write_registry_graph(tmp_path, "proj", nodes=[ {"id": "a", "label": "a", "community": 0}, @@ -1815,6 +1771,36 @@ def test_from_path_hot_reload(self, tmp_path): reg.rescan() assert reg.get(reg.names()[0]).graph.number_of_nodes() == 2 + def test_from_paths_reloads_graph_only_before_each_request(self, tmp_path, monkeypatch): + graph_path = _write_registry_graph( + tmp_path / "repo", "graphify-out", nodes=[ + {"id": "a", "label": "a", "community": 0}, + ], edges=[], + ) + registry = GraphRegistry.from_paths([graph_path]) + _, handlers = _build_server(registry) + from graphify import reflect + + monkeypatch.setattr( + reflect, + "load_learning_overlay", + lambda path: pytest.fail("explicit registry reload must not load sidecars"), + ) + _write_registry_graph( + tmp_path / "repo", "graphify-out", nodes=[ + {"id": "a", "label": "a", "community": 0}, + {"id": "b", "label": "b", "community": 0}, + ], edges=[], + ) + import os + original_mtime = graph_path.stat().st_mtime + os.utime(graph_path, (original_mtime + 1, original_mtime + 1)) + + assert "Nodes: 2" in handlers["graph_stats"]({}) + + def test_registry_has_no_directory_discovery_api(self): + assert not hasattr(GraphRegistry, "from_" + "directory") + def test_from_path_evicts_deleted(self, tmp_path): gp = _write_registry_graph(tmp_path, "proj") reg = GraphRegistry.from_path(gp) @@ -1824,6 +1810,24 @@ def test_from_path_evicts_deleted(self, tmp_path): reg.rescan() assert reg.names() == [] + def test_from_paths_loads_graph_json_without_learning_overlay(self, tmp_path, monkeypatch): + repo = tmp_path / "repo" + graph_path = repo / "graphify-out" / "graph.json" + graph_path.parent.mkdir(parents=True) + graph_path.write_text('{"nodes": [], "links": []}', encoding="utf-8") + from graphify import reflect + + monkeypatch.setattr( + reflect, + "load_learning_overlay", + lambda path: pytest.fail("explicit registry must not load sidecars"), + ) + + registry = GraphRegistry.from_paths([graph_path]) + + assert registry.names() == ["repo"] + + from graphify.serve import _build_server @@ -1837,9 +1841,9 @@ def test_single_graph_has_no_list_graphs(self, tmp_path): assert "use_graph" not in handlers def test_multi_graph_has_list_graphs(self, tmp_path): - _write_registry_graph(tmp_path, "alpha") - _write_registry_graph(tmp_path, "beta") - reg = GraphRegistry.from_directory(tmp_path) + alpha = _write_registry_graph(tmp_path / "alpha", "graphify-out") + beta = _write_registry_graph(tmp_path / "beta", "graphify-out") + reg = GraphRegistry.from_paths([alpha, beta]) server, handlers = _build_server(reg) assert "list_graphs" in handlers assert "use_graph" in handlers @@ -1851,9 +1855,9 @@ def test_single_graph_has_pr_tools(self, tmp_path): assert "list_prs" in handlers def test_multi_graph_no_pr_tools(self, tmp_path): - _write_registry_graph(tmp_path, "alpha") - _write_registry_graph(tmp_path, "beta") - reg = GraphRegistry.from_directory(tmp_path) + alpha = _write_registry_graph(tmp_path / "alpha", "graphify-out") + beta = _write_registry_graph(tmp_path / "beta", "graphify-out") + reg = GraphRegistry.from_paths([alpha, beta]) server, handlers = _build_server(reg) assert "list_prs" not in handlers @@ -1870,13 +1874,13 @@ def test_single_graph_query(self, tmp_path): assert "AuthService" in result def test_multi_graph_use_graph_and_query(self, tmp_path): - _write_registry_graph(tmp_path, "alpha", nodes=[ + alpha = _write_registry_graph(tmp_path / "alpha", "graphify-out", nodes=[ {"id": "a1", "label": "UserService", "community": 0}, ], edges=[]) - _write_registry_graph(tmp_path, "beta", nodes=[ + beta = _write_registry_graph(tmp_path / "beta", "graphify-out", nodes=[ {"id": "b1", "label": "PaymentGateway", "community": 0}, ], edges=[]) - reg = GraphRegistry.from_directory(tmp_path) + reg = GraphRegistry.from_paths([alpha, beta]) session = {} _, handlers = _build_server(reg, session_state=session) @@ -1894,9 +1898,9 @@ def test_multi_graph_use_graph_and_query(self, tmp_path): assert "Nodes: 1" in result def test_all_tools_have_graph_param(self, tmp_path): - _write_registry_graph(tmp_path, "alpha") - _write_registry_graph(tmp_path, "beta") - reg = GraphRegistry.from_directory(tmp_path) + alpha = _write_registry_graph(tmp_path / "alpha", "graphify-out") + beta = _write_registry_graph(tmp_path / "beta", "graphify-out") + reg = GraphRegistry.from_paths([alpha, beta]) server, _ = _build_server(reg) from mcp import types as _t import asyncio @@ -1910,18 +1914,31 @@ def test_all_tools_have_graph_param(self, tmp_path): props = t.inputSchema.get("properties", {}) assert "graph" in props, f"tool {t.name} missing graph param" + def test_explicit_registry_rejects_project_path(self, tmp_path): + explicit_graph = tmp_path / "repo" / "graphify-out" / "graph.json" + explicit_graph.parent.mkdir(parents=True) + explicit_graph.write_text('{"nodes": [], "links": []}', encoding="utf-8") + other_project = tmp_path / "other" + (other_project / "graphify-out").mkdir(parents=True) + (other_project / "graphify-out" / "graph.json").write_text('{"nodes": [], "links": []}', encoding="utf-8") + registry = GraphRegistry.from_paths([explicit_graph]) + _, handlers = _build_server(registry) + + with pytest.raises(ValueError, match="project_path is not supported"): + handlers["graph_stats"]({"project_path": str(other_project)}) + class TestResolveGraph: def test_explicit_param(self, tmp_path): - _write_registry_graph(tmp_path, "alpha") - _write_registry_graph(tmp_path, "beta") - reg = GraphRegistry.from_directory(tmp_path) + alpha = _write_registry_graph(tmp_path / "alpha", "graphify-out") + beta = _write_registry_graph(tmp_path / "beta", "graphify-out") + reg = GraphRegistry.from_paths([alpha, beta]) ctx = _resolve_graph(reg, graph="alpha", current=None) assert ctx.name == "alpha" def test_session_default(self, tmp_path): - _write_registry_graph(tmp_path, "proj") - reg = GraphRegistry.from_directory(tmp_path) + graph_path = _write_registry_graph(tmp_path / "proj", "graphify-out") + reg = GraphRegistry.from_paths([graph_path]) ctx = _resolve_graph(reg, graph=None, current="proj") assert ctx.name == "proj" @@ -1932,59 +1949,41 @@ def test_single_graph_implicit(self, tmp_path): assert ctx is not None def test_ambiguous_raises(self, tmp_path): - _write_registry_graph(tmp_path, "a") - _write_registry_graph(tmp_path, "b") - reg = GraphRegistry.from_directory(tmp_path) + first = _write_registry_graph(tmp_path / "a", "graphify-out") + second = _write_registry_graph(tmp_path / "b", "graphify-out") + reg = GraphRegistry.from_paths([first, second]) with pytest.raises(ValueError, match="multiple graphs"): _resolve_graph(reg, graph=None, current=None) def test_unknown_name_raises(self, tmp_path): - _write_registry_graph(tmp_path, "x") - reg = GraphRegistry.from_directory(tmp_path) + graph_path = _write_registry_graph(tmp_path / "x", "graphify-out") + reg = GraphRegistry.from_paths([graph_path]) with pytest.raises(ValueError, match="not found"): _resolve_graph(reg, graph="nope", current=None) - def test_empty_registry_raises(self, tmp_path): - reg = GraphRegistry.from_directory(tmp_path) - with pytest.raises(ValueError, match="no graphs loaded"): - _resolve_graph(reg, graph=None, current=None) - - -# --- CLI --graphs-dir tests --- - -from graphify.serve import _main - - class TestMainCLI: - def test_graphs_dir_forces_http(self, tmp_path, capsys): - _write_registry_graph(tmp_path, "proj") - with pytest.raises(SystemExit): - _main(["--graphs-dir", str(tmp_path), "--transport", "stdio"]) - captured = capsys.readouterr() - assert "stdio" in captured.err.lower() or "http" in captured.err.lower() + def test_serve_cli_rejects_removed_graphs_dir(self, tmp_path, capsys): + from graphify.serve import _main + removed_option = "--graphs" + "-dir" - def test_graphs_dir_empty_exits(self, tmp_path): with pytest.raises(SystemExit): - _main(["--graphs-dir", str(tmp_path)]) - - def test_graphs_dir_missing_exits(self, tmp_path): - with pytest.raises(SystemExit): - _main(["--graphs-dir", str(tmp_path / "nonexistent")]) + _main([removed_option, str(tmp_path)]) + assert f"unrecognized arguments: {removed_option}" in capsys.readouterr().err class TestUnifiedIntegration: def test_multi_graph_full_flow(self, tmp_path): - _write_registry_graph(tmp_path, "alpha", nodes=[ + alpha = _write_registry_graph(tmp_path / "alpha", "graphify-out", nodes=[ {"id": "a1", "label": "UserService", "community": 0, "source_file": "user.py", "source_location": "L1", "file_type": "python"}, {"id": "a2", "label": "AuthService", "community": 0, "source_file": "auth.py", "source_location": "L1", "file_type": "python"}, ], edges=[ {"source": "a1", "target": "a2", "relation": "calls", "confidence": "EXTRACTED"}, ]) - _write_registry_graph(tmp_path, "beta", nodes=[ + beta = _write_registry_graph(tmp_path / "beta", "graphify-out", nodes=[ {"id": "b1", "label": "PaymentGateway", "community": 0, "source_file": "pay.py", "source_location": "L1", "file_type": "python"}, ], edges=[]) - reg = GraphRegistry.from_directory(tmp_path) + reg = GraphRegistry.from_paths([alpha, beta]) session = {} _, handlers = _build_server(reg, session_state=session) @@ -2003,13 +2002,6 @@ def test_multi_graph_full_flow(self, tmp_path): assert "list_prs" not in handlers - _write_registry_graph(tmp_path, "gamma", nodes=[ - {"id": "g1", "label": "Logger", "community": 0}, - ], edges=[]) - reg.rescan() - listing = handlers["list_graphs"]({}) - assert "gamma" in listing - def test_single_graph_retro_compat(self, tmp_path): _write_registry_graph(tmp_path, "proj", nodes=[ {"id": "n1", "label": "Main", "community": 0, "source_file": "main.py"}, diff --git a/tests/test_serve_http.py b/tests/test_serve_http.py index f450ca9a4d..391733ca9c 100644 --- a/tests/test_serve_http.py +++ b/tests/test_serve_http.py @@ -52,6 +52,17 @@ def _graph_file(tmp_path: Path) -> str: return str(p) +def _repository_graph(tmp_path: Path, name: str, node_count: int) -> Path: + graph_path = tmp_path / name / "graphify-out" / "graph.json" + graph_path.parent.mkdir(parents=True) + graph_path.write_text(json.dumps({ + "directed": True, + "nodes": [{"id": f"{name}-{index}", "label": name, "community": 0} for index in range(node_count)], + "edges": [], + }), encoding="utf-8") + return graph_path + + def _client(app) -> TestClient: # Default host is 127.0.0.1, so the DNS-rebinding guard only accepts that # Host header (TestClient otherwise sends the disallowed "testserver"). @@ -219,20 +230,9 @@ def test_graph_param_is_optional_on_every_tool(tmp_path): def test_graph_param_routes_to_that_graph(tmp_path): """A multi-graph server answers the default graph when graph param is omitted and a specific graph when graph param is provided.""" - # Write two graph directories - alpha_dir = tmp_path / "alpha" - alpha_dir.mkdir() - beta_dir = tmp_path / "beta" - beta_dir.mkdir() - alpha_graph = {"directed": True, "nodes": [{"id": "a", "label": "A", "community": 0}], "edges": []} - beta_graph = {"directed": True, "nodes": [ - {"id": "b1", "label": "B1", "community": 0}, - {"id": "b2", "label": "B2", "community": 0}, - {"id": "b3", "label": "B3", "community": 0}, - ], "edges": []} - (alpha_dir / "graph.json").write_text(json.dumps(alpha_graph), encoding="utf-8") - (beta_dir / "graph.json").write_text(json.dumps(beta_graph), encoding="utf-8") - registry = serve_mod.GraphRegistry.from_directory(tmp_path) + alpha = _repository_graph(tmp_path, "alpha", 1) + beta = _repository_graph(tmp_path, "beta", 3) + registry = serve_mod.GraphRegistry.from_paths([alpha, beta]) app = serve_mod._build_http_app(registry=registry, json_response=True) with _client(app) as client: headers = _init_session(client) @@ -240,6 +240,22 @@ def test_graph_param_routes_to_that_graph(tmp_path): assert "Nodes: 3" in _call_tool(client, headers, "graph_stats", {"graph": "beta"}, rid=3) +def test_use_graph_selection_is_isolated_per_http_session(tmp_path): + alpha = _repository_graph(tmp_path, "alpha", 1) + beta = _repository_graph(tmp_path, "beta", 3) + app = serve_mod._build_http_app( + registry=serve_mod.GraphRegistry.from_paths([alpha, beta]), json_response=True + ) + with _client(app) as client: + first = _init_session(client) + second = _init_session(client) + + assert "Switched to graph 'alpha'" in _call_tool(client, first, "use_graph", {"graph": "alpha"}, rid=2) + assert "Switched to graph 'beta'" in _call_tool(client, second, "use_graph", {"graph": "beta"}, rid=3) + assert "Nodes: 1" in _call_tool(client, first, "graph_stats", {}, rid=4) + assert "Nodes: 3" in _call_tool(client, second, "graph_stats", {}, rid=5) + + @pytest.mark.parametrize( ("value", "expected"), [(None, 8), ("", 8), ("bad", 8), ("0", 1), ("-4", 1), ("3", 3)], diff --git a/tools/skillgen/expected/graphify__skill-agents.md b/tools/skillgen/expected/graphify__skill-agents.md index 2ff7840c3b..190827d9ac 100644 --- a/tools/skillgen/expected/graphify__skill-agents.md +++ b/tools/skillgen/expected/graphify__skill-agents.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -548,7 +547,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-aider.md b/tools/skillgen/expected/graphify__skill-aider.md index 398012b35f..4996beb787 100644 --- a/tools/skillgen/expected/graphify__skill-aider.md +++ b/tools/skillgen/expected/graphify__skill-aider.md @@ -22,7 +22,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --neo4j # generate graphify-out/cypher.txt for Neo4j /graphify --neo4j-push bolt://localhost:7687 # push directly to Neo4j /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify add # fetch URL, save to ./raw, update graph /graphify add --author "Name" # tag who wrote it diff --git a/tools/skillgen/expected/graphify__skill-amp.md b/tools/skillgen/expected/graphify__skill-amp.md index 2ff7840c3b..190827d9ac 100644 --- a/tools/skillgen/expected/graphify__skill-amp.md +++ b/tools/skillgen/expected/graphify__skill-amp.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -548,7 +547,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-claw.md b/tools/skillgen/expected/graphify__skill-claw.md index 3e1d9f2fda..abd2811d23 100644 --- a/tools/skillgen/expected/graphify__skill-claw.md +++ b/tools/skillgen/expected/graphify__skill-claw.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -551,7 +550,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-codex.md b/tools/skillgen/expected/graphify__skill-codex.md index fdb69319dc..af3f723c78 100644 --- a/tools/skillgen/expected/graphify__skill-codex.md +++ b/tools/skillgen/expected/graphify__skill-codex.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -548,7 +547,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-copilot.md b/tools/skillgen/expected/graphify__skill-copilot.md index 3e1d9f2fda..abd2811d23 100644 --- a/tools/skillgen/expected/graphify__skill-copilot.md +++ b/tools/skillgen/expected/graphify__skill-copilot.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -551,7 +550,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-devin.md b/tools/skillgen/expected/graphify__skill-devin.md index 214ba319a4..f9be846cbf 100644 --- a/tools/skillgen/expected/graphify__skill-devin.md +++ b/tools/skillgen/expected/graphify__skill-devin.md @@ -32,7 +32,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --neo4j # generate graphify-out/cypher.txt for Neo4j /graphify --neo4j-push bolt://localhost:7687 # push directly to Neo4j /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify add # fetch URL, save to ./raw, update graph diff --git a/tools/skillgen/expected/graphify__skill-droid.md b/tools/skillgen/expected/graphify__skill-droid.md index f75bdf79b5..fd148d485d 100644 --- a/tools/skillgen/expected/graphify__skill-droid.md +++ b/tools/skillgen/expected/graphify__skill-droid.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -548,7 +547,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-kilo.md b/tools/skillgen/expected/graphify__skill-kilo.md index eb787b76fa..3e70b050a4 100644 --- a/tools/skillgen/expected/graphify__skill-kilo.md +++ b/tools/skillgen/expected/graphify__skill-kilo.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -551,7 +550,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-kiro.md b/tools/skillgen/expected/graphify__skill-kiro.md index 3e1d9f2fda..abd2811d23 100644 --- a/tools/skillgen/expected/graphify__skill-kiro.md +++ b/tools/skillgen/expected/graphify__skill-kiro.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -551,7 +550,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-opencode.md b/tools/skillgen/expected/graphify__skill-opencode.md index 5e2ae50f7d..91ced60675 100644 --- a/tools/skillgen/expected/graphify__skill-opencode.md +++ b/tools/skillgen/expected/graphify__skill-opencode.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -543,7 +542,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-pi.md b/tools/skillgen/expected/graphify__skill-pi.md index 3e1d9f2fda..abd2811d23 100644 --- a/tools/skillgen/expected/graphify__skill-pi.md +++ b/tools/skillgen/expected/graphify__skill-pi.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -551,7 +550,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-trae.md b/tools/skillgen/expected/graphify__skill-trae.md index 79b80cbaff..050667bc20 100644 --- a/tools/skillgen/expected/graphify__skill-trae.md +++ b/tools/skillgen/expected/graphify__skill-trae.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -549,7 +548,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-vscode.md b/tools/skillgen/expected/graphify__skill-vscode.md index 23f05b032f..20c7c0835c 100644 --- a/tools/skillgen/expected/graphify__skill-vscode.md +++ b/tools/skillgen/expected/graphify__skill-vscode.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -547,7 +546,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill-windows.md b/tools/skillgen/expected/graphify__skill-windows.md index 56b9df37d1..d631821ec3 100644 --- a/tools/skillgen/expected/graphify__skill-windows.md +++ b/tools/skillgen/expected/graphify__skill-windows.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -573,7 +572,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skill.md b/tools/skillgen/expected/graphify__skill.md index 3e1d9f2fda..abd2811d23 100644 --- a/tools/skillgen/expected/graphify__skill.md +++ b/tools/skillgen/expected/graphify__skill.md @@ -29,7 +29,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -551,7 +550,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/expected/graphify__skills__agents__references__exports.md b/tools/skillgen/expected/graphify__skills__agents__references__exports.md index 89430e90ef..242ff868e0 100644 --- a/tools/skillgen/expected/graphify__skills__agents__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__agents__references__exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__amp__references__exports.md b/tools/skillgen/expected/graphify__skills__amp__references__exports.md index 89430e90ef..242ff868e0 100644 --- a/tools/skillgen/expected/graphify__skills__amp__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__amp__references__exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__claude__references__exports.md b/tools/skillgen/expected/graphify__skills__claude__references__exports.md index 89430e90ef..242ff868e0 100644 --- a/tools/skillgen/expected/graphify__skills__claude__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__claude__references__exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__claw__references__exports.md b/tools/skillgen/expected/graphify__skills__claw__references__exports.md index 89430e90ef..242ff868e0 100644 --- a/tools/skillgen/expected/graphify__skills__claw__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__claw__references__exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__codex__references__exports.md b/tools/skillgen/expected/graphify__skills__codex__references__exports.md index 89430e90ef..242ff868e0 100644 --- a/tools/skillgen/expected/graphify__skills__codex__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__codex__references__exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__copilot__references__exports.md b/tools/skillgen/expected/graphify__skills__copilot__references__exports.md index 89430e90ef..242ff868e0 100644 --- a/tools/skillgen/expected/graphify__skills__copilot__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__copilot__references__exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__droid__references__exports.md b/tools/skillgen/expected/graphify__skills__droid__references__exports.md index 89430e90ef..242ff868e0 100644 --- a/tools/skillgen/expected/graphify__skills__droid__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__droid__references__exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__kilo__references__exports.md b/tools/skillgen/expected/graphify__skills__kilo__references__exports.md index 89430e90ef..242ff868e0 100644 --- a/tools/skillgen/expected/graphify__skills__kilo__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__kilo__references__exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__kiro__references__exports.md b/tools/skillgen/expected/graphify__skills__kiro__references__exports.md index 89430e90ef..242ff868e0 100644 --- a/tools/skillgen/expected/graphify__skills__kiro__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__kiro__references__exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__opencode__references__exports.md b/tools/skillgen/expected/graphify__skills__opencode__references__exports.md index 89430e90ef..242ff868e0 100644 --- a/tools/skillgen/expected/graphify__skills__opencode__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__opencode__references__exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__pi__references__exports.md b/tools/skillgen/expected/graphify__skills__pi__references__exports.md index 89430e90ef..242ff868e0 100644 --- a/tools/skillgen/expected/graphify__skills__pi__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__pi__references__exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__trae__references__exports.md b/tools/skillgen/expected/graphify__skills__trae__references__exports.md index 89430e90ef..242ff868e0 100644 --- a/tools/skillgen/expected/graphify__skills__trae__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__trae__references__exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__vscode__references__exports.md b/tools/skillgen/expected/graphify__skills__vscode__references__exports.md index 89430e90ef..242ff868e0 100644 --- a/tools/skillgen/expected/graphify__skills__vscode__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__vscode__references__exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/expected/graphify__skills__windows__references__exports.md b/tools/skillgen/expected/graphify__skills__windows__references__exports.md index 89430e90ef..242ff868e0 100644 --- a/tools/skillgen/expected/graphify__skills__windows__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__windows__references__exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/fragments/core/aider.md b/tools/skillgen/fragments/core/aider.md index 398012b35f..4996beb787 100644 --- a/tools/skillgen/fragments/core/aider.md +++ b/tools/skillgen/fragments/core/aider.md @@ -22,7 +22,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --neo4j # generate graphify-out/cypher.txt for Neo4j /graphify --neo4j-push bolt://localhost:7687 # push directly to Neo4j /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify add # fetch URL, save to ./raw, update graph /graphify add --author "Name" # tag who wrote it diff --git a/tools/skillgen/fragments/core/core.md b/tools/skillgen/fragments/core/core.md index 8b89bf4903..c527a12563 100644 --- a/tools/skillgen/fragments/core/core.md +++ b/tools/skillgen/fragments/core/core.md @@ -26,7 +26,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --falkordb # generate graphify-out/cypher.txt for FalkorDB /graphify --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault) @@ -486,7 +485,7 @@ graphify export html # auto-aggregates to community view if graph > 5000 nodes ### Steps 6b-8 - Wiki, Neo4j, FalkorDB, SVG, GraphML, MCP, benchmark (only on their flags) -These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`, `--multi-mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. +These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, `--falkordb`/`--falkordb-push`, `--svg`, `--graphml`, `--mcp`) or, for the token-reduction benchmark, when `total_words` exceeds 5,000. A default run with no export flags skips all of them. See `references/exports.md` for each one. Run any `--wiki` export before Step 9 cleanup so `.graphify_labels.json` is still available. --- diff --git a/tools/skillgen/fragments/core/devin.md b/tools/skillgen/fragments/core/devin.md index 214ba319a4..f9be846cbf 100644 --- a/tools/skillgen/fragments/core/devin.md +++ b/tools/skillgen/fragments/core/devin.md @@ -32,7 +32,6 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --neo4j # generate graphify-out/cypher.txt for Neo4j /graphify --neo4j-push bolt://localhost:7687 # push directly to Neo4j /graphify --mcp # start MCP stdio server for agent access -/graphify --multi-mcp # start multi-graph MCP Docker server /graphify --watch # watch folder, auto-rebuild on code changes (no LLM needed) /graphify --wiki # build agent-crawlable wiki (index.md + one article per community) /graphify add # fetch URL, save to ./raw, update graph diff --git a/tools/skillgen/fragments/references/shared/exports.md b/tools/skillgen/fragments/references/shared/exports.md index 89430e90ef..242ff868e0 100644 --- a/tools/skillgen/fragments/references/shared/exports.md +++ b/tools/skillgen/fragments/references/shared/exports.md @@ -76,20 +76,6 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desk } ``` -### Step 7e - Multi-graph MCP server (only if --multi-mcp flag) - -For serving multiple graphs from one endpoint: - -```bash -# structure: my-graphs//graph.json -docker build --target multi -t graphify-multi . -docker run -p 8080:8080 -v "$(pwd)/my-graphs:/graphs:ro" graphify-multi -``` - -This starts an HTTP/SSE MCP server that auto-discovers all `/graph.json` in the mounted `/graphs` volume. Tools: `list_graphs`, `use_graph`, plus all single-graph tools (`query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`) — each with an optional `graph` parameter. - -Set `GRAPHS_DIR`, `SCAN_INTERVAL`, `PORT`, `GRAPHIFY_API_KEY` env vars to configure. - ### Step 8 - Token reduction benchmark (only if total_words > 5000) If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: diff --git a/tools/skillgen/gen.py b/tools/skillgen/gen.py index 09e19ede00..6437a9d7d6 100644 --- a/tools/skillgen/gen.py +++ b/tools/skillgen/gen.py @@ -1181,7 +1181,7 @@ def monolith_roundtrip(platform: Platform) -> list[str]: unification, the unified frontmatter description, the chunk-cleanup rewrite (#1172), the four #1392 runbook fixes (directed propagation, content-only semantic scope, stale-cache unlink, and the zero-node/shrink-guard ordering), - and semantic-cache source scoping (#1757). + semantic-cache source scoping (#1757). The comparison is a multiset diff, not a positional zip: a line whose text is unchanged but merely *moved* (the report-write line shifted below ``to_json``