npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mastervault-mcp-server

v1.4.0

Published

A headless, filesystem-backed MCP server that serves any MasterVault — its files and its operating protocol — to any MCP client. No Obsidian required.

Downloads

33

Readme

MasterVault MCP Server

A headless, filesystem-backed Model Context Protocol server that serves any MasterVault — its files and its operating protocol — to any MCP client, over stdio. No Obsidian required.

Point it at a vault directory; any MCP-capable LLM client (ModelForge, Claude Desktop, AnythingLLM, etc.) can then orient on the vault's protocol, read and search its contents, log decisions, and soft-delete files — all behind the client's own approval flow.

Why this exists

An Obsidian vault can already be served over MCP via the Local REST API plugin, but that ties it to Obsidian. This server drops the Obsidian dependency: it speaks the same vault semantics against a plain directory, so the MasterVault becomes portable to any client and any model. It also surfaces the vault's protocol (orientation, decision-logging, soft-delete), not just its files — so a fresh LLM can run the system, not merely read it.

Install

Run it directly, no install step:

npx -y mastervault-mcp-server /absolute/path/to/vault

Or install it globally for a shorter command:

npm install -g mastervault-mcp-server
mastervault-mcp-server /absolute/path/to/vault

Requires Node.js 18+.

From source (for contributing)

git clone https://github.com/JustMichael-80/mastervault-mcp-server.git
cd mastervault-mcp-server
npm install      # also builds via the prepare script
npm run build    # (if you skipped prepare)

Run

mastervault-mcp-server /absolute/path/to/vault
# or
MASTERVAULT_ROOT=/absolute/path/to/vault node dist/index.js

The vault path is the only configuration. Nothing is hardcoded — the same binary serves any vault.

Multi-vault discovery

Point the server at a parent directory instead of a single vault, and it discovers every MasterVault beneath it (any directory containing an _orientation.md):

mastervault-mcp-server --discover /path/to/projects-root

The first discovered vault (alphabetically) becomes the active vault; the mastervault_list_vaults tool lists all of them by name. The scan is depth-bounded, skips hidden and dependency directories, and does not follow symlinks out of the tree. Discovery only locates vaults — every file operation stays confined to the active vault's sanitized root, so a vault name can never select an arbitrary path.

