Java development skills for AI coding agents. Works with Claude Code and kiro-cli;
skills are plain SKILL.md directories, so the same content serves both.
Skills install by default and switch themselves off when their prerequisite is
missing: a SessionStart hook checks each skill's dependency and, when it is
unreachable, sets Claude Code's skillOverrides to off so the skill stops loading.
The moment the dependency comes back, the same hook removes the override. Nothing is
deleted, and an override you set yourself is never touched.
git clone https://github.com/ebasanez/java-dev-ai-plugin.git
cd java-dev-ai-plugin
./install.shThe installer:
- detects which agent is running (env vars, process tree), which are installed
(
claude/kiro-clion PATH,~/.claude,~/.kiro) and which the project uses (.claude/,CLAUDE.md,.kiro/) — asking only when several apply; - runs each skill's pre-install check and shows the result;
- asks whether to install it (default yes for skills with
defaultAnswer: true); - copies the skill into the agent's skills directory;
- offers to register any MCP server the check discovered.
A failed pre-install check warns but does not stop the installation
(checkIsBlocking: false in plugin.manifest.json).
| Flag | Meaning |
|---|---|
--agent claude-code|kiro-cli|both |
skip agent detection |
--scope user|project (--user / --project) |
~/.claude, ~/.kiro vs ./.claude, ./.kiro (default: user) |
--with <id> / --without <id> |
answer an optional skill without prompting |
--yes, -y |
non-interactive; use defaultAnswer from the manifest |
--no-mcp |
never offer MCP registration |
./uninstall.sh removes only the skills listed in the manifest (--purge also
deletes .bak.* backups). MCP registrations are left in place.
| Agent | User scope | Project scope |
|---|---|---|
| Claude Code | ${CLAUDE_CONFIG_DIR:-~/.claude}/skills/<id> |
./.claude/skills/<id> |
| kiro-cli | ${KIRO_HOME:-~/.kiro}/skills/<id> |
./.kiro/skills/<id> |
/plugin marketplace add ebasanez/java-dev-ai-plugin
/plugin install java-dev-ai-plugin@java-dev-ai-plugin
/plugin marketplace add also accepts the full clone URL
(https://github.com/ebasanez/java-dev-ai-plugin.git) or a local checkout path.
This installs every skill (they live in skills/, which Claude Code auto-loads) and
registers the SessionStart hook that enables/disables them per session. No further
step is needed for Claude Code — install.sh is for kiro-cli, for non-plugin installs,
and for registering the MCP server.
The plugin ships .mcp.json at its root, which Claude Code reads on install — so the
IDE's MCP server is registered for you and execute_tool is available without any
claude mcp add:
{
"mcpServers": {
"intellij-idea": { "type": "http", "url": "http://127.0.0.1:64342/stream" }
}
}64342 is the first port an IntelliJ-based IDE takes; a second IDE lands on 64343 and so on, and the port is not configurable (IJPL-207839). If yours differs, copy the exact URL from Settings | Tools | MCP Server and either edit this file or register the server yourself — the status line names whichever config file it found.
These are the values IntelliJ's own Auto-Configure writes, and streamable HTTP is the only transport a plain script can drive, so it is what the probe prefers.
The probe only ever touches the MCP transport endpoints: /stream (reported as
http), then /sse (reported as sse). It deliberately never calls the legacy
/api/mcp/list_tools — current IDEs do not serve it, and all IDE work goes through
execute_tool anyway. A server offering only that endpoint is treated as not found.
What the probe found drives registration, so install.sh passes the matching
--transport (IDEA_MCP_URL / IDEA_MCP_TRANSPORT override both).
Keep exactly one entry for the IDE. Running Auto-Configure on a project adds its own
server (named idea) pointing at the same port — two registrations of one IDE means
its whole toolset is loaded twice into context every turn.
Start Claude with --plugin-dir-no-mcp to make the engine ignore this file entirely.
kiro-cli does not read a plugin's .mcp.json, and neither does a plain git clone +
./install.sh — so the installer registers the server itself, whether or not an IDE
is running. With one detected it uses the probed endpoint and transport; with none it
falls back to the values in this .mcp.json, so the registration is simply inert until
the IDE starts. It skips agents where the server name is already registered, so running
it alongside a plugin install does not create duplicates.
The hook (hooks/session-start-mcp-check.sh) runs each skill's preinstallCheck and:
| Check result | Action |
|---|---|
| fails | skillOverrides["java-dev-ai-plugin:<skill>"] = "off" — the skill stops loading and stops costing context |
| passes | that override is removed — the skill comes back |
It then reports the current state at every session start:
java-dev-ai-plugin status:
IntelliJ IDEA MCP server: available at http://127.0.0.1:64342/stream (http transport, tool count unknown until a session opens)
IntelliJ IDEA MCP tooling: loaded - MCP server 'intellij-idea' is registered in <plugin>/.mcp.json, so execute_tool is callable
Skill intellij-idea-mcp-helper: loaded
The three lines are independent: the IDE can be up while its MCP server is not
registered with the agent (so execute_tool is missing), and the skill can be loaded
while the IDE is down. A line only ends in - disabled just now / - re-enabled just now when this run actually changed something.
The report is emitted as hook JSON — systemMessage so you see it in the UI, and
hookSpecificOutput.additionalContext so the model knows the state too. Plain
stdout from a SessionStart hook only ever reaches the model, which is why the status
would otherwise appear to be missing.
Rules it follows:
- it only ever changes overrides it wrote itself (tracked in
${XDG_STATE_HOME:-~/.local/state}/java-dev-ai-plugin/); an override you set by hand, or edited afterwards, is left alone; - it writes to
.claude/settings.local.jsonin the project — the same file/skillsuses; - it reads MCP registration from
.mcp.json,~/.claude.jsonand the agent'ssettings.jsondirectly, rather than shelling out toclaude mcp get; - probe results are cached for 60s so back-to-back sessions do not re-probe.
| Variable | Effect |
|---|---|
JDAP_OVERRIDE_SCOPE |
local (default), project or user settings file |
JDAP_DISABLED_VALUE |
off (default), name-only, or user-invocable-only |
JDAP_PROBE_CACHE_TTL |
probe cache lifetime in seconds (default 60) |
To opt out permanently, set the override yourself — the hook will then keep its hands off:
{ "skillOverrides": { "java-dev-ai-plugin:intellij-idea-mcp-helper": "off" } }kiro-cli has no equivalent setting, so there "disabled" means simply not copying the
skill in (install.sh --without <id>, or uninstall.sh).
Routes Java-semantic work to a running IntelliJ IDEA MCP server instead of grep/sed: renaming a Java element, semantic/symbol search, detecting file errors, linting/reformatting a file, and listing project dependencies or modules.
Requires IntelliJ IDEA 2025.2+ with Settings | Tools | MCP Server enabled (earlier versions can use the JetBrains MCP Server plugin).
Install check. scripts/probe_mcp.sh looks for the IDE on ports 64342-64352,
then 63342 and 6365, on 127.0.0.1 and — under WSL — the default gateway. Not
finding one is only a warning; the skill installs and stays inert until an IDE is up.
Tool resolution. The bundled reference.md maps intents to tool names and their
expected arguments. It is explicitly marked as approximate: names drift between IDE
versions and depend on Exposed Tools, and there is no HTTP endpoint to enumerate
them — current IDEs do not serve /api/mcp/list_tools, so nothing here calls it.
When a call is rejected, the IDE's own error message is the authority.
Invocation. Everything goes through the router — no direct tool calls:
execute_tool(
command: "rename_refactoring --pathInProject src/main/java/com/example/Foo.java --symbolName Foo --newName Bar",
projectPath: "/abs/path/to/project"
)
Environment overrides
| Variable | Effect |
|---|---|
IDEA_MCP_HOST |
host to probe first (needed when the IDE runs on Windows and the agent in WSL) |
IDEA_MCP_PORT / IDE_PORT |
port to probe first |
IDEA_MCP_URL |
exact URL to register with the agent |
IDEA_MCP_TRANSPORT |
http (default) or sse, overriding what the probe detected |
IDEA_MCP_BUDGET |
probe wall-clock budget in seconds (default 6) |
- Create
skills/<id>/SKILL.md(frontmatter limited tonameanddescriptionso both agents parse it). - Add an entry to
plugin.manifest.json:
{
"id": "<id>",
"path": "skills/<id>",
"optional": true,
"defaultAnswer": true,
"summary": "one line shown at the install prompt",
"preinstallCheck": "skills/<id>/scripts/check.sh",
"checkIsBlocking": false,
"mcpServerName": "<name>",
"skillOverrideKey": "java-dev-ai-plugin:<id>",
"autoDisableWhenCheckFails": true
}| Field | Effect |
|---|---|
preinstallCheck |
must exit 0 when satisfied and print one line of JSON |
checkIsBlocking |
true aborts the install when the check fails; false only warns |
mcpServerName |
with a baseUrl in the check's JSON, enables the MCP registration offer |
autoDisableWhenCheckFails |
the SessionStart hook manages this skill's skillOverrides entry |
skillOverrideKey |
the settings key to write (defaults to the bare skill id) |
Omit autoDisableWhenCheckFails for skills with no external dependency — they then
stay loaded unconditionally.
./tests/run_all.shSyntax-checks every script, then runs detection, probe and install tests
against a fake IDE MCP endpoint (tests/fake_ide.py) and a temporary HOME.