Skip to content

feat: lownotes-mcp bridge for MCP clients - #113

Merged
FabioHAraujo merged 7 commits into
mainfrom
feat/mcp-bridge
Oct 29, 2026
Merged

FabioHAraujo merged 7 commits into
mainfrom
feat/mcp-bridge

Conversation

@FabioHAraujo

Copy link
Copy Markdown
Contributor

Stacked on #109 (MCP server); the base becomes main once #109 merges.

MCP clients (Claude Desktop, Claude Code, Cursor) launch local servers as a process and talk over stdio. lownotes-mcp is that process: it relays between the client's stdio and the running LowNotes.

The bridge

  • Binary: src-tauri/src/bin/lownotes-mcp.rs, a console binary. It calls mcp_bridge::run() in the library, so it shares the endpoint and credential code with the app. default-run = "lownotes" keeps cargo run and tauri dev on the app.
  • Token: read from the OS credential store through the reference in settings.json, without writing the file. When MCP is off, or the app has not created a token yet, the bridge says so instead.
  • Windows endpoint check: pipe names are machine-wide, so before sending the token the bridge checks that the process serving the pipe runs as the same user (GetNamedPipeServerProcessId, then the process token's SID).
  • Unix: the socket sits in a folder only the user can enter, so no extra check is needed.
  • Relay: after the OK handshake, bytes are copied both ways, flushing every chunk to stdout. The bridge exits when either side closes.
  • When LowNotes cannot be reached: the bridge answers the client's first request with a JSON-RPC error that says why, then exits with code 1. The possible reasons are: app not open, MCP off, token refused, endpoint owned by another user, credential store unavailable, or too many clients.
  • Logs: stderr through tracing, at warn by default (LOWNOTES_LOG overrides it). No note content or token.

Shipping

  • Tauri bundles src/bin/* next to the app, so the NSIS/MSI installers, the .app, and the .deb, .rpm and AppImage packages include it.
  • release.yml:
    • the Windows portable zip and the Linux portable tarball carry lownotes-mcp;
    • the per-architecture macOS jobs upload both binaries, and the universal job runs lipo on each before tauri bundle;
    • the Arch package (PKGBUILD.ci and the AUR template) installs /usr/bin/lownotes-mcp with its own checksum.
  • bundle.yml checks that the debug .deb ships /usr/bin/lownotes-mcp.

Tests

  • Bridge relay: a test connects the bridge to a real server over a named pipe on Windows (a Unix socket on CI), then runs initialize and tools/call and checks the exit code when the client closes.
  • Refusals: a wrong token comes back as a JSON-RPC error with the request's id. Both "LowNotes not open" and "MCP off" are answered on the first request, while notifications are skipped.
  • Token lookup: the bridge finds the token reference the app saved, and only while MCP is enabled.
  • Manual: with MCP off, echo '{"jsonrpc":"2.0","id":1,"method":"initialize"}' | lownotes-mcp prints the error and exits 1.

Full AGENTS.md verification on Windows: bun install --frozen-lockfile, version:check, check, check:e2e, bun test, the Python script tests, cargo fmt --check, cargo clippy --lib --bins --tests -D warnings, cargo test --locked --lib, bun run build and test:e2e all pass.

Not verified locally: the macOS universal release path and the Arch package. Both run only in the release workflow.

Closes #102

LowNotes serves the open vault to MCP clients over a per-user named pipe
(Windows) or Unix socket, after a token handshake. The token lives in the OS
credential store and never reaches the webview. Tools list, read and search
notes and read links and backlinks; a resource template exposes notes by path.
Off by default, and only vaults listed in the MCP settings are served.

Closes #101
MCP clients launch lownotes-mcp, which reads the token from the OS
credential store, checks that the pipe it reached belongs to the same
Windows user, completes the handshake and relays stdio to the running app.
When LowNotes is closed or MCP is off, it answers the first request with a
JSON-RPC error that says why.

Tauri bundles the binary next to the app; the release workflow adds it to
the portable archives, the universal macOS build and the Arch packages, and
the bundle smoke test checks the .deb ships it.

Closes #102
@FabioHAraujo FabioHAraujo added enhancement New feature or request priority: P2 Important: performance, architecture or release quality size: M Medium: a few days area: ci-cd GitHub Actions workflows and checks area: release Packaging, signing, updater and distribution rust Pull requests that update rust code labels Oct 29, 2026
@FabioHAraujo
FabioHAraujo changed the base branch from feat/mcp-server to main October 29, 2026 20:39
@FabioHAraujo
FabioHAraujo merged commit b15954d into main Oct 29, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: ci-cd GitHub Actions workflows and checks area: release Packaging, signing, updater and distribution enhancement New feature or request priority: P2 Important: performance, architecture or release quality rust Pull requests that update rust code size: M Medium: a few days

Projects

None yet

Development

Successfully merging this pull request may close these issues.

lownotes-mcp: stdio bridge for MCP clients, shipped on all platforms

1 participant