Discovery was contributed by VDMO (https://github.com/vdmo).

Bundled single-file build

For vendoring or shipping the server as one self-contained file with no npm install at the consumer end:

npm run build:bundled
# produces dist-bundled/index.js — all dependencies inlined (~890kb)
node dist-bundled/index.js /absolute/path/to/vault

The bundle is produced by esbuild (Node 18 target, ESM) with a createRequire shim for CommonJS interop. Useful when another application packages this server as a component rather than depending on it as an installed module.

Connecting a client

ModelForge

In Settings → MCP servers, add a stdio server:

  • Command: node
  • Args: /absolute/path/to/mastervault-mcp-server/dist/index.js /absolute/path/to/vault

(or use the mastervault-mcp-server bin directly if installed globally). The server's tools then appear in Agent mode's tool list, each behind ModelForge's Allow/Deny approval — exactly like its built-in file tools.

Any MCP client (generic stdio config)

{
  "mcpServers": {
    "mastervault": {
      "command": "node",
      "args": ["/absolute/path/to/dist/index.js", "/absolute/path/to/vault"]
    }
  }
}

Tools

| Tool | Tier | Read-only | What it does | |------|------|:---------:|--------------| | mastervault_orient | protocol | ✅ | Reads the orientation file and the protocol files it points to, in order. Also returns context_file_status — CLEO_context.md's mtime, its age in days, and whether it's ≥14 days old — so a client can run the protocol's staleness check without a separate stat tool. null if that file doesn't exist. Call this first. | | mastervault_get_confidence_summary | protocol | ✅ | Returns the calibration dashboard (_Meta/Confidence Summary.md). | | mastervault_log_decision | protocol | ✍️ | Appends a consequential decision (proposal + confidence + verdict) to the right category in _Meta/Decision Log.md. | | mastervault_read | files | ✅ | Reads a file, optionally by line range; parses markdown frontmatter. | | mastervault_list | files | ✅ | Lists a directory, paginated, directories first. | | mastervault_search | files | ✅ | Case-insensitive full-text search across text files. | | mastervault_write | files | ✍️ | Creates or overwrites a file. | | mastervault_patch | files | ✍️ | Replaces one exact, unique text block in a file. | | mastervault_stage_delete | delete | ✍️ | Moves a file to _ToDelete/ and logs the proposal. Never hard-deletes. | | mastervault_git_status | git | ✅ | Git status of the vault (if under version control). | | mastervault_git_log | git | ✅ | Recent commits. | | mastervault_git_diff | git | ✅ | Working-tree or staged diff, optionally for one file. |

Every tool supports response_format: "markdown" (default) or "json". The three git tools are read-only; on a non-git vault they return a clear "not a repository" message rather than an error. In --discover mode, mastervault_list_vaults is also exposed.

Large responses in json format

Every tool response carries two representations: a text rendering (content[0].text) and structured data (structuredContent). This server enforces a response size limit on the text side (CHARACTER_LIMIT, 25,000 characters) so a single call can't blow out a client's context window. structuredContent is never truncated by this limit, regardless of format — it always carries the complete data. The size limit only ever shapes what shows up in the text body.

For response_format: "markdown", exceeding the limit just shortens the document with a trailing [Response truncated at N characters...] note — safe, since it's free text.

For response_format: "json", content[0].text is a JSON.stringify'd blob, and slicing that string by raw character count can cut it mid-token — producing text that looks like JSON but fails to parse. Every JSON-format tool response avoids this by bounding the object before stringifying, not the string after, so content[0].text is always valid JSON. Depending on the tool, this shows up as one of:

  • truncated: true + truncated_fields: [...] — one or more string fields (e.g. mastervault_read's content, mastervault_git_diff's output, mastervault_orient's largest file bodies, named individually as truncated_files) were shortened, with a visible [...elided: <field> truncated at N of M characters for size...] marker left at the cut point. The kept text is never cut mid-character — a cut that would split a multi-byte character (e.g. mid-emoji) backs off by one position first, so the result always round-trips cleanly through UTF-8 encode/decode.
  • json_size_truncated: true + json_size_truncated_count: N (mastervault_list, mastervault_search) — the array field itself (entries, hits) was too large as a whole page, so N trailing elements were dropped from the text body and the last surviving element was replaced with a sentinel object — { _elided: true, note, dropped_count } — so the gap is visible directly in the array, not only in a sibling key easy to miss when scanning entries. This is distinct from mastervault_search's own truncated/total/count fields, which mean "more matches exist beyond limit" — a pagination concern, not a size-on-the-wire concern. Both can be true at once and mean different things.
  • A minimal fallback envelope ({ truncated: true, truncation_note, keys }) — only for a tool response with no field the server knows how to shrink. As of this fix, every tool reachable with a large realistic payload (read, git_diff, list, search, orient) has a proper elidable field instead; this fallback exists as a safety net for anything unforeseen, not as expected behavior for any current tool.

Security model

  • Path confinement is the single security boundary. Every path is resolved and confined to the vault root before any filesystem call. Lexical .. traversal, absolute paths, and null bytes are rejected; a leading slash is treated as vault-relative, not filesystem-absolute. Existing paths get a second realpath check so a symlink inside the vault can't point out of it.
  • No hard delete. The server has no tool that destroys data. stage_delete only moves files into _ToDelete/; a human is the sole final actor who empties it. This is why stage_delete is marked non-destructive — it's reversible by design.
  • No shell execution. File operations only. If a client needs shell access it provides that itself (ModelForge does, sandboxed and gated separately).
  • stdio hygiene. All logging goes to stderr; stdout carries only the MCP protocol.

The MasterVault protocol layer

This server is more than a file server because of three conventions it understands:

  • _orientation.md — the entry point a fresh LLM reads first (via mastervault_orient) to inherit the vault's working rules.
  • _Meta/Decision Log.md + Confidence Summary.md — a decision-logging + calibration system: consequential proposals are logged with a pre-verdict confidence estimate, and the gap between estimate and outcome accumulates into a per-category calibration signal.
  • _ToDelete/ — the soft-delete staging area; the human is always the final actor on removal.

A vault that lacks these still works as a plain file tree — the protocol tools report what's missing rather than failing.

Development

npm run dev            # tsx watch
npm run build          # tsc -> dist/
npm run build:bundled  # esbuild -> dist-bundled/index.js (single file)
npm test               # node --test, 42 tests
npm start              # node dist/index.js <vault>

Tests

The suite (test/vault.test.mjs, test/tools.test.mjs, test/git.test.mjs, test/wire.test.mjs) covers the filesystem layer, the path-confinement security boundary (traversal, absolute paths, null bytes, symlink-escape), and the tool layer (patch match rejection, section-aware decision logging, soft-delete collision handling). A note on platform coverage: automated CI typically runs on Linux, which cannot reproduce every macOS-specific filesystem behavior (symlink canonicalization, path case-sensitivity, /var→/private/var-style redirects). A green CI run is necessary but not sufficient for those behaviors specifically — verify on macOS directly (not a Linux CI runner or container) before relying on filesystem-boundary tests. A green run on macOS is evidence for macOS behavior; it says nothing about Linux or Windows.

test/vault.test.mjs and test/tools.test.mjs stub the MCP SDK's registerTool and call handlers directly in-process — fast, but structurally blind to anything that only breaks during actual MCP wire serialization. test/wire.test.mjs closes that gap: it spawns the real built server (dist/index.js) and drives it through an actual MCP Client over stdio, with fixtures sized to exceed CHARACTER_LIMIT on ordinary content (a large file read, an uncommitted diff, a directory listing with long filenames, a search with many hits, and emoji content sized to force a cut exactly inside a UTF-16 surrogate pair). It asserts content[0].text always parses as valid JSON, elided text round-trips byte-identically through UTF-8 encode/decode, and structuredContent is always the complete, untruncated data.

License

MIT