Go to file
Marco Sadjadi a189111782 feat(marketplace): default-on share in wizard + owner unshare anytime
Goal: maximize template volume without a dark pattern and without leaking data.

Wizard Done-page Share panel:
- 'Share as template in the marketplace (recommended)' checkbox, default ON,
  rendered inline in the build-success flow where every user lands.
- Honest copy — corrected a draft that claimed 'only abstracted code pattern is
  shared'. That is false: the FULL generated code becomes publicly viewable on
  the template detail page (by design, for pre-fork audit). The panel now says:
  'Your secrets stay private ... but your generated code becomes publicly
  viewable so others can audit it before forking. Unshare anytime.'
- When checked: inline minimal form — short description (prefilled from the
  spec), category select, optional per-secret credential hints. One 'Publish to
  marketplace' click. Not auto-published silently — that would be a consent dark
  pattern; one visible deliberate click keeps it clean.
- Forked servers don't show the panel (re-publishing a fork is an edge case).

Owner unshare/reshare:
- GET /v1/servers/:id/template — owner lookup, drives the Publish tab UI.
- PATCH /v1/templates/:slug/visibility { shared } — owner-only toggle between
  public and hidden. 403 for non-owners, 409 if an admin took it down (owner
  cannot resurrect an admin takedown). Audit-logged as template.unshare /
  template.reshare.
- Server-detail Publish tab now detects an existing template and shows the
  shared status (public/hidden/takedown badge), fork count, a marketplace link
  and an Unshare/Re-share button — instead of the publish form.

Why this is safe to default ON:
- Secrets are architecturally bound to mcp_servers, never copied into templates.
  Publish reads tools_schema + generated_code only; the secrets table is never
  touched. Data leak is structurally impossible, not policy-dependent.
- Publish re-scans the generated code for banned patterns AND hardcoded
  credentials (sovereign-audit hardening) before it can reach the marketplace.
- The user sees a visible, pre-ticked checkbox and reads one honest sentence
  before publishing. Privacy-conscious users untick; everyone else contributes
  volume. Informed consent, GDPR-clean.

Verified end-to-end via API:
  GET server/:id/template -> null (unpublished)
  POST /v1/templates -> published, slug share-test-server
  GET server/:id/template -> status public
  PATCH visibility {shared:false} -> hidden, drops out of public list
  PATCH visibility {shared:true} -> public again
UI: Publish tab renders the shared-status panel with View + Unshare (screenshot
confirmed).

Also: hero badge date set to 2026-05-20. Changed 'MCP spec 2025-11-25' to
'updated 2026-05-20' — claiming an MCP spec dated today would be factually wrong
(no such spec release exists); 'updated' is accurate and gives the requested
fresh date. The real spec date is still cited correctly in /docs.
2026-05-20 17:04:46 +02:00
apps feat(marketplace): default-on share in wizard + owner unshare anytime 2026-05-20 17:04:46 +02:00
packages feat(marketplace): template publish + fork + voting/ranking + admin moderation 2026-05-19 23:22:35 +02:00
scripts chore(dev): bootstrap script wires docker + drizzle push + turbo dev 2026-05-19 00:35:27 +02:00
.env.example feat(admin): password-auth admin panel with 8 pages + 15 API endpoints 2026-05-19 23:01:26 +02:00
.gitignore chore: bootstrap monorepo (turbo, biome, docker-compose, env, CHOICES) 2026-05-19 00:20:15 +02:00
biome.json chore: bootstrap monorepo (turbo, biome, docker-compose, env, CHOICES) 2026-05-19 00:20:15 +02:00
BuildMyMCPServer_MASTER_PROMPT.md chore: bootstrap monorepo (turbo, biome, docker-compose, env, CHOICES) 2026-05-19 00:20:15 +02:00
CHOICES.md feat(web): real 3-step wizard, settings, audit, docs, marketing pages 2026-05-19 18:20:31 +02:00
docker-compose.yml fix: live-run wiring (SDK 1.29, zod 3.25, OAUTH_ISSUER split, alt host ports, web on 3001, log level cast, pino transport) 2026-05-19 00:57:23 +02:00
package.json chore(dev): bootstrap script wires docker + drizzle push + turbo dev 2026-05-19 00:35:27 +02:00
pnpm-lock.yaml feat(llm): extract Claude SYSTEM_PROMPT + generateSpec into shared @bmm/llm package 2026-05-19 18:05:31 +02:00
pnpm-workspace.yaml chore: bootstrap monorepo (turbo, biome, docker-compose, env, CHOICES) 2026-05-19 00:20:15 +02:00
README.md chore(dev): bootstrap script wires docker + drizzle push + turbo dev 2026-05-19 00:35:27 +02:00
TEMPLATE_SECURITY_AUDIT.md fix(security): template integration sovereign audit + critical fixes 2026-05-19 23:35:45 +02:00
tsconfig.base.json chore: bootstrap monorepo (turbo, biome, docker-compose, env, CHOICES) 2026-05-19 00:20:15 +02:00
turbo.json chore: bootstrap monorepo (turbo, biome, docker-compose, env, CHOICES) 2026-05-19 00:20:15 +02:00

