
Security News
Lovable’s OJ Rewrites Vite’s Dev Server in Rust as AI Lowers the Cost of Forking Open Source
Lovable’s OJ rewrites Vite’s dev server in Rust, reducing memory use and preview times as AI lowers the cost of open source reimplementation.
letin
Advanced tools
MCP server for Power Query (M): inspect, refactor, lint, version and guide query edits in Excel workbooks and Power BI PBIP projects
An MCP server that gives an AI assistant (GitHub Copilot in VS Code, Claude, …) real tools for managing Power Query (M) queries, in Excel workbooks and in Power BI projects.
Copilot in Excel / Power BI can suggest M. It cannot see how your queries depend on each other, rename one without breaking the rest, repoint forty queries at a new server, tell you which step killed query folding, put your queries in git, run a query to see what a step really returns, or check the M it just wrote against the real function library. This server does those things.
| Area | Tools |
|---|---|
| Inspect | list_sources list_queries get_query dependency_graph (JSON or Mermaid, lineage, orphans, cycles, refresh order) list_data_sources find_in_queries |
| Guided actions | list_transforms apply_transform (29 editor actions as parameters, not hand-written M: unpivot, pivot, group by, merge, append, filter, types, conditional column, split, fill, dedupe, date parts, …) remove_step |
| Bulk edit / refactor | rename_query rename_step (reference-safe) replace_in_queries (strings-only by default) extract_parameter copy_queries (with dependencies) set_query delete_query |
| Lint / performance | lint_queries: folding breakers before filters, hard-coded paths/servers/URLs, Csv.Document pinned column counts, dead steps, wrong in step, untyped Table.AddColumn, repeated Changed Type, brittle RemoveColumns, late filtering, duplicated staging logic, orphans, cycles |
| Version control | export_queries / import_queries (one .pq per query + manifest) diff_queries list_snapshots restore_snapshot |
| Run M | evaluate_query (whole query or up to a step) evaluate_steps (every step of a query in one engine call, with the step where an error first appears) evaluate_m (any expression, may reference the source's queries): real column names, types, sample rows, row count, Table.Profile, or the engine's error. Runs in a private hidden Excel on a throwaway copy, under a timeout |
| M language | validate_m (syntax errors with line/column and cause; unknown steps/functions with did-you-mean; wrong argument counts) format_m / format_queries (token-verified pretty-printer, comments kept) m_function_help (858 library members with signatures, generated from the engine's #shared) |
| Excel live | refresh_query (returns the engine's error text) preview_query |
Every write snapshots first, returns a unified diff, accepts dry_run=true, and is refused if it would turn valid M into a syntax error.
All edits are token-aware: a query called Sales is never confused with a column [Sales],
the string "Sales", or a comment.
Every tool takes a source:
source | Backed by | Read | Write |
|---|---|---|---|
C:\path\book.xlsx (.xlsm, .xlsb) | Closed: the file's DataMashup part, Excel is not started. Open in Excel: live COM. | ✅ | ✅ via COM. Already open → edited live, left unsaved for you to review. Closed → opened hidden with macros disabled, saved, closed. |
excel:active | The workbook in front in Excel | ✅ | ✅ |
Report.pbip, its folder, or X.SemanticModel | TMDL files (tables/*.tmdl, expressions.tmdl) | ✅ | ✅ M of any query; add/rename/delete for shared expressions only (renaming a table must be done in Desktop) |
model.bim (or a project that contains one) | TMSL JSON: legacy PBIP, Tabular Editor, SSAS/AAS projects | ✅ | ✅ same rules as TMDL; string-vs-line-array form of each expression is kept |
pbi:desktop, pbi:desktop:<port>, pbi:desktop:<title> | The model of a running Power BI Desktop (works for .pbix, sees unsaved edits), read through Desktop's own ADOMD client | ✅ | ❌ read-only by design: inspect, lint, diff, export, copy_queries out of it |
Orders.pq / .m | One query per file, named after the file | ✅ | ✅ |
mashup.pq (any section document) | section Section1; shared A = ...; e.g. Fabric Dataflow Gen2 git items, Power Query SDK | ✅ | ✅ member-level edits; [attributes] and comments survive |
a folder of .pq files | export_queries output | ✅ | ✅ |
A .pbix file is refused with instructions (save as .pbip, or open it and use pbi:desktop). Desktop must be
closed/reopened to pick up PBIP edits (that is how Desktop works, not a limitation of this server).
evaluate_* never runs anything in your session. A private, hidden, macro-disabled Excel opens a throwaway copy of the
workbook (unsaved edits included), or for non-Excel sources a blank workbook seeded with the source's queries. Your expression
is wrapped in try, the outcome is serialised to JSON by M itself, landed on a scratch sheet and read back. The refresh runs
in the background under a watchdog; on timeout that Excel is killed, so a credential or privacy prompt cannot hang the server.
Typical cost: 7-10 s per call. Non-Excel sources are evaluated by Excel's engine: Power BI-only connectors are unavailable
and credentials come from Excel's data source settings for your Windows user. ignore_privacy_levels=true turns the privacy
firewall off for that one throwaway evaluation.
Windows, Python 3.10+, Excel installed for workbook editing. letin is on PyPI
and in the MCP Registry as io.github.S-CurveLabs/letin.
The simplest way to run it is with uv, which needs no separate install step:
uvx letin
Or install it with pip install letin and run letin.
Run MCP: Open User Configuration from the command palette and add:
{
"servers": {
"letin": {
"type": "stdio",
"command": "uvx",
"args": ["letin"]
}
}
}
Then in Copilot Chat switch to Agent mode and check that the letin tools are enabled.
claude mcp add letin -- uvx letin
git clone https://github.com/S-CurveLabs/letin.git
cd letin
python -m venv .venv
.\.venv\Scripts\pip install -e .
Opening the clone in VS Code picks up .vscode/mcp.json, which runs that checkout with .venv\Scripts\python.exe -m letin.
C:\Reports\Sales.xlsx and draw the dependency graph as Mermaid."\\oldserver\finance. Move that into a parameter called SourceFolder."Query1 to stg_Orders everywhere."Budget, unpivot everything except Department and Account, then group by Department summing Value."./queries so I can commit them." / "What changed in the workbook since that export?"Sales have after the Merged Queries step? Show me 5 rows." / "Walk me through what every step of Sales does." / "At which step does the error first appear?"Sales by Month."Table.NestedJoin? Which functions split text?"%LOCALAPPDATA%\letin\snapshots\<workbook>-<hash>\ (last 50 per source);
override the root with LETIN_HOME.AutomationSecurity = ForceDisable: workbook macros never run.refresh_query only works on a workbook you have open, because a hidden refresh can block forever on a
credentials or privacy-level prompt.evaluate_* and refresh_query run M, always in Excel's engine, which then
contacts whatever data sources that M reads, exactly as a refresh in Excel would. Every other tool is static analysis.Expression.Evaluate, #shared) are reported, not rewritten.info, never as errors.
Regenerate the catalog after an Office update with python scripts/build_m_library.py.model.bim is re-serialised as 2-space JSON, so the first diff can be noisy if your tool formats it differently..\.venv\Scripts\pip install -e ".[dev]"
.\.venv\Scripts\pytest -m "not excel" # pure tests
.\.venv\Scripts\pytest # also drives a real hidden Excel
Layout: m/ (lexer, structural parser, full syntax parser, validator, formatter) → graph.py lint.py refactor.py
transforms.py (pure, host-agnostic) → hosts/ (Excel COM + file, PBIP/TMDL, model.bim, live Desktop, M files, folder)
→ evaluate.py (hidden-Excel evaluation) → server.py (MCP tools). data/m_library.json is generated by
scripts/build_m_library.py.
MIT. See LICENSE.
FAQs
MCP server for Power Query (M): inspect, refactor, lint, version and guide query edits in Excel workbooks and Power BI PBIP projects
We found that letin demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
Lovable’s OJ rewrites Vite’s dev server in Rust, reducing memory use and preview times as AI lowers the cost of open source reimplementation.

Security News
It has been one year since Shai-Hulud made its first appearance on npm.

Research
/Security News
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.