DEV Community

Henrik Westergård
Henrik Westergård

Posted on

I Turned IntelliJ Into a 90-Tool MCP Server for Coding Agents (and the Agent Built Most of It)

I built a JetBrains plugin that gives coding agents real IDE capabilities: 90+ tools covering file editing through IntelliJ's Document API, code navigation via the PSI, git, build, tests, and immediate editor feedback including SonarLint findings after every edit. Most of the code was written by the agent using the plugin itself. Here is how that happened.

How it started

A few years ago I stepped away from active software development after changing jobs. Recently I got a GitHub Copilot license at work and decided to give agentic coding a real try. I had used Copilot before, but my experience with the JetBrains plugin had always been underwhelming. It works much better in VS Code, or at least it did historically. So instead of the plugin, I started running the Copilot CLI directly in the IntelliJ terminal. And honestly, that was already a revelation. Good enough that I wanted to push it further.

Running an agent in a terminal inside your IDE quickly exposes three real problems though.

File edits bypass the IDE. The agent writes directly to disk and IntelliJ does not know about it. No syntax highlighting, no auto-format, no undo history, and I had to manually refresh files constantly.

The agent cannot use IDE intelligence. IntelliJ has incredibly fast code navigation: go to declaration, find usages, symbol search. The agent was spending turn after turn grepping through the project, reinventing what IntelliJ already does instantly.

And the agent is completely blind to IDE feedback. If my code had a warning right there in the editor, the agent had no idea unless it happened to build. An obvious error might only be noticed at the very end of a turn, after several more questionable edits had been stacked on top. SonarLint findings were invisible entirely.

These problems had an obvious solution.

Building it

I had never written a JetBrains plugin, never touched Kotlin, and had no practical experience with the MCP protocol. A few years ago I would never have taken this on, there were too many unknowns. But I had Copilot and wanted to see how far a coding assistant could carry me through genuinely unfamiliar territory.

The answer was a working proof of concept in an afternoon.

The code was a mess, of course. My first approach used a Go sidecar to bridge the Copilot SDK, so there were three languages in play simultaneously, Kotlin for the plugin UI, Java for the logic, and Go for the bridge. After discovering that ACP (Agent Client Protocol, Copilot's JSON-RPC 2.0 protocol over stdio) was a simpler path, I refactored everything and dropped the sidecar. Then I published to the JetBrains Marketplace.

After posting on Reddit I got good feedback about allowing the plugin to run in pure MCP mode, so any external agent client could connect without the plugin managing the agent process itself. I also got requests to support more agents. Since I was already on ACP, adding more clients was straightforward.

Almost everything in the project has been written by the agent, and once the plugin was stable enough, it started developing itself. It is the most complete vibe coding experience I have had. I have only prompted, reviewed and redirected. 99% of the source code is generated by LLMs.

What it does

The plugin embeds a full MCP server inside IntelliJ. Tool calls go through IntelliJ's own APIs rather than raw disk, so edits come with undo history, auto-format and VCS tracking built in.

In practice this means the agent can:

  • edit and read files through the Document API instead of writing directly to disk
  • navigate code using IntelliJ's PSI (go to declaration, find references, symbol search) instead of text search
  • see errors and warnings immediately after each edit, including SonarLint findings
  • run tests and builds and get the results back in the tool response

The IDE stays live while the agent works. Files the agent reads or edits open in the editor in real time and edits are highlighted. Git operations open the Git tool window. Test runs open the test runner. You can watch everything unfold without leaving IntelliJ.

Supported agents are GitHub Copilot, JetBrains Junie, Amazon Kiro, OpenCode, Claude Code and OpenAI Codex, with switching between them from a dropdown. That is useful when you have multiple subscriptions since each typically includes some free usage.

There is also an optional web-based chat UI served over HTTPS from localhost. It supports PWA so you can install it on your phone and follow along or respond to permission prompts when AFK.

The feedback loop is the point

The feature I am most happy about is the immediate editor feedback after edits. When the agent adds code to an existing method and cyclomatic complexity spikes, SonarLint flags it the instant the edit lands. The agent sees it and refactors right there, rather than producing something that technically works but will cause pain later.

This is also what makes the agent-builds-itself dynamic work well. Because every edit gets real IDE scrutiny in the same response, the generated code has to pass that bar before moving on. Over a long session this produces noticeably more maintainable code, and the agent builds a better mental model of the codebase as it goes.

What I learned about the protocols

ACP and MCP are both fairly young and the gaps show when you run multiple agents through the same integration layer.

The biggest challenge was tool call correlation. When an agent executes a tool, two separate events arrive: one over ACP carrying the UI representation, and one over MCP carrying the actual invocation. You need to match them up to show the right result in the UI.

The approach I ended up with hashes the tool arguments using canonical JSON and SHA-256, using the first 8 characters as a correlation key. Both sides compute the same hash independently. There is also a FIFO fallback for synchronous tools where argument matching is not reliable.

Claude Code CLI is the only agent that handles this at the protocol level, by embedding the ACP tool_use ID directly in the MCP _meta field. Every other agent does not send a correlation ID, so the hash fallback covers them. It would be nice if this was standardized, but the hash approach works well enough for now.

Each agent also has its own quirks around error formats, tool result handling and what parts of the protocol they actually implement. Working through those has been the most educational part of the project.

License and privacy

Since my original goal was a better agentic coding experience for colleagues in an enterprise environment, the license is Apache 2.0. There should be no question about whether it can be used at work.

The plugin collects no data and has no telemetry. It only connects to IntelliJ's APIs and to whatever agent you configure. What the agents and JetBrains do on their end is outside my control, but the plugin itself is fully local.


The plugin is open source and available on the JetBrains Marketplace.


Here is the plugin Start-up Screen:

Screenshot of init screen of plugin

Here is what the chat looks like
Screenshot of plugin

Top comments (0)