From e803578c020c0eb5e5876a96adf09965ebea12b8 Mon Sep 17 00:00:00 2001
From: Prateek Singh
Date: Mon, 20 Jul 2026 21:43:05 -0400
Subject: [PATCH 1/3] fix(mcp): close 5 design issues found by live-driving all
48 verbs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Found by driving the real editor with the real sidecar on v0.1.120 —
gaps the fake-half unit suites (C++ fakes the sidecar, Rust fakes the
bridge) structurally cannot see. Opus-architected, implemented in
dependency order, each with a red-state test that FAILS without the fix.
#1 Welcome tab (index 0) was a silent trap: it appeared in list_open_tabs
like any tab but insert_text/compare_tabs/save_tab failed on it with
generic errors, and read_tab returned empty text (worse — looked like
an empty document). Now every tab carries "editable"; the five
tab-context write/read verbs gate on it.
#3 git_* were unusable with no repo file open. runGit now appends the
editor's STARTUP working dir (QDir::currentPath captured once at
construction, never live — a live cwd would make git_status depend on
the last file dialog) as the final candidate root, so
`notepatra ~/repo && git_status` works.
#4 save_tab could not persist AI-generated content: it refused untitled
tabs and had no path. It now takes an optional `path` (Save-As). It
STAYS WRITE-tier and approval-gated: the path is validated (absolute +
parent exists) BEFORE the card, the card SHOWS the destination
(OVERWRITE-flagged if it exists), and the write executes only inside
the approved closure. No headless bypass.
#5 replace_selection was unusable by an AI — it needed a selection but
nothing could set one. New ACT-tier verb select_range (1-based, like
goto_line) sets the selection with no card (it mutates only the
selection, like goto_line); replace_selection still carries its own
approval. Tool count 48 -> 49.
#6 generic errors ("could not insert", "could not open compare view",
"needs Save As") replaced with specific, actionable messages so an AI
can self-correct.
Verified independently, not just by the implementer: full ctest 71/71,
Rust default + --features remote green, fmt + clippy --all-features
clean, Windows cross-check (x86_64-pc-windows-msvc) clean. Red-state
spot-checked by hand — forcing tabIsEditable true fails exactly the 3
gate tests. Approval-gate audit: save_tab validates before the card and
executes only in the approval closure; select_range enqueues zero cards.
Deliberate deviation from spec: the Rust mock does NOT prepend a Welcome
tab at index 0 — that would shift ~55 index-dependent assertions and
break every write test targeting tab_index 0. The C++ bridge (source of
truth) fully implements and tests Welcome-tab behavior; the mock
exercises editable:false via diagram tabs.
#2 (export_chart-to-file "TypeError: e.isString") is a separate WebEngine
runtime bug, investigated separately — not in this change.
Co-Authored-By: Claude Opus 4.8
---
notepatra-mcp/src/lib.rs | 2 +-
notepatra-mcp/src/remote/scope.rs | 6 +-
notepatra-mcp/src/tools.rs | 82 ++++++-
notepatra-mcp/src/transport/mock.rs | 70 +++++-
notepatra-mcp/src/transport/mod.rs | 32 ++-
notepatra-mcp/src/transport/socket.rs | 41 +++-
notepatra-mcp/tests/protocol.rs | 69 +++++-
notepatra-mcp/tests/socket_bridge.rs | 4 +-
src/mainwindow.cpp | 61 ++++++
src/mainwindow.h | 5 +
src/mcp_bridge.cpp | 203 ++++++++++++++++--
src/mcp_bridge.h | 24 +++
test_mcp_bridge.cpp | 293 +++++++++++++++++++++++++-
13 files changed, 840 insertions(+), 52 deletions(-)
diff --git a/notepatra-mcp/src/lib.rs b/notepatra-mcp/src/lib.rs
index 33e03e5..d90f2c1 100644
--- a/notepatra-mcp/src/lib.rs
+++ b/notepatra-mcp/src/lib.rs
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
-// The tools::definitions() json! array is large enough (48 tools) to exceed
+// The tools::definitions() json! array is large enough (49 tools) to exceed
// the default macro recursion limit.
#![recursion_limit = "512"]
// UNGATED on purpose: the default std-only build needs the per-user config dir
diff --git a/notepatra-mcp/src/remote/scope.rs b/notepatra-mcp/src/remote/scope.rs
index d86c6f8..f4598e5 100644
--- a/notepatra-mcp/src/remote/scope.rs
+++ b/notepatra-mcp/src/remote/scope.rs
@@ -128,7 +128,7 @@ mod tests {
fn filter_sizes_are_cumulative() {
let full = serde_json::json!({ "result": { "tools": definitions() } });
let total = definitions().as_array().unwrap().len();
- assert_eq!(total, 48);
+ assert_eq!(total, 49);
for (scope, want) in [
(Scope::ReadOnly, READ_TOOLS.len()),
@@ -145,9 +145,9 @@ mod tests {
scope.as_str()
);
}
- // Concretely: 24 / 37 / 48.
+ // Concretely: 24 / 38 / 49.
assert_eq!(READ_TOOLS.len(), 24);
- assert_eq!(READ_TOOLS.len() + ACT_TOOLS.len(), 37);
+ assert_eq!(READ_TOOLS.len() + ACT_TOOLS.len(), 38);
}
#[test]
diff --git a/notepatra-mcp/src/tools.rs b/notepatra-mcp/src/tools.rs
index 20545e5..1dc3506 100644
--- a/notepatra-mcp/src/tools.rs
+++ b/notepatra-mcp/src/tools.rs
@@ -43,6 +43,7 @@ pub const ACT_TOOLS: &[&str] = &[
"open_file",
"new_tab",
"goto_line",
+ "select_range",
"set_language",
"compare_tabs",
"format_json",
@@ -220,6 +221,22 @@ pub fn definitions() -> Value {
"additionalProperties": false
}
},
+ {
+ "name": "select_range",
+ "description": "Set the editor's text selection to a 1-based line/column range in a tab (default: the active tab). Columns are clamped to each line's length. Use to highlight a span for the user, e.g. before replace_selection.",
+ "inputSchema": {
+ "type": "object",
+ "properties": {
+ "start_line": { "type": "integer", "minimum": 1, "description": "1-based line where the selection starts" },
+ "start_col": { "type": "integer", "minimum": 1, "description": "1-based column where the selection starts" },
+ "end_line": { "type": "integer", "minimum": 1, "description": "1-based line where the selection ends" },
+ "end_col": { "type": "integer", "minimum": 1, "description": "1-based column where the selection ends (exclusive)" },
+ "tab_index": { "type": "integer", "minimum": 0, "description": "Zero-based tab index (default: active tab)" }
+ },
+ "required": ["start_line", "start_col", "end_line", "end_col"],
+ "additionalProperties": false
+ }
+ },
{
"name": "set_language",
"description": "Set the syntax-highlighting language of a tab (defaults to the active tab). Use after new_tab, or when a file is highlighted with the wrong language.",
@@ -322,13 +339,16 @@ pub fn definitions() -> Value {
{
"name": "save_tab",
"description": format!(
- "Save an open tab (default: the active tab) to its file on disk. \
- {APPROVAL_NOTE}"
+ "Save an open tab (default: the active tab) to disk. Pass path \
+ to \"Save As\" to a new absolute file (its parent folder must \
+ already exist); an untitled tab that has never been saved \
+ requires path. {APPROVAL_NOTE}"
),
"inputSchema": {
"type": "object",
"properties": {
- "tab_index": { "type": "integer", "minimum": 0, "description": "Zero-based tab index (default: active tab)" }
+ "tab_index": { "type": "integer", "minimum": 0, "description": "Zero-based tab index (default: active tab)" },
+ "path": { "type": "string", "description": "Absolute path to save the tab to (\"Save As\"); its parent folder must exist. Omit to save to the tab's existing file." }
},
"required": [],
"additionalProperties": false
@@ -660,6 +680,7 @@ pub fn call(
"find_in_tab" => find_in_tab(transport, args),
"new_tab" => new_tab(transport, args),
"goto_line" => goto_line(transport, args),
+ "select_range" => select_range(transport, args),
"set_language" => set_language(transport, args),
"compare_tabs" => compare_tabs(transport, args),
"format_json" => format_text(transport, args, "json"),
@@ -768,6 +789,16 @@ fn optional_one_based(args: &Map, key: &str) -> Result
- New in v0.1.120:notepatra-mcp now ships a prebuilt signed Windows sidecar and a one-click Claude Desktop bundle — connect Claude Desktop, Claude Code, OpenAI Codex, and any MCP client to the running editor. 48 tools (Git, read-only SQL, saved-connection queries, charts, Noter notes); every write human-approved in-window; nothing leaves your machine.
+ New in v0.1.120:notepatra-mcp now ships a prebuilt signed Windows sidecar and a one-click Claude Desktop bundle — connect Claude Desktop, Claude Code, OpenAI Codex, and any MCP client to the running editor. 49 tools (Git, read-only SQL, saved-connection queries, charts, Noter notes); every write human-approved in-window; nothing leaves your machine.
Website ·
@@ -51,7 +51,7 @@ Not a port. Not a wrapper. Something new — **for everyone**.
I asked: **what would a small native code editor look like if it was built today, in 2026, when AI is part of every developer's workflow, and ran natively on Linux + macOS + Windows from one codebase?**
-The answer: a tiny native executable — ~12 MB bare (~12.4 MB on Linux x64) on every platform — with a Rust-powered core, Scintilla editing engine, and local-first AI integration (cloud backends optional). v0.1.120 downloads: 4.4 MB Linux x64 (tarball, Qt from the system), 27.7 MB on macOS (DMG with bundled Qt), 32.8–42.7 MB on Windows (MSI/zip/setup.exe with bundled Qt DLLs). An editor that can fix your broken JSON with regex in milliseconds — and when regex isn't enough, it asks your AI to figure it out — local by default, six cloud backends one click away when you want a frontier model. No telemetry. No subscription. No mandatory API key.
+The answer: a tiny native executable — ~12 MB bare (~12.4 MB on Linux x64) on every platform — with a Rust-powered core, Scintilla editing engine, and local-first AI integration (cloud backends optional). v0.1.121 downloads: 4.4 MB Linux x64 (tarball, Qt from the system), 27.7 MB on macOS (DMG with bundled Qt), 32.8–42.7 MB on Windows (MSI/zip/setup.exe with bundled Qt DLLs). An editor that can fix your broken JSON with regex in milliseconds — and when regex isn't enough, it asks your AI to figure it out — local by default, six cloud backends one click away when you want a frontier model. No telemetry. No subscription. No mandatory API key.
Notepatra started on Linux — because that's where the gap was. But great tools shouldn't have borders. **Notepatra runs on Linux, Windows, and macOS.** Same codebase. Same features. No one gets left behind.
@@ -239,7 +239,7 @@ A first-class diagramming surface that **renders in the default binary on every
From v0.1.118, Notepatra ships **`notepatra-mcp`** — a stdio JSON-RPC 2.0 [Model Context Protocol](https://modelcontextprotocol.io) server that connects external AI assistants (Claude Desktop, Claude Code, OpenAI Codex, the OpenAI Agents SDK, and any spec-compliant MCP client) to the running editor over a local socket. Nothing leaves your machine: stdio to the client, local socket to the editor, no network connections.
-**48 tools in three tiers**:
+**49 tools in three tiers**:
| Tier | Tools | Gate |
|---|---|---|
@@ -287,7 +287,7 @@ Full tool reference, Claude Desktop / Agents SDK snippets, security model, and h
**Why this hybrid?**
- **C++** because Qt and QScintilla are C++ — zero friction for UI
- **Rust** because file I/O, text processing, and parsing must never crash — Rust's ownership system guarantees memory safety
-- **Result**: the speed of C++, the safety of Rust. The bare executable is **~12 MB** on every platform (~12.4 MB Linux x64, similar on macOS / Windows). Latest v0.1.120 download sizes: **4.4 MB** Linux x64 tar.gz · **4.1 MB** Linux ARM64 tar.gz · **27.7 MB** macOS DMG (with bundled Qt) · **42.7 MB** Windows MSI · **32.8 MB** Windows NSIS · **37.4 MB** Windows portable zip. _Installed footprint on Windows is ~75-85 MB after the MSI extracts bundled Qt + QScintilla DLLs — normal for any Qt-based installer._
+- **Result**: the speed of C++, the safety of Rust. The bare executable is **~12 MB** on every platform (~12.4 MB Linux x64, similar on macOS / Windows). Latest v0.1.121 download sizes: **4.4 MB** Linux x64 tar.gz · **4.1 MB** Linux ARM64 tar.gz · **27.7 MB** macOS DMG (with bundled Qt) · **42.7 MB** Windows MSI · **32.8 MB** Windows NSIS · **37.4 MB** Windows portable zip. _Installed footprint on Windows is ~75-85 MB after the MSI extracts bundled Qt + QScintilla DLLs — normal for any Qt-based installer._
---
@@ -307,7 +307,7 @@ irm https://notepatra.org/install.ps1 | iex
That's it. Auto-detects your OS, downloads the right binary, installs it, adds to PATH, creates shortcuts.
-### Or download manually — [Latest release: v0.1.120](https://github.com/singhpratech/notepatra/releases/latest)
+### Or download manually — [Latest release: v0.1.121](https://github.com/singhpratech/notepatra/releases/latest)
| Platform | Download | Size | What's inside |
|---|---|---|---|
@@ -332,11 +332,11 @@ For one-time-install-then-every-user-sees-it on a shared machine, or silent push
| OS | Artefact | Silent admin install |
|---|---|---|
-| 🪟 **Windows** | [`notepatra-x.x.x.msi`](https://github.com/singhpratech/notepatra/releases/latest) | `msiexec /i notepatra-0.1.120.msi /quiet` — installs to `C:\Program Files\Notepatra\`, adds system PATH, registers HKCR file associations, all-users Start Menu. WiX-built, MajorUpgrade-aware, SCCM-friendly. |
+| 🪟 **Windows** | [`notepatra-x.x.x.msi`](https://github.com/singhpratech/notepatra/releases/latest) | `msiexec /i notepatra-0.1.121.msi /quiet` — installs to `C:\Program Files\Notepatra\`, adds system PATH, registers HKCR file associations, all-users Start Menu. WiX-built, MajorUpgrade-aware, SCCM-friendly. |
| 🍎 **macOS** | [`Notepatra.dmg`](https://github.com/singhpratech/notepatra/releases/latest) | Mount + `sudo cp -R "/Volumes/Notepatra/Notepatra.app" /Applications/` from a deployment script. Or open the DMG manually and drag to `/Applications` (admin password). Notarised + stapled. |
-| 🐧 **Debian / Ubuntu / Mint / Pop!_OS** (x64 + ARM64) | [`notepatra_0.1.120_amd64.deb`](https://github.com/singhpratech/notepatra/releases/latest) | `sudo apt install ./notepatra_0.1.120_amd64.deb` — installs to `/opt/notepatra/` + symlink at `/usr/bin/notepatra`, hicolor icons, `.desktop` registration. ARM64: replace `amd64` → `arm64`. |
-| 🐧 **Fedora / RHEL / CentOS Stream / Rocky / Alma** (x64 + ARM64) | [`notepatra-0.1.120-1.x86_64.rpm`](https://github.com/singhpratech/notepatra/releases/latest) | `sudo dnf install ./notepatra-0.1.120-1.x86_64.rpm` — same layout as the .deb. ARM64: replace `x86_64` → `aarch64`. Bundles QScintilla 2.14.1 alongside the binary because Fedora ships an incompatible packaging. |
-| 🐧 **Arch / openSUSE Tumbleweed / Manjaro / EndeavourOS / other glibc 2.38+** | [`Notepatra-0.1.120-x86_64.AppImage`](https://github.com/singhpratech/notepatra/releases/latest) | `chmod +x Notepatra-0.1.120-x86_64.AppImage && sudo cp Notepatra-0.1.120-x86_64.AppImage /opt/notepatra.AppImage && sudo ln -s /opt/notepatra.AppImage /usr/local/bin/notepatra`. Requires glibc 2.38+ (Ubuntu 24.04+, Fedora 40+, Arch, Tumbleweed). Older distros: use the .deb / .rpm. |
+| 🐧 **Debian / Ubuntu / Mint / Pop!_OS** (x64 + ARM64) | [`notepatra_0.1.121_amd64.deb`](https://github.com/singhpratech/notepatra/releases/latest) | `sudo apt install ./notepatra_0.1.121_amd64.deb` — installs to `/opt/notepatra/` + symlink at `/usr/bin/notepatra`, hicolor icons, `.desktop` registration. ARM64: replace `amd64` → `arm64`. |
+| 🐧 **Fedora / RHEL / CentOS Stream / Rocky / Alma** (x64 + ARM64) | [`notepatra-0.1.121-1.x86_64.rpm`](https://github.com/singhpratech/notepatra/releases/latest) | `sudo dnf install ./notepatra-0.1.121-1.x86_64.rpm` — same layout as the .deb. ARM64: replace `x86_64` → `aarch64`. Bundles QScintilla 2.14.1 alongside the binary because Fedora ships an incompatible packaging. |
+| 🐧 **Arch / openSUSE Tumbleweed / Manjaro / EndeavourOS / other glibc 2.38+** | [`Notepatra-0.1.121-x86_64.AppImage`](https://github.com/singhpratech/notepatra/releases/latest) | `chmod +x Notepatra-0.1.121-x86_64.AppImage && sudo cp Notepatra-0.1.121-x86_64.AppImage /opt/notepatra.AppImage && sudo ln -s /opt/notepatra.AppImage /usr/local/bin/notepatra`. Requires glibc 2.38+ (Ubuntu 24.04+, Fedora 40+, Arch, Tumbleweed). Older distros: use the .deb / .rpm. |
> All artefacts ship with cosign `.sig` + `.pem` for keyless Sigstore verification and SLSA build provenance. See **[Verify your download](#verify-your-download)** below.
@@ -346,9 +346,9 @@ For teams that **can't or won't send code to public LLM endpoints** — regulate
| OS | Artefact | Silent admin install |
|---|---|---|
-| 🪟 **Windows** | [`notepatra-local-ai-0.1.120.msi`](https://github.com/singhpratech/notepatra/releases/latest) | `msiexec /i notepatra-local-ai-0.1.120.msi /quiet` — installs to `C:\Program Files\Notepatra Local AI\`, distinct UpgradeCode so SCCM treats it as its own product. Add/Remove Programs shows "Notepatra Local AI". |
-| 🐧 **Debian/Ubuntu x64** | [`notepatra-local-ai_0.1.120_amd64.deb`](https://github.com/singhpratech/notepatra/releases/latest) | `sudo apt install ./notepatra-local-ai_0.1.120_amd64.deb` |
-| 🐧 **Debian/Ubuntu ARM64** | [`notepatra-local-ai_0.1.120_arm64.deb`](https://github.com/singhpratech/notepatra/releases/latest) | `sudo apt install ./notepatra-local-ai_0.1.120_arm64.deb` |
+| 🪟 **Windows** | [`notepatra-local-ai-0.1.121.msi`](https://github.com/singhpratech/notepatra/releases/latest) | `msiexec /i notepatra-local-ai-0.1.121.msi /quiet` — installs to `C:\Program Files\Notepatra Local AI\`, distinct UpgradeCode so SCCM treats it as its own product. Add/Remove Programs shows "Notepatra Local AI". |
+| 🐧 **Debian/Ubuntu x64** | [`notepatra-local-ai_0.1.121_amd64.deb`](https://github.com/singhpratech/notepatra/releases/latest) | `sudo apt install ./notepatra-local-ai_0.1.121_amd64.deb` |
+| 🐧 **Debian/Ubuntu ARM64** | [`notepatra-local-ai_0.1.121_arm64.deb`](https://github.com/singhpratech/notepatra/releases/latest) | `sudo apt install ./notepatra-local-ai_0.1.121_arm64.deb` |
**The binary physically cannot reach `api.openai.com`, `api.anthropic.com`, `openrouter.ai`, `api.mistral.ai`, `generativelanguage.googleapis.com`, or any other public LLM endpoint.** Every `QNetworkAccessManager` request goes through an allowlist that only accepts:
@@ -360,7 +360,7 @@ For teams that **can't or won't send code to public LLM endpoints** — regulate
Local Ollama, local llama.cpp, self-hosted Ollama on the LAN, and any other OpenAI-compatible server you have installed locally or on your private network — **all continue to work** in the cloud-free build. Only public-cloud LLM endpoints are blocked. The cloud-URL paste box is stripped from the UI as well, so users can't even type a public host. Auditors can confirm by running `strings notepatra | grep -c openai.com` — zero hits.
-On Linux the two flavors share the same `notepatra` binary name on disk; `apt` Conflicts ensures only one of `notepatra` / `notepatra-local-ai` is installed at a time, swap transactionally with `sudo apt install ./notepatra-local-ai_0.1.120_amd64.deb`. On Windows the two MSIs are independent products (different UpgradeCode + ProductName + install dir) so they can coexist if needed; admins typically push one or the other based on policy. `notepatra --version` self-identifies the build by name — only the bare lite build carries an edition suffix: `Notepatra Lite v0.1.120` for the lite build and `Notepatra v0.1.120` for the full build (DuckDB bundled), plus `Notepatra Local AI Lite v0.1.120` / `Notepatra Local AI v0.1.120` for the cloud-free (local-ai) builds; the same name shows in the window title bar and the About dialog.
+On Linux the two flavors share the same `notepatra` binary name on disk; `apt` Conflicts ensures only one of `notepatra` / `notepatra-local-ai` is installed at a time, swap transactionally with `sudo apt install ./notepatra-local-ai_0.1.121_amd64.deb`. On Windows the two MSIs are independent products (different UpgradeCode + ProductName + install dir) so they can coexist if needed; admins typically push one or the other based on policy. `notepatra --version` self-identifies the build by name — only the bare lite build carries an edition suffix: `Notepatra Lite v0.1.121` for the lite build and `Notepatra v0.1.121` for the full build (DuckDB bundled), plus `Notepatra Local AI Lite v0.1.121` / `Notepatra Local AI v0.1.121` for the cloud-free (local-ai) builds; the same name shows in the window title bar and the About dialog.
### Verify your download
@@ -622,6 +622,7 @@ Notepatra follows [Keep a Changelog](https://keepachangelog.com/) and [Semantic
| Version | Date | Highlights |
|---|---|---|
+| [**v0.1.121**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.121) | 2026-07-21 | **MCP design hardening — 6 fixes from live-driving all 48 verbs against a running editor (48 → 49 tools; Read 24 / Act 14 / Write 11).** `list_open_tabs` now reports an **`editable`** flag on every tab, and the read / insert / compare / save verbs gate on it — so the read-only **Welcome tab (index 0)**, previously a silent trap, returns a specific error instead of a no-op. **`save_tab` gains an optional Save-As `path`** so an AI can persist a `new_tab`'s content to disk — still Write-tier and approval-gated, path validated before the card, destination shown on it. New **`select_range`** verb (Act) finally makes `replace_selection` usable by an AI. `git_*` now falls back to the editor's **startup working directory**, so Git works when Notepatra was launched from inside a repo with no workspace open. Generic errors ("could not insert", "could not open compare view", "needs Save As") are replaced with **specific, actionable** ones. **Charts render on Qt 5.15 WebEngine** — the chart bundle now polyfills `Object.hasOwn` and `structuredClone` before the Vega scripts, which Qt 5.15's WebEngine (Chromium ~87) lacks; this had been breaking all chart rendering there (`render_chart` drew nothing, `export_chart` surfaced `e.isString`). Approval gate unchanged: every write needs an in-editor click, 120 s auto-deny, no headless bypass. |
| [**v0.1.120**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.120) | 2026-07-20 | **MCP full control — 48 tools, a remote gateway, and the sidecar finally works on Windows and macOS.** `notepatra-mcp` grows from 35 to 48 tools (Read 24 / Act 13 / Write 11), making every sub-app AI-drivable: **Diagram** (`create_diagram`, `get_diagram_source`, `set_diagram_source`), **Data-analyst** (`list_connections`, `run_query`, `list_tables`, `open_data_analyst`, `export_query_results` — reaches your saved PostgreSQL / MySQL / SQL Server / SQLite / DuckDB connections, SELECT-only and row-capped), **Charts** (`render_chart`, `export_chart`), **Noter** (`open_noter`), and **discovery** (`list_languages`, `get_capabilities`). **Two defects that made the sidecar unusable outside Linux are fixed:** the Windows named-pipe transport deadlocked on every verb — the pipe was opened without `FILE_FLAG_OVERLAPPED` and a parked reader thread blocked every write forever, so no tool call ever completed (only the first request *after* the greeting hung, which is why it looked healthy) — and on macOS the sidecar could not locate a running editor at all, because it guessed `$TMPDIR` while Qt binds under `NSTemporaryDirectory()`; the editor now publishes its real bound endpoint. New opt-in **loopback-only remote gateway** (`serve` / `pair` / `connect`, 8-digit HMAC pairing, fail-closed scopes) — the default build stays **crypto-free**, asserted in every CI job, and a remote write still raises the same local Approve card. Windows gains a prebuilt **cosign-signed sidecar zip** and a one-click **`.mcpb`** Claude Desktop bundle. `.mcpb` also fixed to stop handing Intel Macs an arm64 binary and ARM64 Linux an x64 one. Approval gate unchanged: every write needs an in-editor click, 120 s auto-deny, no headless bypass. Full offscreen ctest 71/71, sidecar 83 tests (117 with `--features remote`). |
| [**v0.1.119**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.119) | 2026-07-18 | **MCP depth — 35 tools.** The `notepatra-mcp` sidecar grows from 22 to **35 tools in three tiers** — **Read 18 / Act 9 / Write 8**. New read tools: `list_reminders`, read-only Git (`git_status` / `git_diff` / `git_log` / `git_show` / `git_branch`), `validate_npd`, and **`run_sql`** (SELECT-only). New act tool: `open_note`. New **human-approved** write verbs: `create_note`, `append_note`, `set_reminder`, `export_diagram`. `find_in_tab` / `search_project` gained an optional `regex` flag. **Windows named-pipe transport is now supported** (Linux/macOS/Windows all connect via `--socket`; prebuilt Windows binaries not yet in the signed bundle — build from source / `cargo install`). **`run_sql` security:** SELECT-only via the SQL classifier and, on the Full/DuckDB edition, an engine sandbox — the file is materialized in-memory, then `enable_external_access=false` is set before the untrusted query runs, so it cannot read host files; an adversarial security pass hardened it before ship. Bare Lite binary unchanged at 12.4 MB (the new tools live in the sidecar). Full offscreen ctest 71/71, Lite 68/68, 60 sidecar cargo tests, live end-to-end across all 35 tools. |
| [**v0.1.118**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.118) | 2026-07-17 | **MCP support — your editor, readable by your AI.** New standalone **`notepatra-mcp`** sidecar: a spec-compliant stdio JSON-RPC 2.0 [Model Context Protocol](https://modelcontextprotocol.io) server exposing **22 tools in three tiers** — read (10), act (8), and write (4) — plus open tabs / Noter notes as MCP resources and 3 ready-made prompts. Works with **Claude Desktop, Claude Code, OpenAI Codex CLI, the OpenAI Agents SDK**, and any spec-compliant stdio MCP client. **Every write is human-gated:** an Approve/Deny card inside the editor window, 120 s auto-deny, FIFO one-at-a-time, no headless bypass — the gate lives in the editor process, so no MCP client can write without a human click. Local socket + stdio only, no network connections; Linux/macOS first (Windows named-pipe transport in a future release). Prebuilt `notepatra-mcp` binaries ship as cosign-signed release artifacts; new docs page [notepatra.org/mcp.html](https://notepatra.org/mcp.html). Bare-binary size claim corrected 12.4 → 12.4 MB. Full ctest 68/68 + 47 sidecar cargo tests + live E2E 17/17. |
diff --git a/docs/docs.html b/docs/docs.html
index 6221aaf..3c4f421 100644
--- a/docs/docs.html
+++ b/docs/docs.html
@@ -299,7 +299,7 @@