Skip to main content
Glama
README.md
# mdgraph

Scan a repo's markdown into a graph, **visualize** it in the browser, and **expose** it to Claude (or any MCP host) as a navigation index.

One data model — `{ nodes, edges }` — with three consumer(s):

```
              scan  (the only hard part)
                 │  emits { nodes, edges }
      ┌──────────┼───────────┐
      ▼          ▼           ▼
   graph.json  browser     MCP server
   (a file)   (viewer)   (agents read it)
```

Insights, reachability, and orphans are all **derived** from the model at read time. Nodes and edges stay dumb.

## The model

```jsonc
node = { id, label, path, type, cluster, content }   // type: root | ai | doc
edge = { source, target, sourceLine, context }        // context = the line the link lives on
```

`type` is assigned by filename convention (`README.md` → root, `CLAUDE.md`/`AGENTS.md`/`*.mdc` → ai, else doc). Edges come from **actual links in the text** — standard `[x](./y.md)` and `[[wikilinks]]` — not folder membership, so a file in `docs/` that links across the tree still connects across the tree. Folders only drive `cluster` (coloring/grouping).

## Install & run

No install needed — run it straight with npx:

```bash
npx @emmd474/mdgraph scan .            # print the graph as JSON
npx @emmd474/mdgraph view .            # open the interactive graph in a browser
npx @emmd474/mdgraph scan . --out graph.json
```

Or install globally to get a plain `mdgraph` command:

```bash
npm install -g @emmd474/mdgraph
mdgraph view ./my-repo
mdgraph scan ./my-repo --out graph.json
```

`dir` defaults to the current directory. `view` takes `--port` (default 4173).

## Commands

| Command | What it does |
|---|---|
| `mdgraph scan [dir]` | Build the graph, print JSON to stdout (or write with `--out`). |
| `mdgraph view [dir]` | Serve the interactive graph at `localhost:4173`; re-scans on refresh. |
| `mdgraph mcp [dir]` | Run the MCP server over stdio, for Claude and other agents. |

## Expose to Claude (MCP)

**Claude Desktop** — add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "mdgraph": {
      "command": "npx",
      "args": ["-y", "@emmd474/mdgraph", "mcp", "/abs/path/to/your/repo"]
    }
  }
}
```

**Claude Code:**

```bash
claude mcp add mdgraph -- npx -y @emmd474/mdgraph mcp /abs/path/to/your/repo
```

Restart the host and Claude gets four tools:

| Tool | Purpose |
|---|---|
| `get_project_map` | Content-free overview: types, clusters, link counts, orphan/reachable flags, edges. The cheap way to orient. |
| `read_doc` | Raw markdown of one doc by path. |
| `get_context` | Everything reachable from an entry doc, in read order — the exact set to load to understand it. `includeContent: true` bundles the markdown. |
| `find_orphans` | Docs nothing links to. |

The point: an agent calls `get_project_map` to orient, then `get_context("README.md")` to pull **only** the docs the task needs — instead of dumping every `.md` into context.

## Publishing (for maintainers)

The name `mdgraph` is taken on npm, so this publishes **scoped** under your account:

```bash
# 1. set the scope to YOUR npm username (edit "name" in package.json if not @emmd474)
npm whoami          # confirm you're logged in; else: npm login
npm publish --access public
```

Scoped packages are private by default, so `--access public` is required the first time. To ship an update, bump the version and publish again:

```bash
npm version patch   # 0.1.0 -> 0.1.1, also creates a git tag
npm publish
```

`npm pack --dry-run` shows exactly what ships (currently 7 files, ~16 kB — no node_modules, no test repo, thanks to the `files` allowlist).

## Try it on the example

```bash
git clone <this repo> && cd mdgraph && npm install
node cli.mjs view testrepo
node cli.mjs scan testrepo
```

## What's real vs. next

Tested and working: the scanner (md + wikilink extraction, code-fence skipping, convention typing, orphan detection), the browser viewer, and all four MCP tools over a live stdio handshake.

Next, roughly in order:
- **Harden link parsing** — the scanner is line-based and skips fenced blocks, but an inline code span (`` `[x](y)` ``) can still yield a false link. Swap in a real markdown AST (`remark` + `unist-util-visit`) when you want precision; the emitted shape stays identical.
- **Manual edges** — let the viewer write `related:` into a file's frontmatter, read as a third edge source.
- **Frontmatter tags** as a cluster source alongside folders.
- **`--watch`** on `view` to push graph updates over server-sent events.

MIT licensed.