Skip to content

release(mcp): make the MCP server package installable and registry-ready - #95

Merged
7shep merged 2 commits into
mainfrom
agent/issue-60-mcp-release
Jul 31, 2026
Merged

release(mcp): make the MCP server package installable and registry-ready#95
7shep merged 2 commits into
mainfrom
agent/issue-60-mcp-release

Conversation

@7shep

@7shep 7shep commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Summary

Makes the MCP server installable from npm as @7shep/universal-mcp, so users can connect an MCP client without cloning the monorepo.

  • Public package metadata: name, description, MIT license, repository (with directory), homepage, bugs, keywords, engines.node >= 22, bin, explicit files, publishConfig.access: public. private: true removed. Version starts at 0.1.0-alpha.0.
  • scripts/bundle.mjs produces the published entrypoint with esbuild.
  • test/package.test.mjs is the install smoke test.
  • server.json draft for the official MCP Registry under io.github.7shep/*.
  • docs/MCP_RELEASE.md covers client configuration, environment variables, tarball contents, versioning, the release steps, and rollback.

Why a bundle was necessary

The server depends on eight private @universal/* workspace packages. Publishing it as-is would produce a tarball that cannot install, because npm would try to resolve those from the registry. bundle.mjs inlines them and keeps only the genuine runtime dependencies external — @modelcontextprotocol/sdk, zod, and the three the runtime build path actually needs (playwright, sharp, fonteditor-core) plus typescript. Those five move from transitive workspace deps to declared dependencies; nothing new was added to the repo's dependency graph, they are just now honest about being runtime requirements. esbuild is the one new devDependency.

Two bundled packages read files relative to their own module URL — the runtime's project template/, and the deterministic provider's .txt sources. The bundle copies each to exactly where the bundled code will look, then asserts it landed there, so a layout change fails the build rather than a user's first run. The script also fails if any import other than a declared dependency is left external.

The smoke test is a real one

test/package.test.mjs runs offline and:

  1. packs the tarball and asserts it carries dist/index.js, the provider assets, template/, server.json, README.md, LICENSE.MD — and no src/, no scripts/, no *.test.*, no tsconfig.json;
  2. asserts the manifest declares no @universal/* or workspace: dependency, is not private, and has license/repository/engines;
  3. extracts the tarball to a temp directory outside the checkout, links only the five declared dependencies, starts the binary there, lists tools, and calls create_design_plan so the bundled internals actually execute.

Step 3 is the one that matters: if the bundle reaches for a workspace package or a monorepo source path, the server does not start and the test fails. It links from the local store rather than installing from the registry, so it does not download Playwright or Sharp — what it proves is that nothing outside those five is needed.

Wired into pnpm --filter @7shep/universal-mcp test, so it runs in the existing CI gate.

Publishing stays maintainer-triggered

No workflow publishes, and no npm or registry credential is added to the repository or CI. docs/MCP_RELEASE.md documents the manual steps, the pre-1.0 "no API stability" expectation, why pre-releases must not take the latest tag, and rollback via npm dist-tag / npm deprecate rather than unpublish.

server.json is checked in as a draft. Registry submission additionally needs namespace-ownership proof via the registry CLI, which is deliberately not automated here.

Renaming

The workspace package name changes from @universal/design-mcp to @7shep/universal-mcp (nothing depends on it internally). The 13 pnpm --filter references across README, CONTRIBUTING, and docs are updated. The directory stays packages/design-mcp.

Also added: UNIVERSAL_REPOSITORY_ROOT so the containment guard can be set explicitly when installed rather than inferred from a monorepo-relative path, and an eslint block giving **/*.mjs Node globals.

Validation

  • pnpm --filter @7shep/universal-mcp test — 14 server tests + 3 packaging tests, all passing
  • pnpm lint, pnpm typecheck, pnpm format:check

Not done: nothing is published. @7shep/universal-mcp should be checked as available (and the scope claimed) before the first release.

Closes #60.

🤖 Generated with Claude Code

The server built a local binary but was private and depended on eight
private workspace packages, so a published tarball could not install.

Bundle those packages into the entrypoint, declare the real runtime
dependencies, add public package metadata, a draft MCP Registry entry, and
an offline smoke test that starts the packed binary outside the monorepo.

Closes #60.

Co-Authored-By: Claude <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
universal Ready Ready Preview Jul 31, 2026 6:48pm

@7shep
7shep merged commit 79420a4 into main Jul 31, 2026
7 checks passed
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.

release(mcp): make the MCP server package installable and registry-ready

1 participant