feat(mcpb): companion Desktop Extension — Claude Desktop config form#38
Merged
Conversation
Thin bundle entry point: build_argv() maps the form-injected REDSHIFT_* env vars into the server's inline-mode CLI flags; password stays in REDSHIFT_PASSWORD env. Server package unchanged (adapter lives in the bundle). Part of the companion .mcpb (server.type uv). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Generates mcpb/manifest.json (manifest_version 0.4, server.type uv, user_config form + ${user_config.*} env injection) + bundle pyproject (pins redshift-comment-mcp==<root version>) + .mcpbignore. Version single-sourced from pyproject; generated files gitignored (CI regenerates before mcpb pack).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…angs) Adds the Claude Desktop .mcpb path (download from Releases → install → fill form; needs uv) alongside the plugin path; clarifies install ONE of plugin (skills) OR .mcpb (desktop form). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Runs the generator into a tmp dir and asserts manifest version == pyproject fallback_version == plugin.json version. The .mcpb is a 4th version surface but auto-derived, so this guards against drift. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New pack-mcpb job (needs: publish, prerelease==false): generate manifest → npx @anthropic-ai/mcpb pack → softprops upload to the release. Runs after PyPI publish so the bundle-pinned version exists. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
brainstorm→plan for the Claude Desktop .mcpb (server.type uv); spike PASSED (form+injection+connect); decision: assume uv prereq, no bundling/signing. See also the surface-difference finding (plugin userConfig ≠ desktop form). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a companion
.mcpbDesktop Extension (alongside the existing Claude Code plugin) so Claude Desktop / Cowork users get a Tableau-style connection config form in the Connectors panel — no terminal, no JSON, password → OS keychain.Server package code is unchanged — the bundle reuses the server's existing inline mode via a thin adapter.
Why
The existing Claude Code plugin's
userConfigdoes not render as a form in the Claude Desktop Connectors panel (empirically confirmed — it shows raw config). Only a.mcpbDesktop Extension (like Tableau MCP) renders the form there.pluginand.mcpbare separate artifacts (a.mcpbcan't ship skills), so this is a companion — users install one of: the plugin (for skills) or the.mcpb(for the desktop form).How it works (spike-validated end-to-end on real Claude Desktop)
server.type: "uv"→ no dependency bundling (deps from PyPI viauv); requiresuvon the user's machine.mcp_config.env(ignorescommand/argsfor uv-type), so the 5 form fields inject asREDSHIFT_*env via${user_config.X}.mcpb/server/main.py(adapter) maps those env vars → the server's inline-mode CLI flags; password stays inREDSHIFT_PASSWORDenv (never in argv).list_schemasconnects ✅.Changes
mcpb/server/main.py— env→argv adapter (build_argv), lazy server import.scripts/generate_mcpb_manifest.py— generatesmcpb/manifest.json(manifest_version 0.4, server.type uv,user_configform, env injection) + bundlepyproject.toml(pinsredshift-comment-mcp==<root version>) +.mcpbignore. Version single-sourced from pyproject; generated files gitignored (CI regenerates before pack).tests/test_mcpb_adapter.py,tests/test_mcpb_manifest.py— TDD coverage.tests/test_repo_invariants.py— invariant: generated manifest version == pyproject == plugin.json (no drift)..github/workflows/publish.yml— newpack-mcpbjob (needs: publish): generate →mcpb pack→ attach.mcpbto the GitHub Release..mcpbinstall path +uvprereq + "install one of".Verification
Post-merge (separate, manual)
After merge, cut a v0.9.0 GitHub Release → fires
publish.yml(publishes 0.9.0 to PyPI — fixing the standing gap where PyPI is stuck at 0.7.1) → the newpack-mcpbjob packs + attaches the.mcpb. Bundle-pin ↔ PyPI consistency holds because publish runs before pack.🤖 Generated with Claude Code