Releases: kouko/redshift-comment-mcp
Release list
v0.10.0 — get_setup_status reports inline mode truthfully
Fixes a false configured: false from the get_setup_status MCP tool when the server runs in legacy inline mode (the launch shape the Claude Code plugin UI uses: --host/--user/--dbname + REDSHIFT_PASSWORD env). The status tool now detects inline mode and adds a source: "inline" | "profile" field so agents can tell which config mechanism is live. The password value is never materialized in the response (presence-only bool).
See #39.
Pre-release: triggers TestPyPI smoke test. PyPI-live promotion follows after the dry-run goes green.
v0.9.0
v0.7.1 — v0.7.0 catch-up + workflow idempotency fix
🎯 In-band MCP setup — no log-spelunking, no restart
v0.7.1 is the catch-up release that ships v0.7.0's work to PyPI. The
v0.7.0 Pre-release attempt was blocked by two GitHub Actions workflow
quirks (TestPyPI CDN propagation lag + non-idempotent twine upload) that
made test-publish.yml fail spuriously. v0.7.0 was tagged on git and
uploaded to TestPyPI, but never reached PyPI — bumping to 0.7.1 with the
workflow fix (PR #35) is the cleanest path to a green ship, mirroring
the v0.4.0/v0.5.0 → v0.6.0 catch-up pattern.
v0.7.1 = v0.7.0 + workflow fix — functionally identical to v0.7.0
from the user perspective.
agent: list_schemas() → {"error": "not_configured", "exception_class": "ConfigurationError", "next_step": "Call setup_via_dialog..."}
agent: setup_via_dialog(host=..., user=..., dbname=...)
→ OS dialog appears, user types password
→ SELECT 1 against Redshift to verify
→ {"status": "configured", "tested": true}
agent: list_schemas() → works (lazy resolve, no restart)
✨ New MCP tools (11 → 13)
| Tool | What it does |
|---|---|
setup_via_dialog |
Bootstrap or update a profile in-session. Fields go via tool args (non-secret); password collected via OS-native dialog server-side (macOS osascript / Linux zenity). Tests connection against Redshift before declaring success. Returns one of 7 status codes covering happy path + dialog-cancelled / permission-denied / dialog-unavailable / platform-unsupported / empty-password / connection-failed. |
get_setup_status |
Read-only configuration check (no Redshift touch). Returns whether config.toml fields and keychain password exist; safely callable at session start; never returns the password value. |
🆕 Degraded-mode startup
Pre-v0.7.x: server crashed with ValueError("Profile 'default' is not configured...") if no profile existed. Agents had no in-band signal — they had to read ~/Library/Logs/Claude/mcp-server-*.log (client-specific path) to find the recovery hint.
v0.7.x:
- Server boots regardless of profile state — enters the MCP stdio loop and accepts tool calls
- DB tools return a structured
{"error": "not_configured", ...}response withnext_stepfield pointing atsetup_via_dialog - Lazy connection resolution: every tool call re-reads
config.toml+ keychain, so newly written profiles take effect without restarting the MCP client resolve_connection_paramsnow raisesConfigurationError(aValueErrorsubclass for backward-compat)
🔐 Password collection: OS dialog, never the wire
The same osascript / zenity discipline already used by the Claude Code /redshift-setup skill is now in the CLI + MCP tool:
| Subcommand / Tool | Password input |
|---|---|
redshift-comment-mcp set-password --dialog (CLI) |
macOS osascript / Linux zenity → keychain |
redshift-comment-mcp set-password --stdin (CLI) |
One line from stdin → keychain (headless / CI) |
setup_via_dialog (MCP tool) |
Same dialog mechanism via subprocess.run(capture_output=True) — Python str → keyring |
Password value path: user keyboard → OS dialog process stdout (in-pipe) → Python string in-process → keyring.set_password() → OS keychain. Never touches MCP wire, chat, Bash stdout, process args, or shell history.
🛡️ macOS Apple Events permission detection
v0.7.x distinguishes 3 macOS-specific osascript failure modes that pre-v0.7.x all collapsed to "user cancelled":
| Real situation | New status code | Agent guidance in message |
|---|---|---|
| User clicked Cancel button | dialog_cancelled |
Ask user whether intentional; default to retry |
| macOS Automation > System Events permission denied (error -1743) | permission_denied |
Open System Settings → Privacy & Security → Automation → enable System Events; or tccutil reset AppleEvents to force a fresh prompt |
| osascript binary not found | dialog_unavailable |
Fall back to set-password --stdin from terminal |
Detection uses the locale-stable numeric code (-1743) plus case-insensitive English text fallback ("Not authorized" / "Not authorised").
📋 Unified error-response schema
All four "this is broken" responses now carry the same field set so agents can pattern-match a single shape:
{
"error": "not_configured" | "write_profile_failed" | "keychain_write_failed" | "missing_field",
"exception_class": "ConfigurationError" | "PermissionError" | "KeyringLocked" | "ValidationError" | ...,
"message": "<sanitized agent-actionable text>"
}Per CWE-209 + OWASP Error Handling Cheat Sheet, raw str(exc) is not included for write_profile_failed / keychain_write_failed (third-party exception args may carry sensitive context). The exception class name is preserved as a separate field for diagnostic branching. Full exception detail is logged server-side with exc_info=True.
⚡ Connection test before declaring success
setup_via_dialog now runs SELECT 1 against Redshift after writing the profile + password. Catches host typos / VPN-not-connected / wrong password / firewall block / paused-cluster early — agent gets either {"status": "configured", "tested": true} or {"status": "configured_but_connection_failed", "connection_error": "..."} instead of a misleading "configured" followed by an immediate DB tool failure.
Failures are also logged server-side at WARNING level with profile + cluster coords + the underlying error, so operators can correlate transcript-reported issues with server log entries.
🤖 FastMCP instructions block updated
The handshake-time instructions= text now describes:
- The degraded-mode contract (server boots without profile)
- Both entry points: proactive
get_setup_statusat session start vs reactivenot_configuredon tool call - All response statuses agents need to handle, including
permission_deniedandconfigured_but_connection_failed
Agents see the recovery pattern BEFORE encountering an error, not just inside the error itself.
📚 Trilingual README updates
README.md / README.ja.md / README.zh-TW.md all updated with:
- Tool count 11 → 13 + new
setup_via_dialogandget_setup_statusrows - Code-agent bootstrap diagram showing the v0.7.x pure-MCP flow
- Fallback section for headless / no-GUI hosts (
--stdinpipe path)
🧪 Test coverage
| Tier | Before | After | New tests |
|---|---|---|---|
| Unit | 264 passed, 2 skipped | 299 passed, 2 skipped | +35 |
| Integration (live cluster) | 22 passed, 1 skipped | 22 passed, 1 skipped | unchanged shape |
| E2E (MCP wire) | 4 passed | 6 passed | +2 (setup_via_dialog wire registration + SETUP RECOVERY instructions handshake) |
Highlights:
test_bootstrap_then_use_end_to_end— the keystone scenario: server boots without profile → agent calls setup_via_dialog → next DB tool call works without restarttest_server_main_does_not_crash_when_no_profile— regression net against re-introducing upfront resolutiontest_every_db_tool_handles_not_configured— parametric over all 11 DB tools (catches missing@_guardedon new tools)test_get_setup_status_never_returns_password_value— hard security invariant; JSON-serializes response and scans for the password substringtest_collect_password_via_dialog_detects_permission_denied— parametric over realistic macOS stderr shapes (numeric, English, British spelling, lowercase, locale-translated)
🔧 Refactor + dev experience
RedshiftTools.__init__now takes aCallable[[], RedshiftConnectionConfig]provider instead of a built config — enables lazy re-resolution. 58 existingRedshiftTools(config)test call sites mechanically rewritten toRedshiftTools(lambda: config).@_guardeddecorator on all 11 DB tools centralizes theConfigurationError → not_configured responseconversion. Two new tools (setup_via_dialog,get_setup_status) deliberately skip the guard since they must run when no profile exists; documented inline + behaviorally tested.- 5 dialog-failure response builders extracted to module-level functions with a
_DIALOG_FAILURE_BUILDERSdispatch dict —setup_via_dialogbody shrinks from ~250 → ~164 lines.
🛠️ Release workflow fixes (v0.7.1 only — PR #35)
Two GitHub Actions workflow flaws surfaced by the v0.7.0 release attempt, fixed in v0.7.1:
test-publish.yml"Test installation from TestPyPI" step now retries pip install up to 6× with 30s backoff (3 min total) — absorbs the typical 1-3 min lag between TestPyPI's JSON API and its simple index (which pip uses).twine uploadnow uses--skip-existingin bothtest-publish.ymlandpublish.yml— re-runs are idempotent (no more 400 Bad Request on duplicate upload). Before this fix, any transient failure during the publish workflow corrupted the version slot until the next bump.
Forward-looking: future releases on the same workflows will not require version skipping just to retry.
📥 Install
# PyPI / generic MCP client
pip install --upgrade redshift-comment-mcp
# or
uvx redshift-comment-mcp
# Claude Code plugin
claude plugin install redshift-comment-mcppip install --upgrade from v0.6.0 lands directly on v0.7.1 (v0.7.0 is not on PyPI; see workflow fixes section above).
For multi-cluster claude_desktop_config.json / mcp.json examples and the in-band setup_via_dialog agent flow, see README §"Setting up with uvx".
🔗 Forward look: MCP Elicitation primitive
The MCP 2026-07-28 RC spec introduces an Elicitation primitive — a protocol-level mechanism for servers to request direct user input through the client's native UI. Once GA and FastMCP exposes it, the subprocess + osascript dialog hack here becomes obsolete: the server can request a password via the protocol and the client presents a native secure input widget. Documented in code at redshift_tools.py:1122-1140 so future maintainers know this is interim, not permanent architecture.
📊 External references grounding this release
- [CWE-2...
v0.7.0 — In-band MCP setup (degraded-mode + setup_via_dialog)
⚠️ Superseded — never reached PyPI, use v0.7.1 instead
This tag exists in git history and on GitHub Releases, but was never
published to PyPI. The v0.7.0 release attempt was blocked by two
GitHub Actions workflow flaws:
test-publish.yml's "Test installation from TestPyPI" step ran ~30s
after upload — TestPyPI's pip-facing simple index typically lags the
JSON API by 1-3 minutes, so pip couldn't see 0.7.0 yet and the step
failed spuriously.- The twine upload step wasn't idempotent (
--skip-existingmissing),
sogh run rerun --failedhitHTTPError: 400 Bad Requestfrom
the duplicate-version check.
The first failure was a cosmetic timing issue (TestPyPI actually had
0.7.0); the second made the workflow status permanently stuck on
"failed" with no clean recovery path. Bumping to 0.7.1 + fixing the
workflows (PR #35) was the cleanest path to a green ship — same
pattern as v0.4.0/v0.5.0 → v0.6.0.
Migration: install v0.7.1
or later. v0.7.1 is functionally identical to v0.7.0 from the user
perspective — only the publish workflows differ.
pip install --upgrade redshift-comment-mcp # → 0.7.1+
# or
uvx redshift-comment-mcp # → 0.7.1+The original v0.7.0 release notes are below for historical reference.
🎯 In-band MCP setup — no log-spelunking, no restart
v0.7.0 collapses the "code-agent provisions a Redshift profile" UX from
7 steps (with log-spelunking + Bash + MCP-client restart) down to
3 steps, pure MCP wire, no Bash needed. The server now boots even
without a configured profile and exposes a dedicated setup_via_dialog
tool that drives an OS-native password dialog server-side — password
never crosses chat / MCP wire / tool args.
agent: list_schemas() → {"error": "not_configured", "exception_class": "ConfigurationError", "next_step": "Call setup_via_dialog..."}
agent: setup_via_dialog(host=..., user=..., dbname=...)
→ OS dialog appears, user types password
→ SELECT 1 against Redshift to verify
→ {"status": "configured", "tested": true}
agent: list_schemas() → works (lazy resolve, no restart)
(Full v0.7.0 changelog identical to v0.7.1's notes minus the §"Release workflow fixes" section that's unique to v0.7.1.)
v0.6.0 — PyPI catch-up + code-agent uvx bootstrap
🎯 PyPI back in sync with the plugin path
First PyPI release since v0.3.0. The Claude Code plugin path shipped
v0.4.0 + v0.5.0 internally from cloned-repo source, but neither was
published to PyPI due to a release-trigger workflow bug — v0.6.0 rolls
up both prior releases plus the uvx UX work that promotes
uvx redshift-comment-mcp to a first-class install path for non-Claude-
Code MCP clients.
The new Release publishing (MUST) discipline (#31) + publish.yml
trigger fix (#33) close the gap that caused the silent v0.5.0
non-publication. v0.5.0 is intentionally skipped on PyPI; v0.6.0 is
its strict superset plus the UX work.
🤖 New in v0.6.0 — code-agent uvx bootstrap (#33)
uvx redshift-comment-mcp becomes truly stand-alone — no Claude Code
plugin required for first-time setup, and the password stays out of
chat / stdout via OS-native dialog.
| Subcommand | Purpose |
|---|---|
set-password --profile X --dialog |
macOS osascript / Linux zenity password dialog → keychain. Password never enters chat / stdout / argv. |
set-password --profile X --stdin |
Read one line from stdin → keychain (headless / CI use). Mutually exclusive with --dialog. |
server.py's "profile not configured" error messages now offer three
setup paths: Claude Code skill, code-agent pipeline (set-fields +
set-password --dialog), and human terminal (uvx redshift-comment-mcp setup). Before v0.6.0, the error only mentioned the Claude Code skill —
uvx-only users hit a dead-end message.
Trilingual README §"Setting up with uvx" now ships concrete
claude_desktop_config.json snippets (single-profile + multi-cluster)
plus the code-agent bootstrap pipeline (#32 + #33).
✨ New skills (rolled up from v0.4.0)
| Skill | One-liner | PR |
|---|---|---|
/redshift-grep-columns |
Cross-table column keyword search across one or all schemas | #24 |
/redshift-grep-tables |
Cross-schema table keyword search across the entire cluster | #24 |
/redshift-switch-profile |
Switch the active connection profile without re-entering host/user/password | #21 |
🆕 Other new features (v0.4.0 + v0.5.0)
execute_sqltransparency — response now includes_executed_sql
(the rewritten SQL the server actually ran) and_user_facing_message
(a shaped string the agent can show users) (#28).- Zero-config plugin install —
claude plugin installno longer
asks for a profile name. The MCP server reads an active-profile
pointer file written by/redshift-setup(#21, breaking, see
migration below).
⚡ Performance (rolled up from v0.4.0)
- Column metadata SQL: ~3.3x at 12K columns. Rewrote correlated-
subquery pattern to direct LEFT JOIN. Speedup persists at small N (#22). - Long-comment safety in multi-item responses.
MAX_COMMENT_LEN=1000
caps each comment with acomment_truncated_countmarker; single-item
getters never truncate (#23).
🐛 Bug fixes
- Single-profile upgrade rescue (v0.5.0) — pre-PR-22 installs whose
lone profile was not nameddefaultgot hard-broken by the active-
profile pointer file introduction.resolve_active_profilenow falls
back to the lone profile when exactly one exists; explicit
--profile/ env / pointer inputs still resolve verbatim so typos
surface as typos (#29). - uvx-only error UX (v0.6.0) — "no profile configured" error now
guides ALL setup paths, not just the Claude Code skill (#33). - Various skill bug fixes from functional-test pass (#19).
🏠 Housekeeping
- Removed
/redshift-cache-schema— cache layer retired in favor
of always-fresh catalog SQL + the new performance work (#26). - Live-cluster smoke gate.
REDSHIFT_INTEGRATION=1 pytest tests/integration/
exercises every MCP tool against a real Redshift cluster (#25). - New
tests/e2e/tier — MCP wire-protocol tests via stdio
subprocess (#28). - README install-link fix (#27).
⚠️ Breaking — Profile system contract (rolled up from v0.4.0, #21)
If you installed v0.3.0 directly via pip install redshift-comment-mcp:
- Profile pointer file is new.
~/.config/redshift-comment-mcp/active-profile
is now the source of truth for the active profile. Absence is no longer
an error — single-profile users get an implicit fallback (after #29). - Plugin manifest no longer asks for profile name. Anyone who
manually set a profile name via client config should switch to
--profile <name>to override the pointer file, or rely on
/redshift-setup+/redshift-switch-profile.
If your existing single profile is named anything other than default,
upgrading straight to 0.6.0 (not stopping at any 0.4.x / 0.5.0 point)
is the safe path — the single-profile fallback rescue (#29) is included.
🛠️ Release discipline (v0.6.0 internal)
CLAUDE.mdnow codifies the release-publishing flow as a hard
discipline (tag → Pre-release → flip-to-Release → PyPI), so the silent
non-publication that hit v0.4.0 + v0.5.0 doesn't recur (#31)..github/workflows/publish.ymltrigger gainsreleasedactivity
type, sogh release edit --prerelease=false(the Pre-release →
Release promotion) actually fires the workflow. v0.5.0 was the worked
example of this trigger gap — fixed forward in v0.6.0 (#33).
📥 Install
# PyPI / generic MCP client
pip install --upgrade redshift-comment-mcp
# or
uvx redshift-comment-mcp
# Claude Code plugin
claude plugin install redshift-comment-mcp📊 Full changelog
PRs in this release (v0.3.0…v0.6.0):
#19 · #20 · #21 · #22 · #23 · #24 · #25 · #26 · #27 · #28 · #29 · #30 ·
#31 · #32 · #33
v0.5.0 — PyPI catch-up: 3 new skills + execute_sql transparency + 3.3x perf
⚠️ Never reached PyPI — use v0.6.0 instead
This tag exists in git history and on GitHub Releases, but was never
published to PyPI. A publish.yml workflow trigger bug (gh release edit --prerelease=false fires the released event, not published)
caused the Pre-release → Release promotion to silently miss the publish
job. PyPI users went straight from v0.3.0 to v0.6.0.
Migration: install v0.6.0
or later. v0.6.0 is a strict superset of v0.5.0 and ships the trigger
fix forward so this can't recur.
pip install --upgrade redshift-comment-mcp # → 0.6.0+
# or
uvx redshift-comment-mcp # → 0.6.0+The original v0.5.0 release notes are below for historical reference.
🎯 PyPI back in sync with the plugin path
This is the first PyPI release since v0.3.0. The Claude Code plugin path
(claude plugin install, runs from cloned-repo source) shipped v0.4.0 +
v0.5.0 internally, but neither was tagged or released — so PyPI /
uvx redshift-comment-mcp users were stuck on v0.3.0 with no visible
signal. v0.5.0 rolls up both releases' worth of work plus a critical
post-release patch.
Per the new Release publishing (MUST) discipline (#31), this won't
happen again.
✨ New skills
| Skill | One-liner | PR |
|---|---|---|
/redshift-grep-columns |
Cross-table column keyword search across one or all schemas | #24 |
/redshift-grep-tables |
Cross-schema table keyword search across the entire cluster | #24 |
/redshift-switch-profile |
Switch the active connection profile without re-entering host/user/password | #21 |
🆕 New features
execute_sqltransparency — response now includes_executed_sql
(the actual rewritten SQL the server ran) and_user_facing_message
(a shaped string the agent can show users), so the user always knows
exactly what query hit Redshift (#28)- Zero-config plugin install —
claude plugin installno longer asks
for a profile name. The MCP server reads an active-profile pointer file
written by/redshift-setup. One-time/redshift-setup→ done
(#21, breaking, see migration below)
⚡ Performance
- Column metadata SQL: ~3.3x at 12K columns. Rewrote the correlated-
subquery pattern to a direct LEFT JOIN. Speedup persists at small N (#22) - Long-comment safety in multi-item responses.
MAX_COMMENT_LEN=1000
caps each comment with acomment_truncated_countmarker; single-item
getters never truncate. Prevents Claude Code's silent ~25K token cap
from clipping dbt-rich schemas (#23)
🐛 Bug fixes
- Single-profile upgrade rescue. PR #22 introduced the active-profile
pointer file with the contract "absent ↔ usedefault". Pre-PR-22
installs whose lone profile was not nameddefault(e.g.
ichef-prod) got hard-broken by the upgrade.resolve_active_profile
now falls back to the lone profile when exactly one exists; explicit
--profile/ env var / pointer file inputs still resolve verbatim so
typos surface as typos (#29) - Various skill bug fixes from functional-test pass (#19)
🏠 Housekeeping
- Removed
/redshift-cache-schema— cache layer retired in favor of
always-fresh catalog SQL + the new performance work above (#26) - Live-cluster smoke gate.
REDSHIFT_INTEGRATION=1 pytest tests/integration/
exercises every MCP tool against a real Redshift cluster (#25) - New
tests/e2e/tier — MCP wire-protocol tests via stdio subprocess (#28) - README install-link fix (#27)
⚠️ Breaking — Profile system contract (#21)
If you installed v0.3.0 directly via pip install redshift-comment-mcp:
- Profile pointer file is new.
~/.config/redshift-comment-mcp/active-profile
is now the source of truth for the active profile. Absence is no longer
an error — single-profile users get an implicit fallback (after #29). - Plugin manifest no longer asks for profile name. Anyone who manually
set a profile name via client config should switch to--profile <name>
to override the pointer file, or rely on/redshift-setup+/redshift-switch-profile.
If your existing single profile is named anything other than default,
upgrading straight to 0.5.0 (not stopping at any 0.4.x point) is the
safe path — the single-profile fallback rescue (#29) is included.
📥 Install
# PyPI / generic MCP client
pip install --upgrade redshift-comment-mcp
# or
uvx redshift-comment-mcp
# Claude Code plugin
claude plugin install redshift-comment-mcp📊 Full changelog
PRs in this release (v0.3.0…v0.5.0): #19 · #20 · #21 · #22 · #23 · #24 ·
#25 · #26 · #27 · #28 · #29 · #30
v0.3.0 — charter narrowing (BREAKING) + cache-as-LLM-layer + metadata trim
⚠️ Breaking changes
Two skills are removed in this release. Charter narrowed: skills exist
to help users do natural-language search and analysis of data;
artifact generation falls outside that scope.
| Removed | Why | Migration |
|---|---|---|
/redshift-erd |
Mermaid ERD generation is a visualization artifact, not chat-based search/analysis | Ask the LLM directly given catalog data from /redshift-explore or /redshift-cache-schema. Or use SchemaSpy / DBeaver / dbt-erd for serious ERD work |
/redshift-suggest-schema-yml |
dbt yaml drafting is artifact production for an external toolchain | Chain /redshift-profile output and ask the LLM "format this profile JSON as a dbt schema.yml models block" |
Final skill set (5): /redshift-setup, /redshift-explore,
/redshift-profile, /redshift-cache-schema, /redshift-lineage-from-stl.
🚀 Cache layer repurposed as LLM-internal lookup
/redshift-cache-schema switches role from human offline-browsing
artifact to an LLM-side metadata cache that other skills actually
consume.
- New file format: per-table
tables/<schema>__<table>.mdpreserving
multi-line markdown comments verbatim, plus lossy TSV indices
(_tables_index.tsv/_columns_index.tsv) for cross-cluster grep,
plus_meta.jsonfreshness gate (refreshed_at,ttl_hours,
complete: true|false). - Server instructions teach
CACHE PROTOCOL: agents prefer Reading
cache files over MCP round-trips whencomplete=trueand within TTL,
fall back to live MCP on miss with a chat hint to refresh. /redshift-exploreStep 0 +/redshift-profileStep 1 hook into the
cache-first path. Other consumer skills benefit automatically via the
server-level CACHE PROTOCOL.
Expected impact when cache is fresh: ~700 tokens saved + 99% latency
reduction per metadata query (Bash grep on TSV vs search_* MCP, or
single-file Read vs list_columns(include_comments=True)).
🔧 Metadata trim (system prompt — every conversation)
| Region | Before | After | Δ |
|---|---|---|---|
| 7 skill descriptions (now 5) | 6,291 | 2,635 | -58% |
| Server instructions | 2,711 | 1,356 | -50% |
| 11 tool docstrings | 3,281 | 1,296 | -60% |
| Total metadata burden | 12,283 | 5,287 | -57% / ~1,750 tokens / conversation |
Achieved via description-design.md principles
(WHAT + WHEN, not WHAT + WORKFLOW; keyword-belt multi-language triggers
instead of full sentences; no all-caps emphasis density;
deduplicated comment-authoritative rule from 4 places to 1).
📝 Known limits documented
Three-language READMEs now document Claude Code's
~25K token MCP response cap
(silent truncation, no error marker), the two mitigations this plugin
already applies (include_comments=False default + cache layer), and
the MAX_MCP_OUTPUT_TOKENS env-var override.
✅ Test protection: 98 → 142 tests
Three new test files catch the classes of bug encountered during this
refactor cycle:
| Tier | File | Tests | Catches |
|---|---|---|---|
| 1 | tests/test_repo_invariants.py |
19 | Skill ↔ command pairing breaks; YAML frontmatter invalid; description > 1024-char ceiling; dead skill references in markdown; pyproject.toml fallback_version vs plugin.json version drift; trilingual README parity |
| 2 | tests/test_cache_contract.py |
6 | _meta.json required-field documented; TSV index header column counts; column heading pattern; consumer ↔ producer cache-path alignment; server-level CACHE PROTOCOL present |
| 3 | tests/test_skill_descriptions.py |
20 | Each description has Use when / Triggers belt; third-person voice; no workflow recap; ~800-char soft ceiling |
All pure-function tests; run in <100 ms; require no AWS / MCP / DB.
🔐 SQL execute_sql validator (already in v0.2.2, unchanged here)
The validator changes from v0.2.2 (BOM-safe, string/comment-aware,
unterminated-literal rejection, 90.48% coverage gated at 85%) ship as-is
in this release.
📊 Changes Summary
| Area | Change |
|---|---|
| Charter | Skills narrowed to natural-language search/analysis; 2 artifact-generation skills removed |
| Cache | Repurposed as LLM-internal lookup layer with TTL gate + CACHE PROTOCOL |
| Metadata | 57% trim across skill descriptions, server instructions, tool docstrings |
| Tests | +44 tests (3 new files) covering repo invariants, cache contract, description quality |
🔄 Upgrade
pip install --upgrade redshift-comment-mcp
# or
pip install redshift-comment-mcp==0.3.0If you used /redshift-erd or /redshift-suggest-schema-yml, see the
migration notes above.
Full Changelog: v0.2.2...v0.3.0
🤖 Generated with Claude Code
v0.2.2
🚀 Claude Code Plugin Support
This release makes redshift-comment-mcp installable as a Claude Code plugin
with a one-shot conversational onboarding flow — no manual MCP server config
required.
/redshift-setupslash command (PR #9, refined in PR #13) — 4-question
conversational flow that configures a connection profile end-to-end. Default
form silently uses thedefaultprofile name;/redshift-setup <name>opts
into multi-cluster mode and auto-writes~/.claude/settings.json(with
BEFORE/AFTER preview)- Setup CLI
redshift-comment-mcp setup(PR #7) — same flow without the
conversational layer, for non-Claude-Code users - OS-aware password input (PR #9) — system password dialog when GUI is
available, TTY fallback otherwise - 6 MCP-composed skills + tri-lingual docs (EN / JP / 繁中) (PR #9):
/redshift-profile,/redshift-suggest-schema-yml,
/redshift-cache-schema,/redshift-erd,/redshift-explore,
/redshift-lineage-from-stl - Plugin runs from cloned repo source via
uv run --project(PR #7) —
no PyPI release required for plugin users (PyPI install path still supported)
🔐 SQL Security Hardening
execute_sql now stands up to a wider class of payloads. Two fixes shipped:
Expanded blocklist (PR #11). Added MERGE, GRANT, REVOKE, COPY,
UNLOAD to the forbidden-keyword list — covers Redshift upsert, ACL
mutation, and S3 import / export (data exfiltration surface even though
the latter doesn't "write to DB" in the strict sense).
Robust validator (PR #14). Reproduces a real failure where a valid
WITH ... SELECT query was rejected because of a transport-layer BOM
prefix breaking str.strip().startswith('WITH'). Now:
| Hardening | Effect |
|---|---|
| Strip BOM / ZWSP / ZWNJ / ZWJ / WJ / NBSP before startswith | No more false rejection on payloads with invisible prefixes |
Sanitize string literals, quoted identifiers, line / block / $$ comments before keyword scan |
No false positive on WHERE name = 'DELETE me' or -- DROP TABLE old |
| Reject unterminated string / comment / quoted identifier | Closes a potential bypass channel where an open literal could hide a forbidden keyword |
Validator extracted to validate_read_only_sql() module-level function |
Unit-testable without MCP plumbing |
29 new parametrized tests covering BOM / ZWSP / NBSP prefixes, string &
comment false-positives, multi-statement piggyback, and unterminated
literals. Validator module coverage at 90.48%, locked behind a CI gate
that fails the build below 85%.
🛠 Build & CI Robustness
fallback_versionfor plugin cache installs (PR #12) — Claude Code
clones plugins without.git, sosetuptools_scmhad nothing to read at
install time. Falls back to a static version string in that case- FastMCP 2.x ↔ 3.x compat in test helper (PR #8, refined in PR #14) —
_get_tool_fnnow tries publiclist_tools()first, falls back to private
_list_tools. Suite green on both lines - Pin
fastmcp>=2.11.0and addpytest-covto dev deps (PR #14) - Coverage gate on
redshift_tools.py(≥85%, currently 90.48%) (PR #14)
blocks regressions in security-critical code - Stale comment fix (PR #10) — removed inaccurate claim that startup
performs a connection test
📊 Changes Summary
| Area | Change |
|---|---|
| Plugin | Claude Code plugin packaging, /redshift-setup slash command + skill, setup CLI, 6 composed skills |
| Security | execute_sql blocklist expanded; validator now BOM-safe and string/comment-aware; bypass via unterminated literal closed |
| Build | setuptools_scm fallback_version for .git-less installs |
| Tests | FastMCP 3.x compat fallback; 29 new validator cases; CI coverage gate at 85% |
✅ Test Coverage
- 98 tests passing (was 52 in v0.2.0)
- 90.48% coverage on
redshift_tools.py, locked at 85% via CI gate - Python 3.10 / 3.11 / 3.12 matrix in CI
Full Changelog: v0.2.0...v0.2.2
🤖 Generated with Claude Code
Version 0.2.0
🚀 New Features
Search Tools Enhancements
search_schemas- New tool to search schemas by keywords (name or comment)hit_countranking - Search results now prioritize items matching more keywords- Results sorted by
hit_count DESC, name ASC hit_countfield included in response
- Results sorted by
List Tools Optimization
include_parent_commentsparameter - Control whether to fetch parent-level commentslist_tables: skip schema comment query whenFalselist_columns: skip table comment query whenFalse
include_commentsdefault changed toFalseforlist_tablesandlist_columns- Reduces unnecessary SQL queries
list_schemaskeeps defaultTrue
MCP Instructions Updated
- Added
search_schemasto recommended exploration flow - Emphasized keyword language should match user's conversation language
📊 Changes Summary
| Tool | Changes |
|---|---|
search_schemas |
New tool with hit_count ranking |
search_tables |
Added hit_count ranking |
search_columns |
Added hit_count ranking |
list_tables |
Added include_parent_comments, default include_comments=False |
list_columns |
Added include_parent_comments, default include_comments=False |
✅ Test Coverage
- 52 tests passing
- New tests for hit_count sorting (3 tests)
- New tests for
include_parent_commentsparameter
🤖 Generated with Claude Code
v0.1.1
🔧 修正與改進
Bug 修正
- SQL 關鍵字驗證修正:使用
\bregex 字元邊界檢查危險 SQL 關鍵字,避免誤擋含有關鍵字的欄位名稱(如last_update)
文件更新
- README 強化:新增完整的 MCP Client 本地開發設定說明
- 強調 Python 完整路徑的重要性
- 新增環境變數隱藏密碼的設定範例
- 說明更新原始碼後的操作流程
其他
- 新增
_version.py到.gitignore(setuptools-scm 自動生成檔案)
📥 安裝
pip install redshift-comment-mcp==0.1.1🔄 升級
pip install --upgrade redshift-comment-mcp