Skip to content

Make localhost ready for MCP directories: mcp serve, server.json, glama.json, Dockerfile, README, v0.4.0 prep - #64

Merged
marcellosso merged 7 commits into
mainfrom
feat/mcp-registry-ready
Nov 3, 2026
Merged

marcellosso merged 7 commits into
mainfrom
feat/mcp-registry-ready

Conversation

@marcellosso

@marcellosso marcellosso commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

Closes #63

Summary

npx -y @getlocalhost/cli mcp serve [--read-only]
  findApp()                      # same candidates as mcp install; --version/--help probes stay piped
  missing / broken / no --read-only → install or broken instructions on stderr, exit 1
  spawn(<app>/localhost, ['mcp', ...--read-only], { stdio: 'inherit', windowsHide: true })
    SIGINT, SIGTERM, SIGHUP → child.kill(signal)   # not on Windows: the console already sends Ctrl-C
    child exits with code   → exit with it
    child killed by signal  → re-raise it (128 + n if that doesn't end us)
    spawn error             → stderr, exit 1

Nothing but the child writes to stdout. main returns a Promise for serve only, and bin/getlocalhost.js awaits it. install, uninstall and status are unchanged.

 /
+├── server.json        # MCP Registry: io.github.marcellosso/localhost, npm @getlocalhost/cli 0.2.0, args mcp serve
+├── glama.json         # maintainers: marcellosso
+├── .mcp.json          # npx -y @getlocalhost/cli mcp serve
+├── Dockerfile         # introspection only: latest release's .deb (or VERSION), ENTRYPOINT localhost mcp
+├── .dockerignore      # nothing from the repo goes into the context
+├── assets/logo-400.png
 ├── packages/cli/
-│   package.json        0.1.0
+│   package.json        0.2.0, mcpName
+│   test/serve.test.js, test/server-json.test.js
 └── site/src/content/changelog/
+    └── 0.4.0.md        # released: false

Checklist

  • mcp serve [--read-only]: done, as sketched above. parse() takes --read-only for install and serve, rejects it for uninstall and status, and rejects --client and --dry-run for serve. serve reuses refuse() from install, so the missing-app, broken and no---read-only messages are the same ones. Tests in test/serve.test.js cover:

    • parsing;
    • spawn args with and without --read-only;
    • missing app → stderr only, nothing on stdout, exit 1, on all three OSes;
    • --read-only without app support;
    • exit-code forwarding;
    • forwarding SIGINT, SIGTERM and SIGHUP, and the listeners removed afterwards;
    • no forwarding on Windows;
    • re-raising a signal death;
    • a spawn error.

    It also has two end-to-end tests that run mcp serve in a real node process:

    • Every OS, Windows included: Node itself stands in for the app's command (node mcp [--read-only] runs a script named mcp that echoes stdin and exits 3). It checks that stdout carries exactly the server's bytes, that --read-only is passed on, and that exit code 3 comes back through serve.
    • macOS and Linux: a fake localhost shell script (localhost 9.9.9, echoes stdin on mcp) found through the real --version/--help probes. It's skipped on Windows because the fixture is a shell script. USAGE, packages/cli/README.md (a new "Any MCP client" section) and the npm description now cover mcp serve.
  • package.json: mcpName: io.github.marcellosso/localhost, version 0.2.0. No other file lists the CLI version.

  • server.json: as specified. 2025-12-11 is still the latest released schema; the registry repo has only a draft beyond it. The description is 87 characters, not 86, still within 100. test/server-json.test.js checks that name === mcpName, that both versions equal package.json's, the identifier, the mcp serve args and the description length. CI's cli filter now includes server.json and .mcp.json. I left out icons: the schema allows them, but the image URL only exists after merge. It can come later.

  • glama.json: done, and valid against Glama's schema. Glama's schema has only maintainers, so the logo isn't referenced there.

  • Dockerfile: done. It's pinned with ARG VERSION=0.4.0, and a comment says to bump it with each release. --build-arg VERSION=latest resolves the latest tag through the releases/latest redirect. Until v0.4.0 is published, a plain docker build . fails, because the v0.4.0 .deb is a 404. Build with --build-arg VERSION=latest until then. It runs localhost --version at build time and purges curl afterwards. The header comment says it's for introspection only.

  • .mcp.json: done. Effect on contributors: Claude Code treats a root .mcp.json as a project-scoped server. It asks each contributor before enabling it, unless they set enableAllProjectMcpServers or enabledMcpjsonServers. Once approved, it takes precedence over a user-scope server with the same name (local > project > user), so in this repo it replaces the app's own localhost entry. Both run the same app binary, but until CLI 0.2.0 is on npm, npx fetches 0.1.0, which has no serve, so that server fails. CONTRIBUTING.md says to decline it, or to list it in disabledMcpjsonServers. Cursor reads .cursor/mcp.json, not the root file, and Codex ignores it.

  • README: a new subsection at the end of "Coding agents (MCP)", ### How do I add the localhost MCP server to Claude Code, Cursor or Codex?, so the #coding-agents-mcp anchors still work. It opens with a one-sentence definition of localhost mcp, and the tool list says the six editing tools need the app 0.4.0 or later. It has:

    • npx -y @getlocalhost/cli mcp install [--read-only];
    • Claude Code (claude mcp add --scope user localhost -- npx -y @getlocalhost/cli mcp serve; I added --scope user to match the README's other commands);
    • Codex (codex mcp add …, or the [mcp_servers.localhost] block);
    • Cursor, Claude Desktop and other clients (the JSON);
    • the 15 tools, checked against core/localhost-cli/src/mcp/tools.rs and tools/edits.rs;
    • the note on the Dockerfile and the app requirement;
    • <!-- mcp-name: io.github.marcellosso/localhost -->.

    I checked the CLI syntax with claude mcp add --help (2.1.317) and codex mcp add --help (0.166.0). Skipped: the Cursor deeplink, because I couldn't verify its current format. The FAQ is untouched, so it stays in sync with faq.ts. The site's /docs/mcp gets a mcp serve row and a "With npx" section, the agents FAQ answer, which feeds llms.txt, mentions mcp serve, and so does step 4 ("Or set it up by hand") on /agents. The "With npx" section opens with a one-line definition.

  • Logo: assets/logo-400.png, rendered from apps/desktop/src-tauri/icons/icon.svg with sips (1024 px, then 400×400). It has no version number.

  • v0.4.0 prep: following RELEASING.md, the tag is the only version, so tauri.conf.json, MARKETING_VERSION and the crates are untouched. 0.4.0.md (released: false) covers:

    I left out the site, CI and publishing-workflow PRs (Show the Homebrew install across the site #43, CI: run each job only when files it depends on change #47, Website redesign: the labelled panel, landing and every page (#46) #50, Landing hero: GitHub link, per-OS install links and a quieter header Download #54, Site: hero platform links go to the docs; compare page and FAQ cover the MCP write tools #58, Publish @getlocalhost/cli from CI with npm trusted publishing #60, Site: guides, per-tool compare pages, no-Docker wording and the npx fix on /compare #62). "From the release after 0.3.0" in the CLI README now says 0.4.0. Nothing is tagged or released. CONTRIBUTING has a new "Publishing to the MCP Registry" section (mcp-publisher validate, login github, publish, after npm 0.2.0). None of it was run except validate.

Evidence

  • cd packages/cli && npm test: 53 pass, 0 fail (Node 24.10, macOS), and 53 tests with 0 failures on Linux in node:18-slim and node:22-slim (the one skip there is the existing "no Claude Desktop for Linux" test). Before: 39 tests, and mcp serve was Unknown command “mcp serve”.
  • With the installed app (0.3.0), using a throwaway LOCALHOST_STORAGE_ROOT: initialize, then notifications/initialized, then tools/list piped into node packages/cli/bin/getlocalhost.js mcp serve. It exited 0, stdout held exactly 2 JSON-RPC responses (ids 1 and 2, 9 tools), and stderr was empty. mcp serve --read-only against 0.3.0 printed localhost 0.3.0 has no `localhost mcp --read-only` yet… to stderr, put 0 bytes on stdout and exited 1.
  • Without the app (Linux, the real bin in node:22-slim): exit 1, 0 bytes on stdout, and the Linux install steps with https://www.getlocalhost.app on stderr.
  • server.json: mcp-publisher validate (v1.8.7, release binary, SHA-256 checked) reported ✅ server.json is valid. Also valid offline against the 2025-12-11 schema with npx ajv-cli@5.0.0 + ajv-formats@3.0.1 (draft-07), and glama.json against Glama's schema.
  • docker build --platform=linux/amd64 succeeded with VERSION=latest (v0.3.0) and with VERSION=0.3.0. The pinned default, 0.4.0, can only build once that release exists; the image is 137 MB. Piping the issue's initialize + initialized + tools/list, plus a list_projects call, into docker run -i --rm returned ids 1, 2 and 3, serverInfo.version 0.3.0, 9 tools and {"projects": []}. Built on an Apple-silicon Mac through emulation.
  • Site: npm ci can't run in site/. It has pnpm-lock.yaml and no package-lock.json ("can only install with an existing package-lock.json"), so I used pnpm install --frozen-lockfile && pnpm run build, which completed. In dist/changelog.html, 0.4.0 shows as Unreleased and 0.3.0 as v0.3.0. Every anchor the changelog links to exists (#tools, #read-only, #connect-from-a-terminal, #with-npx, /docs/install#homebrew-macos).
  • publish-cli.yml -f dry-run=true on this branch (run 41732144725): success. On Linux, Node 24, it ran npm test, checked that 0.2.0 isn't on npm yet, ran npm pack --dry-run (skill included) and npm publish --dry-run. npm still lists only 0.0.0-stage and 0.1.0.

Not verified locally: Windows. CI runs the CLI tests on windows-latest, including the real-spawn end-to-end test. The first CI run failed 7 serve tests there. They never reached the fake spawn: the test helper built a linux fixture, whose command path used Windows separators on a Windows host while candidates() for Linux looked for a POSIX one, so findApp found no app. That was a test bug, not a bug in serve. The helper now hands findApp the fixture's own command on every OS. The same run's macOS Rust job timed out in localhost-core/tests/ports.rs (no Listener appeared: Elapsed). This PR changes nothing in core/; the job only ran because the PR edits ci.yml. The new tools (15) are verified only from the code, because the installed app and the latest release are 0.3.0.

After merge (Marcel)

  1. Run the Linux packages workflow (gh workflow run packages.yml -R marcellosso/localhost --ref main).
  2. Tag v0.4.0 and publish the draft. The changelog flips to released by itself.
  3. gh workflow run publish-cli.yml -R marcellosso/localhost --ref main (CLI 0.2.0).
  4. mcp-publisher login github && mcp-publisher publish.
  5. Submit to the directories.

Until step 3, npx -y @getlocalhost/cli mcp serve resolves to 0.1.0, which has no serve. The README's npx instructions start working once 0.2.0 is published.

Merge Danger

Door: two-way. It's docs, new root files, a new subcommand and a version field. Nothing is published by merging.

Blast Radius: small. install, uninstall and status behave as before, and their tests pass unchanged. The root .mcp.json prompts Claude Code users in this repo, as described above. The CLI job now also runs when server.json or .mcp.json change.

@vercel

vercel Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
localhost-web Ready Ready Preview Nov 3, 2026 10:43pm UTC

@marcellosso
marcellosso merged commit 017ad3d into main Nov 3, 2026
15 checks passed
@marcellosso
marcellosso deleted the feat/mcp-registry-ready branch November 3, 2026 22:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make localhost ready for MCP directories: mcp serve, server.json, glama.json, Dockerfile, README, v0.4.0 prep

1 participant