Skip to content

Add mz-sql-lsp Claude Code plugin - #32

Open
sjwiesman wants to merge 1 commit into
mainfrom
mz-deploy-plugin
Open

Add mz-sql-lsp Claude Code plugin#32
sjwiesman wants to merge 1 commit into
mainfrom
mz-deploy-plugin

Conversation

@sjwiesman

Copy link
Copy Markdown

Makes this repo a Claude Code plugin marketplace alongside the portable skills, and publishes the mz-deploy language server as its first plugin. Plugins cover capabilities the Agent Skills standard can't express — registering a language server is one.

/plugin marketplace add MaterializeInc/agent-skills
/plugin install mz-sql-lsp@materialize

The plugin declares the mz-deploy lsp server for .sql files and bundles an mz-sql-navigation skill, so agents reach for go-to-definition, hover, and workspace symbols instead of grepping an mz-deploy project.

What's here

File Purpose
.claude-plugin/marketplace.json Marketplace materialize, lists mz-sql-lsp
plugins/mz-sql-lsp/.claude-plugin/plugin.json LSP server declaration + userConfig
plugins/mz-sql-lsp/skills/mz-sql-navigation/SKILL.md Teaches agents to use LSP over grep
plugins/mz-sql-lsp/README.md Install, configuration, troubleshooting
.github/workflows/validate-plugins.yml claude plugin validate --strict matrix

Plus a Plugins section in README.md, and conventions and LSP constraints in AGENTS.md.

Configuration is required, by necessity

project_dir — the directory holding project.toml, relative to the repository root — is a required userConfig setting that Claude Code prompts for on enable.

There is no zero-configuration path, which is worth stating plainly: a userConfig default does not satisfy ${user_config.KEY} substitution. If the value is never set, the LSP server fails to load entirely:

Failed to load LSP servers for plugin mz-sql-lsp: Error: Plugin option
"project_dir" isn't set. Open /plugin manage to configure it

Two alternatives were tested and rejected:

  • Unset ${ENV_VAR} in workspaceFolder collapses to an invalid path. The server then dies with ENOENT ... posix_spawn 'mz-deploy' — which names the binary but is really a bad working directory, a misleading error to hand users.
  • A wrapper script discovering project.toml and passing -d doesn't work. The script resolved -d .../mz correctly and navigation still returned nothing: mz-deploy adopts the LSP rootUri as its project root and ignores the flag.

A static ${CLAUDE_PROJECT_DIR} works but silently returns "No definition found" for projects nested in a subdirectory, confirmed by a control run.

Verification

claude plugin validate --strict passes on both manifests. End to end against a real mz-deploy project via --plugin-dir, both layouts resolved a cross-file reference to the expected file and line:

Layout project_dir Result
project.toml at project root . ✅ resolved to base/base_catalog_extractor__mz_clusters.sql:1
Nested in a subdirectory mz ✅ resolved to mz/models/.../base_catalog_extractor__mz_clusters.sql:1

Bundled skill loads; zero LSP errors in the debug log.

Notes for review

  • The marketplace is named materialize because agent-skills is reserved for Anthropic.
  • The documented metadata.pluginRoot shorthand fails validation, so plugin sources use the explicit ./plugins/{name} form.
  • ENABLE_LSP_TOOL is not required — the LSP tool is on by default.
  • default: "." is kept on the assumption it prefills the enable-time prompt. That was not verified (the prompt is interactive); if it doesn't prefill, it's dead weight and should be removed.
  • CI validates manifests only. Runtime behavior needs a real project and was verified by hand.

Out of scope: the mz-deploy CLI skill, and migrating consumers off local marketplace definitions.

🤖 Generated with Claude Code

Makes this repo a Claude Code plugin marketplace alongside the portable
skills, and publishes the mz-deploy language server as its first plugin.
Plugins cover capabilities the Agent Skills standard cannot express;
registering a language server is one.

The plugin declares the `mz-deploy lsp` server for `.sql` files and bundles
an mz-sql-navigation skill so agents reach for go-to-definition, hover, and
workspace symbols instead of grepping an mz-deploy project.

`project_dir` is a required userConfig setting naming the directory that
holds project.toml. A userConfig `default` does not satisfy
`${user_config.KEY}` substitution, so an unset value fails the server load
outright rather than falling back — there is no zero-configuration path.
Two alternatives were tested and rejected: an unset `${ENV_VAR}` collapses
workspaceFolder to an invalid path and reports a misleading ENOENT against
the binary, and a wrapper script passing `-d` cannot help because mz-deploy
adopts the LSP rootUri as its project root and ignores the flag.

Verified end to end against a real mz-deploy project in both layouts,
project.toml at the root and nested in a subdirectory, with go-to-definition
resolving to the expected file and line. The marketplace is named
`materialize` because `agent-skills` is reserved for Anthropic.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@sjwiesman
sjwiesman marked this pull request as ready for review July 29, 2026 17:46
@sjwiesman
sjwiesman requested a review from bosconi July 29, 2026 17:46

@bosconi bosconi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool. A couple of small edits.


Registers the `mz-deploy` language server for `.sql` files so Claude Code's LSP tool can
resolve go-to-definition, hover, and document/workspace symbols across an
[mz-deploy](https://materialize.com/docs/) project.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[mz-deploy](https://materialize.com/docs/) project.
[mz-deploy](https://materialize.com/docs/manage/mz-deploy/) project.

Comment thread AGENTS.md

Learned by testing; they are easy to get wrong because the docs don't state them.

- A `userConfig` `default` does **not** satisfy `${user_config.KEY}` substitution. If the user never sets the value, the LSP server fails to load entirely. There is no zero-configuration fallback — treat any `${user_config.*}` reference in an LSP config as a required setting and document it as such.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- A `userConfig` `default` does **not** satisfy `${user_config.KEY}` substitution. If the user never sets the value, the LSP server fails to load entirely. There is no zero-configuration fallback — treat any `${user_config.*}` reference in an LSP config as a required setting and document it as such.
- A `userConfig` `default` does **not** satisfy `${user_config.KEY}` substitution. If the user never sets the value, the LSP server fails to load. There is no zero-configuration fallback — treat any `${user_config.*}` reference in an LSP config as a required setting and document it as such.

"fails to load entirely." makes me think there is such a thing as loading partially, which presumably is not the case.

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.

2 participants