Running the server
npx form needs no install and is the one to use with agents that
are themselves npm-installed. iris-lsp --mcp suits editors that already bundle the Iris Code
language-server binary, and needs no Node.js.
The server writes only protocol messages to standard output, so do not wrap it in a script that
prints anything there.
Which folder it analyses
--root is the boundary: nothing outside it is read, and nothing outside it is written. Iris Code
resolves it in this order.
--root, if you pass it. Your own explicit choice, never overridden.- The workspace your editor reports. Clients that support MCP’s
rootscapability tell the server which project is open, so no flag is needed. Iris Code asks for this at startup. - The directory the client launched Iris Code in. The fallback when neither of the above applies.
--root when you want the boundary pinned regardless of client behaviour, such as a scripted or shared setup where the launch directory is not dependable. Pin it per project, though.
A --root registered once for every workspace points every workspace at that one folder: an agent working in project B is then answered about project A, and iris_fix_safe writes into A. Iris Code cannot detect that for you, because a pinned root is a legitimate instruction.
--root . is not a pin. It resolves to the directory the client launched the server in, which is what
Iris Code would have used anyway, and passing it suppresses step 2. Omit the flag instead.
Where several workspace roots are open, Iris Code analyses the first and names the others it is not
analysing. It does not merge them: separate roots are usually separate projects with their own
config and their own gate, so one blended score would describe neither.
Iris Code writes a ready line to standard error as soon as it starts, followed by the resolved folder
and where it came from, so your client log shows what it is actually looking at. Nothing but JSON-RPC
goes to standard output.
Started in a terminal rather than from a client, the server has nobody to talk to and will simply
wait. It says so, and prints the configuration to paste, rather than sitting there silently.
Iris Code refuses to start if the folder turns out to be a whole filesystem, your home directory, or
a directory containing home directories. Granting an agent read and write access across any of those
is not something a project setup needs, and it is the kind of mistake that is otherwise invisible.
Client setup
With the Iris Code extension installed, VS Code discovers the server through its own MCP server picker. Choose Iris Code there; no JSON entry is needed, and VS Code supplies the workspace boundary for each session. For every other client, register the command as an MCP server:iris-lsp --mcp when the binary is installed.
Naming no folder is what lets one registration cover every project you open, and it works when your
client either reports MCP roots or starts the server in the workspace. Verified on real clients:
After connecting, the startup line on standard error states the folder and where it came from, so you
can confirm your client rather than assume.
from your editor, over MCP roots and from the working directory both resolve correctly when that directory is the project.
JetBrains IDEs
The Iris Code JetBrains plugin bundlesiris-lsp, so it can provide the same server without Node.js. With a project open, choose Tools | Iris Code | Set Up MCP Server. The action copies a complete stdio configuration with the bundled executable’s absolute path and --root set to the open project.
Paste it into the MCP settings for the AI assistant you use in that IDE. The plugin does not change an assistant’s configuration itself.
This one pins the folder, and that is not a precaution - it is required. JetBrains AI Assistant reports no MCP roots, starts stdio servers from the IDE installation directory rather than the open project, and exposes no environment variable naming the project.
A bare command there resolves to the IDE’s own install folder, which is not your code. The plugin action fills in the pin so you never type a path, but it is per project: paste it into that project’s settings rather than a global one, and generate it again for the next project.
The bare command resolves the current release each run, so agents pick up fixes without anyone
editing a configuration file. Write @latest if you would rather that were explicit:
dist/cli.js also works, but it never updates, so prefer the npx form
outside development.
Tools
iris_check, iris_fix_safe, iris_refactor_plan and iris_verify_refactor are Free on a single
file. Folder and workspace scope are Pro, as they are in every other Iris Code surface. When
iris_check fails a file for size or complexity, the result says a refactor plan is available.
Pro tools stay in the tool list and describe themselves as Pro rather than being hidden, so your
assistant can tell you what an upgrade would add. Entitlement is checked when a tool runs, not when
it is listed, so a cached tool list cannot be replayed for Pro work.
Findings
iris_check returns every rule that fired, each anchored to a line and carrying its severity
(critical, high, medium or low) and a stable id.
This is a wider list than iris check --format github produces in CI. That surface writes one
error-level annotation per finding into a budget of roughly ten visible per step, so it carries
error-severity findings only. An agent has neither limit and can act on the rest, so it receives
them.
Large results are bounded. When a scan exceeds the response cap, the lowest severities are dropped
first and the response reports totalFindingCount, returnedFindingCount,
findingCountsBySeverity and droppedFindingCountsBySeverity. A critical finding is never dropped
to make room for a low one, and an agent can see that something was withheld rather than presenting
a partial answer as complete.
Explanations
iris_explain returns the finding report plus a context bundle for each finding, so an agent can act
on the cause rather than the label.
For a threshold rule, the bundle carries the measured value, the configured limit, and the overage:
a 302-line file against a 300-line limit reports actual: 302, limit: 300, overBy: 2. The limit
quoted is the one that actually applied to that file, so a per-language languages block or a nested
.irisconfig.json in a monorepo package is reflected rather than the workspace default.
Every bundle also carries the file’s imports and exports, and the other findings in the same file, so
a fix can account for what the file is for and what else is wrong with it.
Rules without a configured number - a hardcoded secret, a security smell - carry the finding’s own
message and that same file context. Iris Code does not invent remediation prose for them.
Safe fixes
iris_fix_safe previews by default. The preview lists the exact changes it would make and returns a
preview_token.
Writing requires apply: true and that token. It is single-use, expires after ten minutes, and
authorises exactly the change set the preview showed, so Iris Code only ever applies edits that have
already been put in front of you. A confirmation flag alone would not give you that, because the
model sets the flag.
For unused JavaScript imports, removing the last binding keeps the module load as import './a'. Whole TypeScript value imports are left for review because the load depends on compiler settings; import type can be removed. See fixes and suggestions.
Eligible fixes can span several lines: a debug statement on its own, an unused variable inside a function that is assigned a literal, a whole unused import or an unused name in an import, and two compatible imports merged into one. The iris fix reference lists the languages and refusals for each.
The same fixes are offered as a Quick Fix in VS Code and by iris fix --safe, from one shared planner, so the surfaces agree. console.error is never removed, because it reports real errors.
Refusals are per finding, with a reason, and one refusal does not block the rest. Iris Code declines
anything it cannot prove:
- A hardcoded secret is never auto-fixed. Rotating a leaked credential and moving it to an environment variable is not a mechanical edit.
- A debug print sharing its line with real code is left alone, because deleting the line would take the code with it.
- Anything needing a name or a judgement, such as extracting a magic number or shortening a long function, stays the agent’s work.
Long scans
Code analysis runs under a fifteen-minute deadline in a separate process, so a large workspace cannot hang the server. Dependency scans allow one active scan per workspace and returnSCAN_IN_PROGRESS for a second
request. If your client sends a progress token, the server reports phase and package counts as it
goes, and warns at two minutes. Cancelling returns the partial results collected so far, marked as
partial, rather than discarding them.
What the server will not do
Analysis is local. Your code is not uploaded, and there is no shell-execution tool and no generic “run any Iris Code command” passthrough, which would route around each tool’s own policy. Every requested path must resolve inside--root. That is checked after resolving symlinks, so a
link pointing outside the workspace is refused rather than followed.
Secret values are never returned, only the masked form every other Iris Code surface shows.
iris_check_dependency and iris_check_package are the tools that reach the network, querying public package registries and OSV.dev. Both require allow_network: true on each call unless you have already allowed network lookups from the CLI, disclose what they are about to do, and fall back to a local cache.
The agent’s flag is never saved as your consent, and it cannot override lookups you have turned off with iris deps --revoke-network.
Licensing
The server resolves your licence from the same credentials the CLI uses, so signing in once withiris auth login covers the CLI, your editor and MCP. The offline grace period applies here too.
A Free licence calling a Pro tool gets an explicit refusal naming the feature and where to upgrade,
which your assistant can relay. It is never a silent empty result.
Organisation and repository restrictions
The MCP server refuses repository tools withHANDOFF_FORBIDDEN when an organisation, project or committed "agentHandoff": false setting forbids the handoff. Tools stay listed and enforcement occurs on every call. The result names the restriction and has no upgrade link. iris_check_package keeps answering.
See Team governance for policy scope, session refresh, signed-out caching and the limits of these controls.
Refactor agent integration describes deterministic plans, session baselines and opt-in finish verification.