BuildMyMCPServer

Describe your tool. We host the server. AI uses it.

Prompt-to-production MCP servers with OAuth 2.1 and Streamable HTTP. Production-grade infrastructure for hosting Model Context Protocol servers your AI clients (Claude Desktop, Cursor, ChatGPT) can install with a copy-paste snippet.

Quick start

# 1. Install
pnpm install

# 2. Copy env. Defaults work for local dev. Set ANTHROPIC_API_KEY if you want real generation.
cp .env.example .env

# 3. Boot everything
pnpm dev

pnpm dev will:

  1. Load .env.
  2. docker compose up -d --wait postgres + redis.
  3. Push the Drizzle schema (drizzle-kit push --force).
  4. Start the full stack in parallel: web (Next.js, :3000), api (Fastify, :4000), generator (BullMQ worker).

Then open:

Click Start building, enter your email, copy the magic-link URL printed to the api terminal output, paste it in your browser. You land on /dashboard. Click New server, paste a prompt, and watch the build stream live over WebSocket.

If ANTHROPIC_API_KEY is unset, the generator returns a deterministic mock spec (an echo and a now tool) so the full end-to-end flow stays demoable.

If Docker is unavailable, the build will fail at the deploy step with a clear error. Otherwise: a fresh container is launched on a host port from RUNNER_PORT_RANGE_START…RUNNER_PORT_RANGE_END, the server is marked live, and the dashboard renders install snippets for Claude Desktop, Cursor and ChatGPT.

Architecture

See BuildMyMCPServer_MASTER_PROMPT.md for the full specification and CHOICES.md for decisions made during this Sprints 13 build.

apps/
  web/              Next.js 15 dashboard + marketing landing
  api/              Fastify control plane (auth, server CRUD, OAuth 2.1 AS, JWKS, WS stream)
  generator/        BullMQ worker — Claude → spec → render → docker build → local deploy
  runner-template/  Hosted MCP server template (Streamable HTTP + OAuth 2.1 RS)
packages/
  db/               Drizzle schema + client
  auth/             Magic-link + session
  types/            Shared Zod contracts

Scripts

Command Effect
pnpm dev Bootstrap + parallel dev for web, api, generator
pnpm dev:no-docker Skip docker-compose (assumes postgres + redis already up)
pnpm build Turbo build all apps
pnpm typecheck Turbo typecheck all apps
pnpm lint Biome check
pnpm lint:fix Biome check --write
pnpm db:push Push schema to postgres (drizzle-kit)
pnpm db:generate Generate SQL migration files
pnpm db:migrate Apply pending migrations
pnpm stop docker compose down

Acceptance check

After pnpm dev is up:

  • http://localhost:3000 renders the landing page.
  • http://localhost:4000/health returns { "ok": true }.
  • Sign in via magic link (URL printed in the api terminal).
  • New Server → paste prompt → live WebSocket stream queued → generating → building → deploying → live.
  • If Docker is running, a container is launched and http://localhost:<port>/mcp responds 401 + WWW-Authenticate without a token, 200 with a valid token issued by /oauth/token.
  • Install snippets render with copy buttons for Claude Desktop, Cursor, ChatGPT.

Repo conventions

  • TypeScript strict, zero any (Biome lints noExplicitAny as error).
  • ESM-only, Node 20 LTS.
  • Conventional commits.
  • Tailwind v4 (@import 'tailwindcss').
  • Geist + Geist Mono.