AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
MCP verified MIT Self-run

Knowledge Gateway

mcp-fszalaj-knowledge-gateway · by fszalaj

Filesystem/git-native MCP knowledge gateway: an Obsidian vault + optional code-graph (incl. Ansible) and doc-to-markdown tools, served over MCP.

No reviews yet
0 installs
13 views
0.0% view→install

Install

$ agentstack add mcp-fszalaj-knowledge-gateway

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution Used
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/mcp-fszalaj-knowledge-gateway)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
26d ago

Declared compatibility

Claude CodeClaude DesktopCursorWindsurf

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Knowledge Gateway? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

knowledge-gateway

A single MCP server that gives agents (Claude Code, Codex, Cursor, Gemini, Copilot, Antigravity) three capabilities over one connection:

  • Vault - read, search, and edit a git-backed Markdown/Obsidian vault (no Obsidian GUI), git as the source of truth.
  • Code graph (optional [graph] / [graph-all]) - build and query a code/Ansible knowledge graph of a repo (functions, calls, roles, tasks, handlers, task -> filter edges); AST-only, local, no LLM.
  • Convert (optional [convert]) - turn PDF / Office / image / HTML files into Markdown.

The vault layer exists because the Obsidian Local REST API plugin serves only the one vault open in a running desktop instance, writes without a lock (silent lost updates), needs a token in every client, and treats git as secondary. This gateway operates on the files directly, with git as the system of record - and adds the graph + convert tools the same way: one server, opt-in extras, no new servers to wire.

Architecture

flowchart LR
    subgraph clients [Agents]
        A1[Claude Code]
        A2[Codex]
        A3[Gemini]
        A4[Copilot - VS Code]
        A5[Cursor]
        A6[Antigravity]
    end
    A1 --- M(( MCP ))
    A2 --- M
    A3 --- M
    A4 --- M
    A5 --- M
    A6 --- M
    M -->|stdio, per repo, no auth| L[Local gateway]
    M -->|HTTP + bearer + ACL| S[Shared gateway]
    L --> V[/Vault: Markdown files/]
    S --> V
    V |atomic write + scoped commit| G[(git)]

Both modes run the same tool implementation over the same path guards; they differ in transport, authentication/ACL, vault loading, and error masking.

Two ways to run

| | Local mode (per repo) | Shared server (team) | |---|---|---| | Use when | a repo wants its own vault for its agents | many people/vaults behind one always-on endpoint | | Transport | stdio subprocess (launched by .mcp.json) | HTTP (put behind Tailscale/HTTPS) | | Secrets / tokens | none - nothing to generate | per-user bearer tokens (admin-generated) | | Trust boundary | local filesystem access you already have | tailnet + HTTPS + per-vault ACL | | Obsidian needed | no | no |

Most repos want Local mode. The shared server is only for a central, always-on team gateway.

Distribution - the stable branch ("update once")

The gateway ships from one moving branch, so a release reaches every consumer and server without re-pinning anything by hand.

flowchart LR
    PR[merge PR to main] --> TAG[tag vX.Y.Z]
    TAG --> MV[move stable -> vX.Y.Z]
    MV --> C["Consumersuvx --refresh @stable(updates next session)"]
    MV --> S["Serversdaily uv tool reinstall(restart if stable moved)"]
  • Consumers pin @stable with uvx --refresh -> the ref is re-fetched on every launch, so

a new release auto-propagates the next time an agent starts. No per-repo re-pin.

  • Servers (long-running) run a pinned uv tool install @stable plus a daily job that

reinstalls + restarts only when stable actually moves.

  • Every release is also an immutable vX.Y.Z tag - pin a tag instead of stable when you

need a frozen, auditable version.

> A moving tag does not work (uvx caches the resolved commit); a branch + --refresh does.

Quickstart - local mode (zero secrets)

Add this to the repo's .mcp.json at the repo root:

