# ADR-111: Multi-Marketplace Publishing Pipeline & Conflict Prevention

**Date:** 2026-03-16 | **Status:** ACCEPTED

---

## Context

Graqle v0.27.0 is published to multiple marketplaces simultaneously. Each marketplace has different update mechanisms, validation requirements, and timing constraints. Without a formal publishing protocol, releases risk:

1. **Version conflicts** — PyPI version doesn't match MCP Registry version doesn't match `server.json`
2. **Validation failures** — MCP Registry validates `mcp-name` tag in PyPI README; if README isn't updated before publish, Registry rejects
3. **Badge/listing drift** — awesome-mcp-servers PR references a version that doesn't exist yet on Glama
4. **User-facing breakage** — `graq plugins install` deploys bridge files that reference features not yet in the released version
5. **Duplicate CORS-style bugs** — one marketplace auto-updates (MCP Registry from PyPI) while another is manual (awesome-mcp-servers), causing version mismatch visible to users

## Decision

### Publishing Order (MANDATORY — sequential, not parallel)

Every release MUST follow this exact order. Steps are sequential because each depends on the previous.

```
Phase 1: Pre-Publish Validation
  ├── 1.1  All tests pass: pytest tests/ -x -q
  ├── 1.2  Version bumped in THREE places (must match):
  │         • pyproject.toml → version = "X.Y.Z"
  │         • graqle/__version__.py → __version__ = "X.Y.Z"
  │         • server.json → version + packages[0].version = "X.Y.Z"
  ├── 1.3  README contains: <!-- mcp-name: com.graqle/graqle -->
  ├── 1.4  Bridge .md files compile (no broken references)
  ├── 1.5  graq plugins list runs without errors
  └── 1.6  git status clean (no uncommitted changes)

Phase 2: PyPI Publish (FIRST — everything else reads from PyPI)
  ├── 2.1  rm -rf dist/ && python -m build
  ├── 2.2  python -m twine upload dist/*
  ├── 2.3  VERIFY: pip install graqle==X.Y.Z (from a clean venv)
  └── 2.4  WAIT 60 seconds for PyPI CDN propagation

Phase 3: MCP Registry Publish (reads from PyPI)
  ├── 3.1  git tag vX.Y.Z && git push origin vX.Y.Z
  │         (triggers .github/workflows/publish-mcp-registry.yml)
  ├── 3.2  VERIFY: GitHub Actions workflow completes green
  └── 3.3  VERIFY: curl registry.modelcontextprotocol.io/v0.1/servers?search=graqle
           returns version X.Y.Z

Phase 4: Lambda Deployment (CI/CD — reads from GitHub)
  ├── 4.1  git push origin master triggers deploy-lambda.yml
  ├── 4.2  WAIT for CI/CD pipeline to complete
  └── 4.3  VERIFY: Lambda smoke tests pass

Phase 5: Manual Marketplace Updates (if needed)
  ├── 5.1  Glama.ai — auto-updates from GitHub (no action unless major changes)
  ├── 5.2  awesome-mcp-servers — update PR only for major features
  ├── 5.3  awesome-claude-code — update issue only for major features
  └── 5.4  mcp.so — re-submit only for major features
```

### Version Conflict Prevention

| Rule | Enforcement |
|------|-------------|
| Version MUST match in all 3 files | Pre-publish check (Phase 1.2) |
| PyPI MUST be published BEFORE MCP Registry | Sequential order enforced |
| `server.json` version MUST match PyPI version | Validated by MCP Registry on publish |
| `mcp-name` tag MUST be in README on PyPI | Validated by MCP Registry on publish |
| Bridge files MUST be included in wheel | `artifacts` config in pyproject.toml |
| Lambda timeout MUST stay >= 300s | deploy-lambda.yml config |
| CORS middleware MUST be skipped on Lambda | `app.py` checks `AWS_LAMBDA_FUNCTION_NAME` |

### Marketplace Registry

| Marketplace | Type | Update Mechanism | Namespace |
|-------------|------|------------------|-----------|
| **PyPI** | Package registry | `twine upload` (manual or CI) | `graqle` |
| **MCP Registry** | MCP server registry | GitHub Actions on `v*` tag (OIDC) | `com.graqle/graqle` |
| **awesome-mcp-servers** | GitHub awesome list | PR (manual) | Entry in README |
| **awesome-claude-code** | GitHub awesome list | Issue (manual, web UI only) | Entry in README |
| **Glama.ai** | MCP directory | Auto-syncs from GitHub | `quantamixsol/graqle` |
| **mcp.so** | MCP directory | Web form (manual) | Listing page |
| **PulseMCP** | MCP aggregator | Auto-ingests from MCP Registry | Auto |
| **Cline Marketplace** | VS Code extension marketplace | Issue + logo (manual) | Listing page |

### Authentication & Secrets

