loopback-mcp-server
Advanced tools
+76
-1
@@ -8,4 +8,79 @@ # Changelog | ||
| ## [0.9.1] — 2026-07-27 | ||
| ## [0.9.2] — 2026-08-02 | ||
| Ships the `init` fix below to adopters. 0.9.1 still writes a git-clone MCP | ||
| config, so source being correct changed nothing until this release. | ||
| ### Added — `npm run bump <version>` | ||
| A release moves SIX hand-typed fields across five files (package.json, | ||
| `SERVER_VERSION`, server.json's version *and* every `packages[].version`, the | ||
| plugin manifest, and the marketplace entry). The gates enforce that they agree, | ||
| so a partial bump fails CI — but a *forgotten* bump fails later and worse: | ||
| `npm publish` refuses with "cannot publish over the previously published | ||
| versions" after the notes are written and the commit is pushed. That happened | ||
| on this release. The command edits only; build, gates and publish stay manual. | ||
| ### Fixed — `init` handed every adopter a git-clone MCP config | ||
| `serverCommand()` emitted `npx -y github:joshidikshant/loopback` on any | ||
| EPHEMERAL run — which is precisely how the README documents onboarding | ||
| (`npx loopback-mcp-server init`). Every adopter following it got `.mcp.json`, | ||
| `.codex/config.toml` and `.gemini/settings.json` pointing at a **git clone that | ||
| runs a full `tsc` build on every cold MCP start**. That was the right call when | ||
| nothing was published; it became wrong the moment `loopback-mcp-server` shipped | ||
| to npm, and it survived because no gate could reach the branch. Now | ||
| `npx -y loopback-mcp-server`, unpinned so adopters get fixes without re-running | ||
| init. The four docs handing out the same stale command are corrected too. | ||
| Found by an adversarial audit that *reproduced* it rather than arguing it, and | ||
| gated twice over: | ||
| - `init-gate` runs the CLI from an `_npx`-shaped fixture — the only path that | ||
| reaches the branch. A first version invoked the normal `dist/index.js` and | ||
| **passed with the git spec restored**; the canary caught it. | ||
| - Its guard-the-guard then had the same disease: it searched raw text for | ||
| `"npx"` while the temp dir was named `loopback-npx-…`, so an absolute path in | ||
| a `node <path>` command satisfied it. Now asserts the parsed `command` field. | ||
| ### Added — `npm run verify:release` | ||
| Post-publish verification of all three channels, by using them: installs the | ||
| published tarball into a clean directory, renders `init` from it, **runs the | ||
| MCP command init actually wrote** (not a path the script composes — the audit | ||
| reproduced a false green there too), confirms the MCP Registry listing resolves | ||
| to the shipped version, and runs the plugin's registered command from an empty | ||
| directory. Tools are checked by NAME, not count, so a rename cannot hide. | ||
| Deliberately not a per-push gate: it needs the network and tests published | ||
| artifacts, so on a PR it would pass while the branch is broken. Sweep is 19. | ||
| ### Fixed — the plugin channel was two releases stale | ||
| A structural review found the Claude Code plugin shipping a **fourth** copy of | ||
| the skill playbook that nothing rendered, so it silently kept the | ||
| pre-attachments version while the other three were fixed. Alongside it, two | ||
| version fields still read `0.8.0` after two published releases, and the plugin | ||
| told Claude Code to install via `npx github:joshidikshant/loopback` — a git | ||
| clone that runs a full `tsc` build on every cold start — when the package is on | ||
| npm. | ||
| - `plugin/skills/loopback/SKILL.md` synced from the canonical template. | ||
| - `plugin/.claude-plugin/plugin.json` and `.claude-plugin/marketplace.json` | ||
| now track `package.json`. | ||
| - `plugin/.mcp.json` installs `loopback-mcp-server` from npm. | ||
| - `init-gate` gained five assertions covering all of it, canaried three ways; | ||
| the sweep is 18 checks. The npm release touches none of these files, which is | ||
| exactly why they rotted. | ||
| ### Removed | ||
| `fv-probe.mjs` — a one-off Playwright scratch file from pass 6, referenced by | ||
| nothing. | ||
| ### Changed — the repo map documents the whole tree | ||
| The six root dot-directories are `init` output (the repo onboards itself, and | ||
| `init-gate` re-renders them each CI run), but nothing said so, which read as | ||
| clutter. The map now covers them, `public/`, `assets/`, and the two root | ||
| manifests that do different jobs — `registry.json` for shadcn, `server.json` | ||
| for the MCP Registry. Also corrected the widget size, still quoted as | ||
| 46KB/15KB against a measured 57KB/19KB. | ||
| ## [0.9.1] — 2026-07-27 — published to npm and the MCP Registry | ||
| ### Added — MCP Registry identity (`mcpName` + `server.json`) | ||
@@ -12,0 +87,0 @@ The official MCP Registry proves package ownership by fetching the **published** |
+13
-3
@@ -27,3 +27,13 @@ /** | ||
| const PACKAGE_ROOT = resolve(__dirname, ".."); | ||
| const REPO_SPEC = "github:joshidikshant/loopback"; | ||
| /** | ||
| * What an ephemeral (npx) run points agent configs at. | ||
| * | ||
| * This was `github:joshidikshant/loopback` back when nothing stable was | ||
| * published — which made every adopter who followed the README's own | ||
| * `npx loopback-mcp-server init` command git-CLONE the repo and run a full | ||
| * `tsc` build on every cold MCP start. The package is on npm now, so the | ||
| * ephemeral branch resolves a published tarball instead. Unpinned on | ||
| * purpose: an adopter should get fixes without re-running init. | ||
| */ | ||
| const NPM_SPEC = "loopback-mcp-server"; | ||
| const SECTION_BEGIN = "<!-- loopback:queue:begin -->"; | ||
@@ -110,3 +120,3 @@ const SECTION_END = "<!-- loopback:queue:end -->"; | ||
| * - Stable checkout elsewhere → absolute path (fast startup). | ||
| * - Ephemeral npx run → `npx github:` (nothing stable to point at). | ||
| * - Ephemeral npx run → `npx loopback-mcp-server` (the published package). | ||
| */ | ||
@@ -117,3 +127,3 @@ function serverCommand(cwd) { | ||
| if (ephemeral || !existsSync(entry)) | ||
| return { command: "npx", args: ["-y", REPO_SPEC] }; | ||
| return { command: "npx", args: ["-y", NPM_SPEC] }; | ||
| const inside = relative(cwd, entry); | ||
@@ -120,0 +130,0 @@ if (!inside.startsWith("..") && !isAbsolute(inside)) { |
+1
-1
@@ -6,3 +6,3 @@ /** MCP server definition: nine loopback_* tools over the feedback store. */ | ||
| import { itemMarkdown, listMarkdown } from "./format.js"; | ||
| export const SERVER_VERSION = "0.9.1"; | ||
| export const SERVER_VERSION = "0.9.2"; | ||
| function ok(text, structured) { | ||
@@ -9,0 +9,0 @@ return { |
@@ -69,2 +69,6 @@ /** | ||
| assert(srv.version === pkg.version && srv.packages.every((x) => x.version === pkg.version), `server.json versions track package.json (${srv.version} / ${srv.packages.map((x) => x.version).join(",")} vs ${pkg.version})`); | ||
| // The registry REJECTS on this rather than truncating, and it is the kind of | ||
| // field that grows during a docs pass. Caught for real: the first draft ran | ||
| // 191 chars and `mcp-publisher validate` 422'd. | ||
| assert(srv.description.length > 0 && srv.description.length <= 100, `server.json description is within the registry's 100-char limit (${srv.description.length})`); | ||
| assert(srv.packages.every((x) => x.identifier === pkgJson.name), `server.json package identifier is the published npm name (${srv.packages.map((x) => x.identifier).join(",")})`); | ||
@@ -71,0 +75,0 @@ console.log(`✅ version + registry-identity parity: ${SERVER_VERSION} / ${srv.name}`); |
@@ -16,3 +16,3 @@ # Claude Code × Loopback | ||
| # or zero-install from GitHub: | ||
| claude mcp add --scope user loopback -- npx -y github:joshidikshant/loopback | ||
| claude mcp add --scope user loopback -- npx -y loopback-mcp-server | ||
| ``` | ||
@@ -19,0 +19,0 @@ |
@@ -15,3 +15,3 @@ # Codex × Loopback | ||
| args = ["/ABS/PATH/loopback/dist/index.js"] | ||
| # or zero-install: command = "npx" / args = ["-y", "github:joshidikshant/loopback"] | ||
| # or zero-install: command = "npx" / args = ["-y", "loopback-mcp-server"] | ||
| ``` | ||
@@ -18,0 +18,0 @@ |
@@ -24,3 +24,3 @@ # Gemini CLI × Loopback | ||
| Zero-install alternative: `"command": "npx", "args": ["-y", "github:joshidikshant/loopback"]`. | ||
| Zero-install alternative: `"command": "npx", "args": ["-y", "loopback-mcp-server"]`. | ||
@@ -27,0 +27,0 @@ **HTTP variant** — point at the long-running central instance instead: |
+5
-2
| { | ||
| "name": "loopback-mcp-server", | ||
| "mcpName": "io.github.joshidikshant/loopback", | ||
| "version": "0.9.1", | ||
| "author": "Dikshant Joshi", | ||
| "version": "0.9.2", | ||
| "files": [ | ||
@@ -23,2 +24,3 @@ "dist", | ||
| "build": "tsc", | ||
| "bump": "node scripts/bump-version.mjs", | ||
| "prepare": "npm run build", | ||
@@ -39,3 +41,4 @@ "start": "node dist/index.js", | ||
| "a11y-gate": "node scripts/a11y-gate.mjs", | ||
| "canary": "node scripts/canary-all.mjs" | ||
| "canary": "node scripts/canary-all.mjs", | ||
| "verify:release": "node scripts/release-verify.mjs" | ||
| }, | ||
@@ -42,0 +45,0 @@ "repository": { |
+41
-10
@@ -18,5 +18,5 @@ # Loopback | ||
| *Real screenshot: the contact form's backend bug was pinned, claimed by | ||
| claude-code, fixed with a PR, verified — pin and badge are green. The wrong AI | ||
| answer is still amber/open.* | ||
| *Seeded demo capture (generated by `scripts/screenshot.mjs`): the contact form's | ||
| backend bug pinned, claimed by claude-code, marked fixed with a linked change, | ||
| verified — pin and badge green. The wrong AI answer is still amber/open.* | ||
@@ -90,3 +90,3 @@ ## Why | ||
| |---|---|---| | ||
| | **Claude Code** | `claude mcp add --scope user loopback -- npx -y github:joshidikshant/loopback` — or the plugin: `claude plugin marketplace add joshidikshant/loopback && claude plugin install loopback@loopback` | `@AGENTS.md` import in CLAUDE.md + skill at `.claude/skills/loopback/` → [claude.md](integrations/claude.md) | | ||
| | **Claude Code** | `claude mcp add --scope user loopback -- npx -y loopback-mcp-server` — or the plugin: `claude plugin marketplace add joshidikshant/loopback && claude plugin install loopback@loopback` | `@AGENTS.md` import in CLAUDE.md + skill at `.claude/skills/loopback/` → [claude.md](integrations/claude.md) | | ||
| | **Codex** | `~/.codex/config.toml`: `[mcp_servers.loopback]` `command`/`args` (or project-scoped `.codex/config.toml`) | AGENTS.md read natively + native SKILL.md at `.agents/skills/loopback/` → [codex.md](integrations/codex.md) | | ||
@@ -361,6 +361,18 @@ | **Gemini CLI** | `~/.gemini/settings.json` → `mcpServers.loopback` | AGENTS.md via `context.fileName` + `@AGENTS.md` in GEMINI.md + `/loopback` command → [gemini.md](integrations/gemini.md) | | ||
| npm publish --otp=<code> # 2FA code from your authenticator | ||
| mcp-publisher validate # checks server.json against the live registry | ||
| mcp-publisher login github # opens a browser | ||
| mcp-publisher publish # reads server.json | ||
| npm run verify:release # proves all three channels from a clean dir | ||
| ``` | ||
| Run `validate` before `publish` — it checks the manifest against the real | ||
| registry without spending an attempt. Run `verify:release` after, and read what | ||
| it prints: it installs the published tarball into a clean directory, renders | ||
| `init` from it, speaks real MCP to the result, confirms the registry listing | ||
| resolves to the version you just shipped, and runs the plugin's own registered | ||
| command from an empty directory. Every one of those steps has caught a real bug | ||
| that the source-side gates could not see. `description` is capped at **100 | ||
| characters** and is rejected, not truncated, past it, so `npm run smoke` | ||
| asserts that limit locally as well. | ||
| ## Tests | ||
@@ -429,5 +441,5 @@ | ||
| the ingestion boundary. | ||
| 7. **Widget is ~46KB / 15KB gzipped, not the ~10KB sketch** — ring buffers, failure-body | ||
| capture, live pins, and the walkthrough earn their bytes; still zero deps, | ||
| one file. | ||
| 7. **Widget is 57KB / 19KB gzipped, not the ~10KB sketch** — ring buffers, failure-body | ||
| capture, live pins, repro steps, the route journey and the walkthrough earn | ||
| their bytes; still zero deps, one file, served pre-compressed with an ETag. | ||
| 8. **Marker-based merges** — `init` re-runs are byte-idempotent; files a human | ||
@@ -446,9 +458,28 @@ has taken over (generated marker removed) are left untouched. | ||
| design/ shared tokens.css — one design system for widget, dashboard, registry | ||
| skills/ canonical loopback SKILL.md (installed for Claude + Codex) | ||
| public/ built dashboard + the published shadcn registry (public/r) | ||
| skills/ CANONICAL loopback SKILL.md — every other copy is rendered from it | ||
| integrations/ canonical playbook + per-agent setup + widget embed + keep-alive | ||
| plugin/ Claude Code plugin (skill + MCP registration); repo doubles as its marketplace | ||
| scripts/ e2e.mjs · the six gates · screenshot.mjs | ||
| docs/ the decision history (spec → memo → paths → technical path) | ||
| scripts/ e2e.mjs · the six gates · canary-all.mjs · screenshot.mjs | ||
| docs/ the decision history (spec → memo → paths → technical path) + ROADMAP | ||
| assets/ the README screenshot (generated by scripts/screenshot.mjs) | ||
| ``` | ||
| Two manifests at the root do different jobs: `registry.json` publishes the | ||
| **shadcn** components, and `server.json` is the **MCP Registry** entry (see | ||
| [Publishing to the MCP Registry](#publishing-to-the-mcp-registry)). | ||
| The root also carries agent config that `init` itself writes — the repo | ||
| onboards *itself*, so these are working proof the command produces what it | ||
| claims, and `init-gate` re-renders them on every CI run to prove they have not | ||
| drifted: | ||
| ``` | ||
| AGENTS.md · CLAUDE.md · GEMINI.md the queue playbook, per agent | ||
| .claude/ .agents/ the loopback skill for Claude Code / Codex | ||
| .codex/ .gemini/ per-agent MCP + command registration | ||
| .mcp.json MCP server registration for this repo | ||
| .claude-plugin/ marketplace manifest (repo hosts its own plugin) | ||
| ``` | ||
| MIT © Dikshant Joshi |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
838861
0.87%6774
0.21%0
-100%481
6.89%