{
  "mcpServers": {
    "wiki": {
      "command": "uvx",
      "args": ["--refresh", "--from", "git+https://github.com/fszalaj/knowledge-gateway@stable",
               "knowledge-gateway", "--local"]
    }
  }
}
  • --local auto-detects the vault in the cwd, in order: the cwd itself if it has .obsidian/,

then ./wiki, then a single *-obsidian-vault/, then a single child dir with .obsidian/ (ambiguous matches error). Pass --vault ./ to be explicit.

  • --refresh re-fetches @stable each launch, so releases auto-apply (adds ~1-2s to start).
  • Commits are scoped to the vault's git subdir and attributed to your own

git config user.name/email. No token: the trust boundary is local filesystem access.

Open the repo in your agent, approve the wiki server once, done.

Tools

| Tool | | |---|---| | list_vaults | vaults reachable here | | list_notes | Markdown paths in a vault | | read_note | raw note content | | list_attachments / read_attachment | list / read binary attachments (image -> inline Image, else File) | | list_canvases / read_canvas / write_canvas | list / read / write Obsidian Canvas (nodes, groups, colors) | | search | ripgrep literal/regex full-text | | backlinks | notes that [[wikilink]] to a note | | list_tags | inline #tags with counts | | query_notes | find notes by frontmatter type / tag (headless Dataview-lite) | | write_note | atomic write (+ optional commit) | | patch_note | insert after a heading or at top/bottom, no full rewrite (+ commit) | | patch_frontmatter | update YAML frontmatter keys, body intact (+ commit) | | delete_note | delete a note (+ optional commit) | | rename_note | rename/move + rewrite inbound flat [[wikilinks]] when the name changes (+ optional commit) | | git_status / git_commit | pending changes / commit (subdir-scoped, attributed) | | list_graphs / graph_query / graph_neighbors / god_nodes / graph_shortest_path / graph_stats | query a built code graph (optional [graph]) | | graph_build | build a code/Ansible graph from a source tree into .graph/.json (local mode only) | | convert_to_markdown | convert a file (PDF/Office/image/HTML/...) in the vault to Markdown (optional [convert]) |

Edits are atomic (temp file + rename). Every path goes through safe_note_path, which blocks traversal, symlink escape, hidden/dotfiles, non-.md targets, and .git/.obsidian - a caller can never read or write outside the vault's notes.

Code graph and conversion (optional)

Two opt-in capabilities, gated behind extras so the core install stays dependency-free:

