Skill v1.0.2
currentAutomated scan100/100~2 modified
version: "1.0.2"
IntelliJ API Power User Guide
RECOMMENDED: Execute Kotlin code directly in IntelliJ IDEA's runtime with full access to IntelliJ Platform APIs.
MCP Steroid - IDE API Access for AI Agents
Execute Kotlin code directly in IntelliJ IDEA's runtime with full access to the IntelliJ Platform API.
Important Notes for AI Agents
Learning Curve: Writing working code for IntelliJ APIs may require several attempts. This is normal! The API is vast and powerful. Keep trying - each attempt teaches you more about the available APIs. Use printException() to see stack traces when errors occur.
Drop-in replacement for LSP: This MCP server replaces LSP (Language Server Protocol) tools with IntelliJ's native APIs — same operations, deeper understanding:
- PSI (Program Structure Interface) instead of LSP document symbols — full semantic analysis
- IntelliJ inspections, refactorings, intentions instead of LSP code actions
- Full project model with module dependencies instead of workspace folders
- Platform-specific indices for O(1) code search instead of filesystem scans
Common task → resource cheat sheet
Before reading further, if your task matches one of these, skip straight to the linked recipe:
| Task | Fetch this | |
|---|---|---|
| Find duplicate / cloned / DRY-violation / copy-paste code | mcp-steroid://ide/find-duplicates | |
| Run a single named inspection + apply quick-fix | mcp-steroid://ide/inspect-and-fix | |
| List enabled inspections in the project | mcp-steroid://ide/inspection-summary | |
| Multi-file literal-text edit | one steroid_execute_code script: read + replace + save all files in a single writeAction { } | |
| Find usages of a symbol | mcp-steroid://lsp/find-references | |
| Find every direct/indirect subtype or implementor | mcp-steroid://ide/type-hierarchy | |
| Run / debug a test | mcp-steroid://ide/demo-debug-test | |
| Run Maven / Gradle tests | mcp-steroid://skill/execute-code-maven, mcp-steroid://skill/execute-code-gradle | |
| API discovery / exploration | continue reading this guide |
The full index is in the "MCP Resources (Use Them)" section below.
Quickstart Flow
1. steroid_list_projects → get list of open projects2. Empty on a clean machine? Run `devrig backend download --json`, install the required product, thencall steroid_open_project. It auto-starts a sole installed backend; no separate start is required.3. Poll steroid_list_projects until the path appears, then pick its `project_name` (the unique routingkey — NOT the human-readable `name`). Do not reuse a key from before an IDE/project restart.4. On a first Maven/Gradle open, fetch `mcp-steroid://skill/execute-code-maven` or`mcp-steroid://skill/execute-code-gradle`, then trigger and await external-system configuration exactlyas that recipe shows.5. steroid_execute_code → run Kotlin code with that project_name6. steroid_execute_feedback → report success/failure for tracking
For unattended Java/JVM work on 2026.2, install IDEA Ultimate with a pinned 2026.2 version. devrig launches it as a frontendless Remote Development backend with MCP Steroid included, so a window or screenshot is not a readiness requirement. Full lifecycle details: mcp-steroid://open-project/managing-backends (fetch it after steroid_list_projects supplies a project_name).
Each steroid_list_projects entry has TWO name fields: project_name (the within-IDE-unique, opaque routing KEY you pass back to every project-scoped tool) and name (the human-readable folder name, informational/display only). Always route by project_name. To find the right project for a file or directory path, pick the project whose path is the longest prefix of your target path (this disambiguates nested checkouts and git worktrees).
Example session:
→ steroid_list_projects← {"projects":[{"project_name":"my-app-9fk2a0xq","name":"my-app","path":"/path/to/my-app","backend_name":"iu-9fk2a0xq"}],"backends":[{"backend_name":"iu-9fk2a0xq","intellij":{"name":"IntelliJ IDEA 2026.1.3","version":"2026.1.3","build":"IU-261.25134.95"}}]}→ steroid_execute_code(project_name="my-app-9fk2a0xq", code="println(project.name)", ...)← "my-app"→ steroid_execute_feedback(project_name="my-app-9fk2a0xq", task_id="...", execution_id="...", success_rating=1.0, explanation="Got project name")
When to Use This Skill
ALWAYS prefer IntelliJ APIs over file-based operations:
| Instead of... | Use IntelliJ API | |
|---|---|---|
Reading files with cat/read | VFS and PSI APIs | |
Searching with grep/find | Find Usages, Structural Search | |
| Manual text replacement | Automated refactorings | |
| Guessing code structure | Query project model directly |
The IDE has indexed everything. It knows the code better than any file search.
Available Tools
steroid_list_projects
List all open projects. Each entry has project_name (the unique routing key to pass to steroid_execute_code and the other project-scoped tools), name (the human-readable folder name, informational only), and path. To map a file/dir path to a project, pick the project whose path is the longest prefix of your target path.
steroid_list_windows
List open IDE windows (and background tasks) and their associated projects. Some windows may not be tied to a project and a project can have multiple windows. Use this in multi-window setups to pick the correct window_id for screenshot/input tools. Each window and task entry references its project by project_name — the single routing key. Look up that project's human-readable name and path via steroid_list_projects by that key (they are not duplicated on window/task entries).
steroid_take_screenshot
Capture a screenshot of the IDE frame and return image content.
HEAVY ENDPOINT: Use only for debugging and tricky configuration. Prefer steroid_execute_code for regular automation.
Parameters:
project_name(required): theproject_namefromsteroid_list_projects(a unique routing key, NOT the raw folder name)task_id(required): Task identifier for loggingreason(required): Why the screenshot is neededwindow_id(optional): Window id fromsteroid_list_windowsto target a specific window
Artifacts (saved under the execution folder):
screenshot.pngscreenshot-tree.mdscreenshot-meta.json
The response includes window_id (also stored in screenshot-meta.json); pass it to steroid_input to target the same window. window_id is also returned by steroid_list_windows.
steroid_input
Send input events (keyboard + mouse) using a sequence string.
HEAVY ENDPOINT: Use only for debugging and tricky configuration. Prefer steroid_execute_code for regular automation.
Parameters:
project_name(required): theproject_namefromsteroid_list_projects(a unique routing key, NOT the raw folder name)task_id(required): Task identifier for loggingreason(required): Why the input is neededwindow_id(required): Window id fromsteroid_list_windows(also returned bysteroid_take_screenshot)sequence(required): Comma-separated or newline-separated input sequence (commas inside values are allowed unless they look like, <step>:; commas are optional when using newlines)
Sequence examples:
stick:ALT, delay:400, press:F4, type:hurraclick:CTRL+Left@120,200click:Right@screen:400,300
Notes:
- Comma separators are detected by
, <step>:patterns, so avoid typing, delay:etc in text. - Trailing commas before a newline are ignored.
- Use
#for comments until the end of the line. - Targets default to screenshot coordinates; use
screen:for absolute screen pixels. - Input focuses the screenshot window before dispatching events.
steroid_execute_code
Execute code with IntelliJ's brain, not just text files.
Give your AI agent a senior developer's toolkit: semantic code understanding, automated refactorings, and IDE intelligence that LSP can't provide.
Parameters: project_name, code (Kotlin suspend function body), task_id, reason, timeout (optional)
Returns: execution_id plus ONLY what the script explicitly prints (println / printJson / printCsv / printToon). The last expression's value is ignored by the runtime — a script that computes but never prints returns no data, just a HINT: about the missing print.
Complete guide: mcp-steroid://skill/coding-with-intellij (API reference, patterns, examples, best practices)
steroid_execute_feedback
Rate execution results. Use after steroid_execute_code.
steroid_open_project
Open a project in the IDE. A managed backend cold start may block until MCP is reachable; only the project-open phase is asynchronous.
Through devrig, a sole installed managed backend is selected and started automatically; backend startup waits until MCP is reachable. The project-open request itself remains asynchronous.
Parameters:
project_path(required): Absolute path to the project directory to opentask_id(required): Task identifier for loggingreason(required): Why you are opening the projecttrust_project(optional): If true, trust the project path before opening (skips trust dialog). Default: true
Workflow:
- Call
steroid_open_projectwith the project path - If
trust_project=true, the project will be trusted automatically (no trust dialog) - Poll
steroid_list_projectsuntil the path appears and keep its freshproject_name - If a frontend exists, use
steroid_list_windows; only use screenshot/input when it reports a modal - A frontendless Remote Development backend has no required window. For a first Maven/Gradle open, await
the build-system model using its execute-code sync recipe before indexed semantic queries
MCP Resources (Use Them)
This server exposes built-in articles through steroid_fetch_resource. These are the fastest way to load full examples and guides without guessing or copy/pasting from the web.
How to access resources:
- Call
steroid_fetch_resourcewith amcp-steroid://URI to load the content.
The fetch tool is project-scoped because articles render for the target IDE. On a clean machine, use the initialize instructions and open-project description to bootstrap; fetch articles after a project appears.
Key resources provided by this server:
mcp-steroid://prompt/skill- This guide as a resource.mcp-steroid://skill/coding-with-intellij- Comprehensive guide for writing IntelliJ API code (execution model, patterns, examples).mcp-steroid://prompt/debugger-skill- Debugger-focused skill guide (breakpoints, sessions, threads).mcp-steroid://lsp/overview- Overview of LSP-like examples and how to use them.mcp-steroid://lsp/<id>- Runnable Kotlin scripts (e.g.,go-to-definition,find-references,rename,code-action,signature-help).mcp-steroid://ide/overview- Overview of IDE power operation examples (refactorings, inspections, generation).mcp-steroid://ide/<id>- Runnable Kotlin scripts (e.g.,extract-method,introduce-variable,change-signature,safe-delete,optimize-imports,pull-up-members,push-down-members,extract-interface,move-class,generate-constructor,call-hierarchy,project-dependencies,inspect-and-fix,inspection-summary,find-duplicates,project-search,run-configuration).mcp-steroid://debugger/overview- Overview of debugger examples (breakpoints, sessions, threads).mcp-steroid://debugger/<id>- Runnable Kotlin scripts (e.g.,set-line-breakpoint,debug-run-configuration,debug-session-control,debug-list-threads,debug-thread-dump).mcp-steroid://open-project/overview- Guide for opening projects via MCP.mcp-steroid://open-project/<id>- Project opening examples (e.g.,open-trusted,open-with-dialogs,open-via-code).mcp-steroid://open-project/managing-backends- devrig download, auto-start, Remote Development, and readiness phases.
These resources are designed to be plugged directly into steroid_execute_code after you configure file paths/positions.
Critical Rules
These are the essential rules you must follow. For detailed examples and patterns, read mcp-steroid://skill/coding-with-intellij.
1. Script Body is a SUSPEND Function
// This is a coroutine - use suspend APIs!// Under the default modal=smart_non_modal, waitForSmartMode() runs automatically before your script.delay(1000) // coroutine delay - works directly
NEVER use `runBlocking` - it causes deadlocks.
NEVER re-probe `waitForSmartMode()` before every operation. The automatic wait (under the default modal=smart_non_modal; skipped under non_modal / unleashed) before script start is only a point-in-time check; IntelliJ may enter dumb mode again before the next statement. For index-dependent PSI queries, wrap the whole query in smartReadAction { }. After project open/import/sync/configuration, first await Observation.awaitConfiguration(project), then use smartReadAction { }.
2. Imports Are Optional
Default imports are provided automatically. Add imports only when you need APIs outside the defaults. Imports must be at the top of the script, never after code.
3. Read/Write Actions for PSI/VFS
THREADING RULE — NEVER SKIP: Any PSI access MUST be insidereadAction { }. Modifications requirewriteAction { }. Threading violations throw immediately.
Built-in helpers (no imports needed):
// Reading PSI/VFS/indicesval data = readAction { project.name }// Modifying PSI/VFS/documentswriteAction { /* modifications here */ }// Runs index-dependent PSI work under IntelliJ's smart-mode read constraintval smart = smartReadAction { /* PSI operations */ }
For detailed threading patterns, see mcp-steroid://skill/coding-with-intellij-threading.
4. Context API
Built-in helpers available in every script (no imports needed):
| Category | APIs | |
|---|---|---|
| Properties | project, disposable, isDisposed | |
| Output (prose / JSON) | println(), printJson(), progress(), printException() | |
| Output (token-efficient tabular) | printCsv(headers, rows, dictColumns) — CSV with optional path-dictionary preamble; printToon(records) — TOON (array-of-records) form | |
| Read/Write | readAction { }, writeAction { }, smartReadAction { } | |
| Scopes | projectScope(), allScope() | |
| File access | findFile(), findPsiFile(), findProjectFile(), findProjectFiles("src/main/**/*.kt"), findProjectPsiFile() | |
| Analysis | runInspectionsDirectly() |
The output methods are the only way to get data back to the agent — the script's last-expression value is ignored by the runtime, so print everything you need.
Tabular output cheat sheet — for find-references, call-hierarchy, project-search, document-symbols, or any flat array-of-records result. Signatures are different on purpose; printCsv takes parallel lists (positional), printToon takes a list of maps (keyed). Mixing them up is the #1 first-try compile error.
// CSV — printCsv(headers: List<String>, rows: Iterable<List<Any?>>, dictColumns: Set<String> = emptySet())// Best when one column has repeated long values (absolute paths, FQNs).// `dictColumns` emits a per-column @col: preamble and replaces each cell with a short ID (`p1`, `p2`, ...).printCsv(headers = listOf("idx", "path", "line"),rows = emptyList<List<Any?>>(),dictColumns = setOf("path"),)// TOON — Token-Oriented Object Notation; https://github.com/toon-format/toon.// printToon(value: Any?) — drop-in for printJson on any value; cheapest on uniform-shape lists.// Pass List<Map<String, Any?>>. Same key set in every map -> compact [N]{cols}: form, column order// from the FIRST map's keys. Different key sets are ACCEPTED too -> less compact per-element block// ([N]: plus `key: value` lines), so never normalize naturally ragged records just to get the// compact form. Do NOT pass headers / rows / dictColumns — that's printCsv.printToon(listOf(mapOf("path" to "/abs/A.kt", "line" to 17), mapOf("path" to "/abs/B.kt", "line" to 42)))
Same records, both formats — most recipes finish by emitting one list of records twice:
val records: List<Triple<String, Int, String>> = emptyList() // built onceprintCsv(headers = listOf("idx", "path", "line", "snippet"),rows = records.mapIndexed { i, (p, l, s) -> listOf(i + 1, p, l, s) },dictColumns = setOf("path"),)printToon(records.map { (p, l, s) -> mapOf("path" to p, "line" to l, "snippet" to s) })
Full API reference with literal sample outputs and an end-to-end example: mcp-steroid://skill/coding-with-intellij-context-api → "Tabular Output".
5. Running Inspections
The IDE has hundreds of inspections — DuplicatedCode, RedundantCast, UnusedDeclaration, language-specific DFA, etc. Two paths from a script:
| You want to… | Use | |
|---|---|---|
| Run all enabled inspections on a file (warnings/errors style) | runInspectionsDirectly(file) — context-API helper, behaves like Map<toolId, List<ProblemDescriptor>> and also exposes failedTools. Works regardless of window focus. | |
Run one named inspection (e.g. DuplicatedCode) on a file | Construct the inspection class directly and pass it to InspectionEngine.inspectEx(...) via a LocalInspectionToolWrapper. See the inspect-and-fix and find-duplicates recipes. | |
| List which inspections are enabled (to know what's available) | mcp-steroid://ide/inspection-summary | |
| Find duplicate code clusters across the project | mcp-steroid://ide/find-duplicates (typed DuplicateProblemDescriptor.textClone, no reflection) |
Pitfall — do not `printJson(result)` from `runInspectionsDirectly`. The result is Map-compatible for legacy callers, but each ProblemDescriptor carries live PSI/VFS objects and can recurse through Jackson. Snapshot the descriptors under a read action, include failedTools, and compute an explicit status:
val vf = findProjectFile("src/main/java/com/example/Foo.java") ?: error("file not found")val result = runInspectionsDirectly(vf)val findings = readAction {result.entries.flatMap { (toolId, descriptors) ->descriptors.map { descriptor ->mapOf("toolId" to toolId,"message" to descriptor.descriptionTemplate,"elementText" to (descriptor.psiElement?.text ?: ""))}}}val status = when {result.failedTools.isNotEmpty() -> "check_failed"findings.isNotEmpty() -> "findings"else -> "clean"}printJson(mapOf("status" to status, "findings" to findings, "failedTools" to result.failedTools))
failedTools is the guard against false clean results: when the sweep cannot run for an input file, or an inspection tool crashes, the findings map may be empty but failedTools is non-empty.
6. Running Tests
Always prefer the IntelliJ IDE runner over `./mvnw test` or `./gradlew test`. The IDE runner returns a simple exit code (0 = all passed), shows structured results, and reuses the running JVM.
See mcp-steroid://skill/coding-with-intellij → "Run Tests via IntelliJ IDE Runner" for the complete pattern.
Only fall back to CLI test commands when the IDE runner cannot be used. Even then, never print the full output — always take(30) + takeLast(30) to avoid MCP token limit errors.
Error Handling
Use printException for errors - it includes the stack trace in the output:
try {// risky operation} catch (e: Exception) {printException("Operation failed", e)}
Troubleshooting
Check if Server is Running
The MCP server runs inside IntelliJ. To verify:
- Open IntelliJ IDEA with the MCP Steroid plugin installed
- Open any project
- Check
.idea/mcp-steroid.mdin the project folder for the server URL - The server port is configurable via
mcp.steroid.server.port; read.idea/mcp-steroid.mdfor the active URL
Endpoints
/- Returns this SKILL.md content/skill.md- Same as above/mcp- MCP protocol endpoint for tool calls/.well-known/mcp.json- MCP server discovery
Fetching mcp-steroid:// articles (preferred)
Use the steroid_fetch_resource MCP tool (it requires project_name for correct IDE-conditional rendering) instead of HTTP fetching or ReadMcpResourceTool. The articles are NOT exposed via resources/list or prompts/list — the tool is the canonical discovery surface.
Common Issues
- "Project not found" - Run
steroid_list_projectsfirst to get exact project names - No output from execute - Only printed values come back; the last expression's value is ignored by the runtime. End the script with
println()/printJson()of everything you need - Timeout - Increase
timeoutparameter (default 60 seconds) - Script errors - Check Kotlin syntax; imports are optional
Detailed Guides
For API examples, patterns, and in-depth coverage, read the dedicated articles:
| Topic | Resource | |
|---|---|---|
| Full guide (start here) | mcp-steroid://skill/coding-with-intellij | |
| Execution model & script structure | mcp-steroid://skill/coding-with-intellij-intro | |
| PSI operations & code analysis | mcp-steroid://skill/coding-with-intellij-psi | |
| Document, editor & VFS operations | mcp-steroid://skill/coding-with-intellij-vfs | |
| Threading & read/write actions | mcp-steroid://skill/coding-with-intellij-threading | |
| Common patterns & project info | mcp-steroid://skill/coding-with-intellij-patterns | |
| Refactoring, completion & services | mcp-steroid://skill/coding-with-intellij-refactoring | |
| McpScriptContext API reference | mcp-steroid://skill/coding-with-intellij-context-api | |
| Java & Spring Boot patterns | mcp-steroid://skill/coding-with-intellij-spring |
Other Resources
- Debugger Skill Guide - Debug workflows and stateful execution
- Test Runner Guide - Test execution patterns
- LSP Examples - LSP-like operations (navigation, code intelligence, refactoring)
- IDE Examples - IDE power operations (refactorings, inspections, generation)
- Debugger Examples - Debugger workflows and API usage
- Test Examples - Test execution and result inspection
- VCS Examples - Version control operations (git blame, history)
- Open Project Examples - Project opening workflows
This is like LSP, but more powerful. IntelliJ APIs offer deeper code understanding and more features than standard LSP. Don't settle for file-level operations when you have IDE-level access.