Skip to content

Commit 9a318cf

Browse files
committed
feat(mcp): open local HTML reports
1 parent 59f5fff commit 9a318cf

11 files changed

Lines changed: 446 additions & 100 deletions

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,40 @@
1919

2020
RepoLens is a **Manifest V3 Chrome extension**. Open a GitHub, GitLab, npm, or PyPI page and click the toolbar icon. RepoLens reads the repo, runs it past the AI provider you picked, and opens a tab that leads with a straight answer: should you use this? You see the verdict before any of the README's pitch.
2121

22+
It also ships a **local MCP server** so your coding agent can scan repos before it installs or recommends a dependency. The agent gets structured JSON, and RepoLens opens a local HTML report in your browser so you still get the full visual verdict — not just a text blob.
23+
2224
> Stars tell you a project is popular. They don't tell you whether it fits your problem. RepoLens answers the question you have: should I use this, and what am I signing up for?
2325
2426
---
2527

28+
## Use RepoLens from your AI agent
29+
30+
Run the local MCP server, then ask Claude/Cursor/Pi/etc. to use RepoLens before adding a dependency:
31+
32+
```bash
33+
cd mcp
34+
npm install
35+
ANTHROPIC_API_KEY=sk-ant-... node server.js
36+
```
37+
38+
Example prompts:
39+
40+
> Use RepoLens to check whether I should use `honojs/hono` for an edge API.
41+
>
42+
> Before installing this package, run a RepoLens scan and open the report.
43+
>
44+
> Generate a RepoLens deep dive for `github.com/fastify/fastify`.
45+
46+
MCP tools:
47+
48+
- `scan_repo` — fast verdict-first dependency report.
49+
- `deep_dive` — plain-English architecture explanation with gaps/assumptions.
50+
- `blueprint_scene` — graph-shaped architecture map.
51+
52+
Each tool writes a self-contained local `.html` report and opens it by default. See [`mcp/README.md`](mcp/README.md) for Claude Desktop config and environment options.
53+
54+
---
55+
2656
## What you get
2757

2858
A scan opens to a **verdict landing** and fans out into focused tabs:

mcp/README.md

Lines changed: 70 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,50 @@
11
# RepoLens MCP server
22