| Marketplace | Auth Method | Secret Location |
|-------------|-------------|-----------------|
| PyPI | Token | `~/.pypirc` (local) |
| MCP Registry (manual) | DNS + Ed25519 key | `mcp-registry-key.pem` (local, .gitignored) |
| MCP Registry (CI/CD) | GitHub OIDC | No secret needed — OIDC token from GitHub Actions |
| GitHub | gh CLI token | `gh auth` (local) |
| AWS (Lambda, Route 53) | AWS CLI credentials | `~/.aws/credentials` |
| Glama.ai | GitHub OAuth | Browser session |

### DNS Records for MCP Registry

| Record | Type | Value | Purpose |
|--------|------|-------|---------|
| `graqle.com` | TXT | `v=MCPv1; k=ed25519; p=7KH1wX7H8QAfa1zOhYA4Om+V9cA5ipS3RRumfv+/MgU=` | MCP Registry namespace ownership |
| `_mcp-verify.graqle.com` | TXT | `MCowBQYDK2VwAyEA7KH1wX7H8QAfa1zOhYA4Om+V9cA5ipS3RRumfv+/MgU=` | Legacy (can be removed) |

### Pre-Publish Checklist (copy-paste for every release)

```markdown
## Release vX.Y.Z Checklist

### Phase 1: Validation
- [ ] `pytest tests/ -x -q` — all pass
- [ ] Version matches in: pyproject.toml, __version__.py, server.json
- [ ] README has `<!-- mcp-name: com.graqle/graqle -->`
- [ ] `graq plugins list` — no errors
- [ ] `graq doctor` — no critical issues
- [ ] git status clean

### Phase 2: PyPI
- [ ] `rm -rf dist/ && python -m build`
- [ ] `python -m twine upload dist/*`
- [ ] Verify: https://pypi.org/project/graqle/X.Y.Z/
- [ ] Wait 60s for CDN

### Phase 3: MCP Registry
- [ ] `git tag vX.Y.Z && git push origin vX.Y.Z`
- [ ] GitHub Actions workflow green
- [ ] Verify: `curl registry.modelcontextprotocol.io/v0.1/servers?search=graqle`

### Phase 4: Lambda
- [ ] `git push origin master` (if not already pushed)
- [ ] CI/CD pipeline green
- [ ] Lambda smoke tests pass

### Phase 5: Announcements (major releases only)
- [ ] Update awesome-mcp-servers PR if needed
- [ ] Post on r/ClaudeAI, r/mcp if major feature
```

## Consequences

**Positive:**
- Version conflicts eliminated by sequential publish order
- MCP Registry auto-publishes on tag push (zero manual steps after Phase 2)
- PulseMCP auto-ingests from MCP Registry (cascading propagation)
- Bridge files are part of the PyPI package — every user gets them
- DNS-based namespace means `com.graqle/*` is permanently owned

**Negative:**
- Publishing takes ~5 minutes instead of instant (sequential order)
- Manual steps still required for some marketplaces (Glama, awesome-* lists)
- Ed25519 private key (`mcp-registry-key.pem`) must be kept safe — if lost, need to regenerate and update DNS

**Risks:**
- PyPI README cache: MCP Registry reads README from PyPI CDN, which may have a few-minute delay after upload
- GitHub Actions OIDC: if GitHub changes OIDC token format, CI/CD publish breaks (mitigate: DNS auth as fallback)
- Glama Docker build: if Glama requires a Docker image for score, we need to add a Dockerfile

---

## Launch Tracker (updated 2026-03-16)

| # | Platform | Status | Blocking On | Owner |
|---|----------|--------|-------------|-------|
| 1 | PyPI | LIVE v0.27.0 | — | Auto |
| 2 | MCP Registry | LIVE `com.graqle/graqle` | — | Auto on `git tag v*` |
| 3 | Glama.ai | SUBMITTED 2026-03-16 | Glama review (1-3 days) | Glama team |
| 4 | awesome-mcp-servers PR #3309 | OPEN — `missing-glama` label | Glama approval → add badge → label clears | Harish + Claude |
| 5 | awesome-claude-code | READY 2026-03-17 | 1-week repo age (March 17) | Harish (web UI) |
| 6 | mcp.so | NOT SUBMITTED | Nothing — submit anytime | Harish (web form) |
| 7 | PulseMCP | AUTO-INGESTING | Reads from MCP Registry | Auto |
| 8 | Cline Marketplace | NOT SUBMITTED | Need 400x400 logo | Harish (GitHub Issue) |
| 9 | Product Hunt | PLANNED | 4-6 week prep, logo, timing | Harish |
| 10 | Hacker News Show HN | PLANNED | Technical write-up | Harish |

### Dependency Graph
```
PyPI (done) → MCP Registry (done) → PulseMCP (auto)
                                   ↘ Glama (submitted, reviewing)
                                       ↘ awesome-mcp-servers PR (add badge)
awesome-claude-code (March 17, web UI)
mcp.so (anytime, web form)
Cline (needs logo)
Product Hunt (needs prep)
Hacker News (needs write-up)
```

---

## Related ADRs
- ADR-056: Lambda Function URL CORS (single source of truth)
- ADR-106: Gate+Rerank activation formula
- ADR-107: Staleness auto-recompile at commit time
