# Mps Console

> Use when running or generating MPS Console code, or when writing `jetbrains.mps.lang.smodel.query` queries anywhere in MPS (intentions, behavior, actions, generator queries, plain BaseLanguage). Covers the console command languages (`jetbrains.mps.console.base` / `ideCommands` / `internalCommands` / `scripts`): `BLCommand` / `BLExpression`, the `#print*` / `#show` result printers, IDE commands (`#make` / `#clean` / `#removeGenSources` / `#reloadClasses` / `#stat` / `#showGenPlan` / `#showBrokenRefs`), `#exec` / `forEach` / `refactor` scripts. Covers the smodel query language: `#nodes` / `#references` / `#models` / `#modules` / `#instances` / `#usages`, the `with`-statement scope wrapper, scopes (`project` / `editable` / `global` / `visible` / `modules` / `models` / `custom`) and query parameters (`scope` / `exact` / `r/o+`). Also how to insert, read, recall, and run console commands with `mps_mcp_insert_console_command_from_json`, `mps_mcp_get_current_editor_root_node(source="console")`, `mps_mcp_get_console_

- Skill: `jetbrains/mps-console` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add jetbrains/mps-console`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jetbrains/mps-console/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: jetbrains (https://skillmd.com/u/jetbrains)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/jetbrains/mps-console

---


# MPS Console and the smodel query language

The **MPS Console** runs DSL code against the live models of the open project: query and mutate nodes, run find-usages, gather statistics, make/clean models, reload classes. Code is typed line-by-line, generated by the MPS generator, and executed in the IDE context. Most console-specific constructs start with `#` and completion (Ctrl+Space) inserts them.

The **smodel query language** (`jetbrains.mps.lang.smodel.query`) exposes the *same* queries (`#nodes`, `#instances`, `#usages`, …) for use in ordinary model code — intentions, behavior methods, actions, migration/refactoring scripts — wrapped in a `with (<scope>) { … }` statement. Reach for it whenever code needs to enumerate nodes/models/modules or find instances/usages across a scope.

## Ways this skill gets used

1. **Type code in the Console tool window** (Tools ▸ Console, or the Console tool window). One command per input. See `references/console-languages.md`.
2. **Write `smodel.query` queries inside model code** (an intention, behavior method, generator query, script). Import `jetbrains.mps.lang.smodel.query` and wrap queries in `with (<scope>) { … }`. See `references/smodel-query.md`.
3. **Insert code into the Console from an agent** via `mps_mcp_insert_console_command_from_json` — builds a command from a JSON blueprint and drops it into the console input **without executing it** (the user reviews and runs it with Ctrl+Enter). See `references/mcp-insertion.md`.
4. **Read the current Console command from an agent** via `mps_mcp_get_current_editor_root_node` with `source = "console"` — returns the node-info envelope of the command currently in the console input (one an agent inserted, or the user typed). Feed its `reference` to `mps_mcp_print_node` for the JSON blueprint (`format = "JSON"`) or the notational printout (`format = "PLAIN TEXT"` / `"HTML"`), or to `mps_mcp_check_root_node_problems` to see the problems MPS's model checker reports for it (way #8). The reference is only valid until the next console interaction (execute / clear / history navigation), so print it promptly and do not cache it.
5. **Browse the Console history from an agent** via `mps_mcp_get_console_history` — lists previously executed commands in order, each with a one-line `preview`, a history-entry `reference`, and an `effectiveCommandReference`. Pass the entry `reference` to recall; pass `effectiveCommandReference` to `mps_mcp_print_node`. Use `includeResponses = true` to also see the printed output. Same reference-validity caveat as #4.
6. **Recall a history command into the input** via `mps_mcp_recall_console_command(historyNodeReference)` — deep-copies a history entry (from #5) back into the input slot **without executing it**. Pass the history entry's `reference`, not its `effectiveCommandReference`. There is no MPS "recall" API to call directly; this mirrors what the Console's own up/down history navigation does (`copy` + insert).
7. **Run the current Console command from an agent** via `mps_mcp_run_console_command` — executes whatever command is currently in the input (placed there by #3 or #6, or typed by the user), exactly as Ctrl+Enter, and only when a command is present. **It executes code with side effects.** The response is not returned by the tool; read it afterwards via #5 (`mps_mcp_get_console_history` with `includeResponses = true`) or from the Console tool window, and note that long-running commands (make/generate) complete asynchronously.
8. **Check a Console command for problems from an agent** via `mps_mcp_check_root_node_problems` — pass the `reference` from way #4 (or an `effectiveCommandReference` from way #5) and it runs MPS's full checker set (structure, constraints, reference scopes, typesystem, and checking rules), surfacing the same errors/warnings the Console editor underlines and the Model Checker reports. Two caveats: **(a) root-scoped** — the tool checks the command's `containingRoot`, which for console code is the single `ConsoleRoot` holding the current input *and the entire history*, so results can include problems from earlier commands; with the default `onlyNodesWithProblems = true` you get a flat list of problem nodes, so match each one's `rootName`/subtree to the command you mean. **(b)** Same reference-validity window as #4 — resolve and check before the next console interaction.

## A command is one of three shapes

The console input holds exactly **one** command (`jetbrains.mps.console.base.structure.Command`):

| Shape | Concept | What it is |
|---|---|---|
| BaseLanguage statements | `BLCommand` (alias `{`) — `body: StatementList` | a `{ … }` block of imperative statements; the value of a trailing expression statement is printed |
| BaseLanguage expression | `BLExpression` — `expression: Expression` | one expression; if non-void its value is printed (as text / AST / interactive response) |
| Interpreted command | `InterpretedCommand` subtypes | non-generated commands: `#stat`, `#showGenPlan`, `#showBrokenRefs`, `#reloadClasses`, `?` (help) |

**Key fact that trips up blueprints:** the query commands (`#nodes`, `#instances`, …), the IDE commands `#make` / `#clean` / `#removeGenSources` / `#show` / `#callAction`, and the printers `#print` / `#printNode` / `#printNodeRef` / `#printSequence` / `#printText` are all baseLanguage **`Expression`s**, not `Command`s. To use one as a standalone command you put it inside a `BLExpression` (or inside `{ … }` statements). Only `InterpretedCommand` subtypes and `#reloadClasses` are commands in their own right.

## Critical Directives

- **This skill is the controlling workflow for Console tasks.** Start from surface syntax first — choose the query (`#instances`, `#usages`, `#nodes`, …), filter and transform with `smodel` / `collections` / `closures`, then insert or run via the console MCP tools. Only fall back to low-level Java/MPS-OpenAPI approaches if the surface syntax route has genuinely failed.
- **Pick the scope deliberately.** Without a scope, console queries run over *all editable models of the current project*; a `with` statement defaults to *editable* models too, so model-changing code is safe. Scopes: `project`, `editable`, `global`, `visible`, `modules(...)`, `models(...)`, `custom(<SearchScope>)`. See `references/smodel-query.md`.
- **`scope` parameter ≠ `with` scope.** When you pass `scope` explicitly as a query parameter it is used *as-is and keeps read-only models*, so `#nodes` inside `with(project)` and `#nodes<scope project>` can return different results.
- **No nested `with`.** A `with` statement may not contain another `with`.
- **Lazy vs eager:** `#nodes` / `#references` / `#models` / `#modules` are lazy sequences (full iteration). `#instances` / `#usages` use the find-usages index — far faster than iterate-then-filter. Prefer `#instances(C)` over `#nodes.ofConcept<C>()`.
- **`exact` parameter** on `#instances` excludes instances of sub-concepts (`#instances<exact>(C)`).
- **MetaAdapterFactory is a rabbit-hole warning for Console tasks.** If you feel tempted to use `MetaAdapterFactory`, hex feature IDs, generated `StructureAspectDescriptor` code, or hand-built `SConcept` / `SContainmentLink` objects while solving a Console command, stop and reframe the solution in surface syntax instead: `#instances(Concept)`, `node.property`, `node.childRole`, `replace with new(Concept)`, `.forEach`, or `.refactor`. `MetaAdapterFactory` belongs to low-level/generated implementation details, not the first-line solution for MPS Console work.
- **Never hand-edit the console's `.mps` model.** Use the editor or the MCP tool. The console lives in a temporary `ConsoleModel_*` model.
- **Insertion and recall do not execute.** `mps_mcp_insert_console_command_from_json` and `mps_mcp_recall_console_command` only place a command in the input; by default leave it for the user to run and tell them it is waiting. To execute it yourself, call `mps_mcp_run_console_command` (way #7) — it runs code with side effects, so do it deliberately and report what it did.
- **Bulk node mutation: pick `refactor` vs `forEach` by whether *you* will run it.** `.refactor({~it => … })` (`RefactorOperation`) pops a **modal confirmation dialog** and applies nothing until a human approves it; `.forEach({~it => … })` (collections `VisitAllOperation`) applies its closure immediately, in the console's own write command, with no dialog. So: when the user asks only to **create / insert** a command for them to run themselves (`mps_mcp_insert_console_command_from_json` and stop), prefer **`refactor`** — the dialog gives them a review-and-confirm step at the keyboard. When the user asks you to **create *and run*** it yourself (you will call `mps_mcp_run_console_command`), prefer **`forEach`** — `refactor` would return `executed:true` but stall on the dialog with no human present, leaving the model unchanged and the run a silent no-op.

## Examples (surface syntax)

```
#models                                          // all editable models in the project
#modules<global>                                 // every module in the repository
#instances(ClassConcept)                         // fast: all ClassConcept instances in scope
#instances<exact>(BaseConcept)                    // exclude sub-concepts
#usages(aNode)                                    // direct references to a node
#print 2 + 2                                     // smart-print a value
#printNode someNode                              // print a node copy
#show #instances(Issue)                          // open the result in the usages view
#make #models<modules myModule>                  // make selected models
#reloadClasses                                   // reload generated classes

// migrate every TryStatement with a catch + long body to TryCatchStatement (from the MPS docs)
// `.forEach` applies immediately and headlessly; `.refactor` instead pops a confirmation dialog
#instances(TryStatement).where({~it => it.catchClause.isNotEmpty; }).forEach({~node => if (node.body.statement.size > 5) { node.replace with new(TryCatchStatement); } })
```

## Related Skills

- `mps-model-manipulation` — the `smodel` / `collections` / `closures` operations (`.where`, `.select`, `.ofConcept<C>`, `replace with new(C)`, `:eq:`) used in the bodies of console commands, `with` blocks, and `refactor` closures. The smodel query language layers on top of these.
- `mps-node-editing` — the JSON blueprint format that `mps_mcp_insert_console_command_from_json` consumes (shared with `mps_mcp_insert_root_node_from_json`).
- `mps-aspect-intentions` — a common host for `with (…) { #instances(…)… }` queries.
- `mps-baselanguage` — host BaseLanguage statements/expressions that fill `BLCommand` / `BLExpression`.
- `mps-run-configurations` — for running a `main`/test root node instead of console code.

## Reference Index

- Open `references/console-languages.md` for the full console command-language reference — every `#` command grouped by language (`base`, `ideCommands`, `internalCommands`, `scripts`), aliases, what each prints, scopes, paste-as-nodeRef, and `#exec` scripts.
- Open `references/smodel-query.md` for the `jetbrains.mps.lang.smodel.query` language used in model code — the `with` statement, the six query expressions, scope parameters, the `scope` / `exact` / `r/o+` query parameters, default-scope rules, and intention/behavior usage examples.
- Open `references/mcp-insertion.md` for `mps_mcp_insert_console_command_from_json` — the two accepted JSON shapes, validated working blueprints (`BLExpression` + query, statement arrays, interpreted commands), concept FQNs and language UUIDs, the "wrap expressions in `BLExpression`" gotcha, and `dryRun` validation.