3-
A local [MCP](https://modelcontextprotocol.io) server that exposes RepoLens's repo
4-
analysis as tools. An LLM client (Claude Desktop, Cursor, etc.) calls a tool and
5-
gets RepoLens's JSON back — ready to render as components.
3+
Let your AI agent audit dependencies before it installs or recommends them.
64

7-
GitHub-only, Anthropic-only, **three tools** (`scan_repo`, `blueprint_scene`,
8-
`deep_dive`). Each reuses the extension's own pipeline modules verbatim
9-
(`fetcher.js`, `prompt.js`, `parser.js`, `deepdive.js`, `blueprint-adapter.js`);
10-
only the provider call (`anthropic.js`) is MCP-specific.
5+
RepoLens MCP runs locally over stdio. Your agent gets structured JSON, and the MCP
6+
server also writes a self-contained **local HTML report** and opens it in your
7+
browser by default — so users get the full RepoLens visual verdict, not just a
8+
block of text in chat.
119

12-
## What stays true
10+
## Why agents need this
1311

14-
- **Local only.** Runs over stdio, spawned by your client. No hosted backend.
15-
- **Bring your own key.** The Anthropic key comes from the environment, never from
16-
a server or the extension's storage. Nothing phones home.
12+
Coding agents constantly choose packages from README text, stars, or stale blog
13+
posts. RepoLens gives the agent a dependency due-diligence tool:
1714

18-
## Tools
19-
20-
### `scan_repo({ repo })`
21-
22-
`repo` is `owner/name` or a GitHub URL. Returns the analysis JSON:
23-
24-
```json
25-
{
26-
"repoId": "honojs/hono",
27-
"platform": "github",
28-
"language": "TypeScript",
29-
"license": "MIT",
30-
"stars": 21000,
31-
"description": "Small, fast web framework for the edges.",
32-
"fit": { "level": "strong", "label": "Strong fit", "why": "Health 92 · 0 flags · 4 pros / 1 cons" },
33-
"bottom_line": "A lean, fast framework worth adopting for edge runtimes.",
34-
"health": { "score": 92 },
35-
"pros": ["..."],
36-
"cons": ["..."],
37-
"red_flags": [],
38-
"capabilities": ["routing", "middleware", "edge"]
39-
}
40-
```
15+
> “Should I use this repo, what are the risks, and what should I try first?”
4116
42-
`fit` is derived deterministically from the health score, red-flag count, and
43-
pros/cons balance — `level` is one of `strong | solid | care | risky`.
17+
## Tools
4418

45-
### `blueprint_scene({ repo })`
19+
- `scan_repo` — verdict-first report: fit, health, pros, cons, red flags,
20+
capabilities, bottom line.
21+
- `deep_dive` — plain-English architecture explanation, weak spots, assumptions,
22+
self-test questions, atoms + lineage.
23+
- `blueprint_scene` — graph-shaped architecture map with nodes/edges/positions.
4624

47-
Maps how the repo is built and returns a laid-out scene — `nodes` (key parts) and
48-
`edges` (how they relate), with positions — ready for a `<DependencyGraph>`-style
49-
component. Heavier than `scan_repo`: it reads source and makes two model calls
50-
(atoms, then lineage). Edges are engine-shaped (`{ id, from, to, rel }`), not
51-
`{ source, target }`.
25+
Every tool accepts:
5226

5327
```json
5428
{
55-
"id": "repo:...",
56-
"scope": "blueprint",
57-
"repoId": "honojs/hono",
58-
"nodes": [
59-
{
60-
"id": "app",
61-
"label": "Hono app",
62-
"kind": "entrypoint",
63-
"x": 120,
64-
"y": 40,
65-
"layer": "entrypoint",
66-
"ref": { "root": true, "purpose": "...", "files": ["src/hono.ts"] }
67-
}
68-
],
69-
"edges": [{ "id": "e123", "from": "app", "to": "router", "rel": "depends-on" }],
70-
"camera": { "x": 0, "y": 0, "zoom": 1 }
29+
"repo": "honojs/hono",
30+
"report": true,
31+
"openReport": true
7132
}
7233
```
7334

74-
### `deep_dive({ repo })`
35+
- `report` defaults to `true` and writes a local `.html` file.
36+
- `openReport` defaults to `true` and opens that file in the browser.
37+
- Set `openReport: false` if the agent should only return the report path.
38+
- Set `report: false` for pure JSON/tool-only usage.
7539

76-
Explains how the repo actually works in plain language, with the weak spots named.
77-
Returns a from-scratch `explanation`, the `gaps` and `assumptions` behind it,
78-
self-test `questions`, per-claim `confidence`, plus the underlying `atoms` and
79-
`lineage`. **Heaviest tool** — reads source and makes three model calls
80-
(atoms → lineage → Feynman).
40+
The returned JSON includes:
8141

8242
```json
8343
{
84-
"repoId": "honojs/hono",
85-
"degraded": false,
86-
"explanation": "Hono is a small web framework that ...",
87-
"gaps": ["..."],
88-
"assumptions": ["..."],
89-
"questions": [{ "q": "What runs a request?", "a": "..." }],
90-
"confidence": [{ "claim": "...", "level": "high", "note": "..." }],
91-
"atoms": [{ "id": "router", "name": "Router", "kind": "subsystem", "purpose": "..." }],
92-
"lineage": {
93-
"links": [{ "from": "app", "to": "router", "relation": "depends-on" }],
94-
"roots": ["app"],
95-
"leaves": []
44+
"report": {
45+
"path": "/tmp/repolens-mcp-reports/honojs-hono-scan_repo-....html",
46+
"url": "file:///tmp/repolens-mcp-reports/honojs-hono-scan_repo-....html",
47+
"opened": true
9648
}
9749
}
9850
```
@@ -109,31 +61,60 @@ export GITHUB_TOKEN=ghp_... # optional; lifts GitHub 60/hr → 500
10961
node server.js # speaks MCP over stdio
11062
```
11163

112-
A `GITHUB_TOKEN` is **strongly recommended** for `blueprint_scene` and `deep_dive`:
113-
each makes 10+ GitHub calls per run and will hit the 60 req/hr anonymous limit
114-
(surfacing as a mid-scan `GitHub 403`) without one.
64+
Optional report environment variables:
65+
66+
```bash
67+
export REPOLENS_MCP_OPEN_REPORT=0 # never auto-open reports
68+
export REPOLENS_MCP_REPORT_DIR=/tmp/reports # custom report directory
69+
```
70+
71+
A `GITHUB_TOKEN` is strongly recommended for `blueprint_scene` and `deep_dive`:
72+
each makes multiple GitHub calls and anonymous GitHub API limits are low.
11573

116-
### Add to Claude Desktop
74+
## Claude Desktop config
11775

118-
In `claude_desktop_config.json`:
76+
Add this to `claude_desktop_config.json`:
11977

12078
```json
12179
{
12280
"mcpServers": {
12381
"repolens": {
12482
"command": "node",
12583
"args": ["/absolute/path/to/repolens/mcp/server.js"],
126-
"env": { "ANTHROPIC_API_KEY": "sk-ant-...", "GITHUB_TOKEN": "ghp_..." }
84+
"env": {
85+
"ANTHROPIC_API_KEY": "sk-ant-...",
86+
"GITHUB_TOKEN": "ghp_..."
87+
}
12788
}
12889
}
12990
}
13091
```
13192

132-
## Notes
93+
## Example prompts
94+
95+
```text
96+
Use RepoLens to check whether I should use honojs/hono for an edge API.
97+
```
98+
99+
```text
100+
Before you add this dependency, run RepoLens scan_repo and open the report.
101+
```
102+
103+
```text
104+
Generate a RepoLens deep_dive for github.com/fastify/fastify and summarize the gaps.
105+
```
106+
107+
```text
108+
Use blueprint_scene on remix-run/remix so I can see how the repo is structured.
109+
```
110+
111+
## Current scope
112+
113+
- GitHub input only: `owner/name` or a GitHub URL.
114+
- Anthropic provider only via `ANTHROPIC_API_KEY`.
115+
- Local-only: no hosted backend, no RepoLens account.
116+
- The Chrome extension still has the broader provider/platform UX; MCP is the
117+
agent-native path.
133118

134-
- `deep_dive` and `blueprint_scene` are GitHub-deep but README-shallow elsewhere:
135-
only GitHub exposes a file tree, so on other platforms they degrade (`deep_dive`
136-
sets `degraded: true`).
137-
- Next (follow-ups): multi-provider (reuse the extension's `providers.js` registry),
138-
npm / PyPI / GitLab inputs for `scan_repo` (the fetcher already supports them —
139-
only the input parser is GitHub-only), and a `tools/list` structural smoke test.
119+
Planned next steps: publish as `repolens-mcp`, add OpenAI/OpenRouter/Gemini env
120+
providers, and extend `scan_repo` to npm/PyPI/GitLab inputs.

mcp/blueprint-scene.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { buildBlueprintScene } from '../src/blueprint-adapter.js';
1919
import { parseRepoInput } from './repo-input.js';
2020
import { callAnthropic } from './anthropic.js';
2121
import { ghOpts } from './github-auth.js';
22+
import { attachHtmlReport } from './report.js';
2223

2324
export const BLUEPRINT_TOOL = {
2425
name: 'blueprint_scene',
@@ -28,7 +29,14 @@ export const BLUEPRINT_TOOL = {
2829
'dependency / architecture diagram. Heavier than scan_repo (reads source, two model calls).',
2930
inputSchema: {
3031
type: 'object',
31-
properties: { repo: { type: 'string', description: 'A repo as owner/name or a GitHub URL' } },
32+
properties: {
33+
repo: { type: 'string', description: 'A repo as owner/name or a GitHub URL' },
34+
report: { type: 'boolean', description: 'Write a local HTML report. Default: true.' },
35+
openReport: {
36+
type: 'boolean',
37+
description: 'Open the local HTML report in the browser. Default: true.',
38+
},
39+
},
3240
required: ['repo'],
3341
additionalProperties: false,
3442
},
@@ -87,6 +95,11 @@ export const BLUEPRINT_TOOL = {
8795
properties: { x: { type: 'number' }, y: { type: 'number' }, zoom: { type: 'number' } },
8896
},
8997
source: { type: 'object', description: 'lens + timestamps' },
98+
report: {
99+
type: 'object',
100+
description: 'Local HTML report path/url opened for the user.',
101+
properties: { path: { type: 'string' }, url: { type: 'string' }, opened: { type: 'boolean' } },
102+
},
90103
},
91104
required: ['id', 'nodes', 'edges'],
92105
},
@@ -99,5 +112,6 @@ export async function runBlueprintScene(args) {
99112
const source = await fetchSource(platform, repoId, opts);
100113
const { atoms } = parseAtoms(await callAnthropic(buildAtomsPrompt(repoData, source, null)));
101114
const lineage = parseLineage(await callAnthropic(buildLineagePrompt(atoms)));
102-
return buildBlueprintScene({ deepDive: { atoms, lineage }, repoId, title: repoId });
115+
const result = buildBlueprintScene({ deepDive: { atoms, lineage }, repoId, title: repoId });
116+
return attachHtmlReport('blueprint_scene', repoId, result, args);
103117
}

mcp/deep-dive.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
import { parseRepoInput } from './repo-input.js';
2121
import { callAnthropic } from './anthropic.js';
2222
import { ghOpts } from './github-auth.js';
23+
import { attachHtmlReport } from './report.js';
2324

2425
export const DEEP_DIVE_TOOL = {
2526
name: 'deep_dive',
@@ -30,7 +31,14 @@ export const DEEP_DIVE_TOOL = {
3031
'wants to *understand* a codebase, not just judge it. Heaviest tool (reads source, three model calls).',
3132
inputSchema: {
3233
type: 'object',
33-
properties: { repo: { type: 'string', description: 'A repo as owner/name or a GitHub URL' } },
34+
properties: {
35+
repo: { type: 'string', description: 'A repo as owner/name or a GitHub URL' },
36+
report: { type: 'boolean', description: 'Write a local HTML report. Default: true.' },
37+
openReport: {
38+
type: 'boolean',
39+
description: 'Open the local HTML report in the browser. Default: true.',
40+
},
41+
},
3442
required: ['repo'],
3543
additionalProperties: false,
3644
},
@@ -67,6 +75,11 @@ export const DEEP_DIVE_TOOL = {
6775
},
6876
atoms: { type: 'array', description: 'The atomic units the explanation is built from.' },
6977
lineage: { type: 'object', description: 'Causal links + roots/leaves between atoms.' },
78+
report: {
79+
type: 'object',
80+
description: 'Local HTML report path/url opened for the user.',
81+
properties: { path: { type: 'string' }, url: { type: 'string' }, opened: { type: 'boolean' } },
82+
},
7083
},
7184
required: ['repoId', 'explanation'],
7285
},
@@ -95,5 +108,6 @@ export async function runDeepDive(args) {
95108
const { atoms } = parseAtoms(await callAnthropic(buildAtomsPrompt(repoData, source, null)));
96109
const lineage = parseLineage(await callAnthropic(buildLineagePrompt(atoms)));
97110
const feynman = parseFeynman(await callAnthropic(buildFeynmanPrompt(repoData, atoms, lineage)));
98-
return buildDeepDiveResult(repoId, atoms, lineage, feynman, source);
111+
const result = buildDeepDiveResult(repoId, atoms, lineage, feynman, source);
112+
return attachHtmlReport('deep_dive', repoId, result, args);
99113
}

mcp/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "0.1.0",
44
"private": true,
55
"type": "module",
6-
"description": "Local MCP server exposing RepoLens repo analysis (scan_repo) as a tool.",
6+
"description": "Local MCP server that lets agents scan repos and opens RepoLens HTML reports.",
77
"bin": {
88
"repolens-mcp": "./server.js"
99
},

0 commit comments

Comments
 (0)