setup-metals-mcp
Skill3 starsChanged 34 days agoMITView on GitHub
Configures metals-mcp for the current Scala project so it works identically in the Claude Code CLI and in "Code" inside the Claude Desktop app. Writes a committed self-locating wrapper script plus a machine-local .mcp.json. Use when the user wants to add metals-mcp to a project, says "setup metals-mcp", "add metals-mcp config", "configure metals-mcp here", or is in a Scala project and asks to wire up any metals MCP integration.
In this repository8 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- 2020-hindsight-scalaSkill
- centralize-ai-outputSkill
- gen-motion-graphicsSkill
- pr-analysisSkill
- riper-5Skill
- setup-serena-mcpSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 1 is distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 23
When Claude Code runs embedded in the Claude Desktop app, it launches stdio MCP servers with cwd = $HOME instead of the project root.
- Very specific: line 77
Write .claude/metals-mcp.sh with the wrapper above.
- Very specific: line 79
Read/parse .mcp.json if it exists (start from {"mcpServers": {}} otherwise).
- Distinctive: line 82
Write back with 2-space indentation and a trailing newline.
- Very specific: line 84
Ensure .mcp.json is gitignored: if <project>/.gitignore doesn't already ignore it, append a .mcp.json line.
- Very specific: line 104
If a global metals-mcp entry exists in ~/.claude.json with no --workspace, it conflicts (fails with --workspace is required).
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
setup-metals-mcp
Configures metals-mcp for the current Scala project so the same setup works in both:
- the Claude Code CLI (
claudein a terminal), and - "Code" inside the Claude Desktop app (embedded Claude Code — same engine as the CLI).
This does not target the Claude Desktop app's plain chat (that reads a separate global
claude_desktop_config.json and has no project concept). This skill is only about Claude Code's
project-level .mcp.json.
Why a wrapper script instead of $PWD
metals-mcp needs the absolute workspace path (--workspace); it does not auto-detect the project.
The obvious approach — sh -c 'metals-mcp --workspace "$PWD" ...' — is not reliable, because
of a confirmed open bug (claude-code#75266):
- When Claude Code runs embedded in the Claude Desktop app, it launches stdio MCP servers with
cwd = $HOMEinstead of the project root. So$PWD(and any relativecommandpath) resolves to the home directory, and metals opens the wrong workspace. The CLI is unaffected, but we want one config that works in both. ${CLAUDE_PROJECT_DIR}does not help in thecommand/argsposition: Claude Code does not populate it in the server-launch environment there.claude mcp listreportsMissing environment variables: CLAUDE_PROJECT_DIRif you try. (Verified against Claude Code 2.1.x.)
The robust fix is a self-locating wrapper script committed inside the project. The wrapper
derives the project root from its own on-disk location, which is independent of the launcher's
cwd — so it computes the correct --workspace in both the CLI and the embedded app. The only piece
that must be cwd-independent is the path to the wrapper itself, so .mcp.json points at it by
absolute path (see the portability note below).
Files this skill manages
<project>/.claude/metals-mcp.sh— committed, portable, self-locating wrapper.<project>/.mcp.json— machine-local (absolute path inside), gitignored, regenerated per machine by re-running this skill.<project>/.gitignore— ensure.mcp.jsonis ignored.
Wrapper script: .claude/metals-mcp.sh
POSIX sh, no readlink -f (BSD readlink on older macOS lacks -f); uses pwd -P to resolve
the script's directory:
#!/bin/sh
# Self-locate the project root from this script's own path, independent of cwd.
# .claude/metals-mcp.sh -> project root is one level up from .claude/
scriptdir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)
root=$(CDPATH= cd -- "$scriptdir/.." && pwd -P)
exec metals-mcp --workspace "$root" --transport stdio--transport stdio is still required: metals-mcp defaults to HTTP (Undertow) and Claude Code
expects stdio (it times out after 30s otherwise).
.mcp.json entry (absolute command)
The skill fills in the real absolute path to the wrapper at run time:
"metals-mcp": {
"type": "stdio",
"command": "/absolute/path/to/project/.claude/metals-mcp.sh"
}Steps
- Determine the absolute path of the current project root (the directory
.mcp.jsonwill live in). - Write
.claude/metals-mcp.shwith the wrapper above. Create.claude/if needed.chmod +xit. - Read/parse
.mcp.jsonif it exists (start from{"mcpServers": {}}otherwise). SetmcpServers["metals-mcp"]to the entry above with the absolute wrapper path filled in. Preserve all othermcpServersentries; overwrite an existingmetals-mcpentry and note it. Write back with 2-space indentation and a trailing newline. - Ensure
.mcp.jsonis gitignored: if<project>/.gitignoredoesn't already ignore it, append a.mcp.jsonline. (The wrapper under.claude/stays committed — it's portable.) - Tell the user:
- That
.claude/metals-mcp.sh(portable, commit it) and.mcp.json(machine-local, gitignored) were written, and that teammates/other machines re-run this skill once to generate their own.mcp.json. - To restart their Claude Code session (CLI) or reopen the "Code" panel in Desktop for the change to take effect.
- That this works in both the CLI and "Code" in the Desktop app, but not Desktop plain chat.
- That
Notes
- Requires metals-mcp v1.6.7+ (
cs install metals-mcpvia Coursier) and Java on PATH. Because the embedded app launches with a minimal environment, if metals-mcp can't findjava, addJAVA_HOME/PATHvia anenvblock on the.mcp.jsonentry, or set them inside the wrapper. - Why absolute path in
.mcp.json(and hence gitignored): the path to the wrapper must not depend on cwd, or bug #75266 breaks the embedded app. An absolute path is the only cwd-independent way to find the wrapper; the wrapper itself is portable and committed. The.mcp.jsonis cheap to regenerate — just re-run this skill. - If a global metals-mcp entry exists in
~/.claude.jsonwith no--workspace, it conflicts (fails with--workspace is required). Suggest:claude mcp remove --scope user metals-mcp.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