| Extra | Adds | |---|---| | [graph] | Python (ast) + Ansible (PyYAML) code graph + the query tools | | [graph-all] | the above + a broad tree-sitter pass over ~30 languages (JS/TS/TSX, Go, Rust, Java, C#, C/C++, Ruby, PHP, bash, PowerShell, Terraform/HCL, Lua, Kotlin, Swift, Scala, R, Perl, Elixir, Dart, SQL, ...): definitions, imports, and within-file calls | | [convert] | attachment -> Markdown via markitdown |

Build a graph (AST-only - local, no network, no LLM) where the code lives:

knowledge-gateway-graph /path/to/code-repo -o /path/to/vault/.graph/myrepo.json
# in a local-mode session the graph_build tool does the same, writing .graph/.json

Query it over MCP with graph_query / graph_neighbors / god_nodes / graph_shortest_path / graph_stats. The graph captures functions/classes/imports/calls and - uniquely for Ansible - roles, tasks, handlers, include_role/import_tasks/notify, and task -> filter plugin edges. Graph files live in the vault's .graph/, are vault-contained (resolved + checked to stay inside the vault), and are read-only to the gateway - the vault tools never depend on them.

Shared server mode

Run this only for a central, always-on gateway reachable over the network.

1. Map vaults - cp vaults.example.yaml vaults.yaml, then set name -> path / repo_root / subdir. repo_root + subdir pathspec-scope commits to a vault that lives inside a larger repo.

2. Mint a token per user (the admin does this):

cp tokens.example.yaml tokens.yaml
openssl rand -hex 32          # once PER user -> the key
chmod 0600 tokens.yaml        # refused at load if group/world-readable
tokens:
  "8f3c…hex…":
    sub: alice                # identity recorded on that user's commits
    vaults: [teamwiki]        # the ONLY vaults this token may see/touch
    write: true               # false = read-only

A token sees only the vaults in its vaults list; anything else returns an opaque vault_forbidden. vaults.yaml + tokens.yaml are gitignored.

3. Run - uv run knowledge-gateway (127.0.0.1:8765, path /mcp/). For a team box, run it as a service behind Tailscale Serve - see deploy/ and Operate below.

4. Connect - the admin shares the token over a password manager (not chat):

claude mcp add --transport http --scope project teamwiki \
  https://YOUR-HOST..ts.net/mcp/ --header "Authorization: Bearer $GW_TOKEN"

Security model

  • No secrets in the repo. vaults.yaml / tokens.yaml are gitignored; only

*.example.yaml ship. tokens.yaml is refused at load if group/world-readable.

  • Local mode has no credential surface - a local stdio subprocess; the trust boundary is

filesystem access the user already has.

  • Server mode is defense in depth, not a public endpoint - tailnet ACL + HTTPS + per-user

StaticTokenVerifier bearer token + per-vault ACL. The bearer layer is a shared secret for use behind a trusted tailnet; do not expose the server publicly.

  • Path guards on all note I/O via safe_note_path (traversal, symlink, hidden/dotfiles

incl. .env, non-.md, .git/.obsidian). Search/backlinks/tags are bounded to *.md.

  • Server-mode error masking - the HTTP server runs mask_error_details=True: only the

gateway's own expected failures surface as ToolError; unexpected OS/git errors are hidden. Local mode keeps details visible.

  • Commits are attributed to the requesting user (server) or the local git identity (local),

and pathspec-scoped to the vault subdir.

Set it up with an AI

Paste this into an agent at a repo's root to wire in local mode:

Add the knowledge-gateway to this repo so agents can read/edit our vault over MCP with zero
tokens:
1. Create or merge `.mcp.json` at the repo root with an mcpServers."wiki" entry that runs:
   uvx --refresh --from git+https://github.com/fszalaj/knowledge-gateway@stable knowledge-gateway --local
   (`--local` auto-detects the vault: ./wiki, a *-obsidian-vault dir, or a dir with .obsidian/.
   If detection is ambiguous, use `--vault ./` instead of `--local`.)
2. Verify: `uvx --refresh --from git+https://github.com/fszalaj/knowledge-gateway@stable \
   knowledge-gateway --help` resolves; then in the agent, call list_vaults and read one note.
Branch + PR, no direct push, no AI attribution.

For the shared server, ask your gateway admin for a token, then run the claude mcp add … from Connect above.

Operate (servers)

A server runs the @stable release as a uv tool, with a daily job that reinstalls and restarts only when stable moved. Reference units are in deploy/:

uv tool install --from git+https://github.com/fszalaj/knowledge-gateway@stable knowledge-gateway
# the binary lives in the uv cache, so point config at the live files via env:
#   KNOWLEDGE_GATEWAY_VAULTS=/vaults.yaml   KNOWLEDGE_GATEWAY_TOKENS=/tokens.yaml
  • deploy/knowledge-gateway.service - the service (systemd --user).
  • deploy/knowledge-gateway-update.{service,timer} + deploy/auto-update.sh - the daily auto-update.

Update now instead of waiting for the timer: uv tool install --reinstall --from git+https://github.com/fszalaj/knowledge-gateway@stable knowledge-gateway, then restart the service. Health: curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8765/mcp/ -> 401.

Release (maintainers)

  1. PR -> merge to main (CI: uv lock --check, pytest matrix).
  2. Bump pyproject.toml version + CHANGELOG.md.
  3. Tag vX.Y.Z and push the tag (the release workflow builds it).
  4. Move stable: git branch -f stable vX.Y.Z && git push --force-with-lease origin stable.

Consumers pick it up next session; servers within a day (or restart now).

Develop

uv venv && uv pip install -e ".[dev]"
uv run pytest                              # ACL + path guards + edit/frontmatter + detect + masking

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.