Skip to main content
Glama

pebble-index-mcp

MCP bridge that exposes a local Obsidian vault and a Hermes Agent instance to the Pebble Index 01 smart ring's double-click MCP sandbox. Voice captures from the ring are routed by the Pebble app's cloud agent into this server's tools, and the answer comes back as a phone notification.

Architecture

[Index ring] → [Pebble app] → [Pebble cloud agent] → [this MCP server]
                                                        ├─ vault tools (local files)
                                                        └─ ask_hermes → Hermes API server
  • The server speaks MCP over Streamable HTTP (official mcp SDK, FastMCP).

  • Every request must carry a bearer token; anything else gets 401.

  • FastMCP's DNS-rebinding protection is on: allowed hosts are loopback plus anything listed in MCP_ALLOWED_HOSTS.

  • The public exposure is a cloudflared tunnel to the loopback port; no cloud infrastructure is required beyond that.

Related MCP server: Obsidian MCP Server

Components

Path

Role

src/pebble_index_mcp/vault.py

Vault: path-sandboxed read/append + ripgrep search over the vault. All paths resolve inside the vault root; absolute paths, .. traversal, and symlink escapes are rejected. Appends are append-only, timestamped, and never overwrite.

src/pebble_index_mcp/hermes.py

HermesClient: forwards questions to an OpenAI-compatible chat completions endpoint with a short-answer system hint. Maps timeouts/transport failures/bad shapes onto HermesTimeout/HermesError.

src/pebble_index_mcp/server.py

FastMCP app: registers the four tools and the ring_persona prompt, wraps the streamable-http app in bearer auth (constant-time compare) and configures host allow-listing.

Tools

  • vault_search(query, max_results=5) — case-insensitive text search; returns path: excerpt lines.

  • vault_read(note_path, max_chars=1500) — reads the head of a note.

  • vault_append(note_path, text) — appends a timestamped - HH:MM text line, creating the note if needed.

  • ask_hermes(question) — forwards to the Hermes API server; 60s timeout with an honest acknowledgment on miss.

Security

  • Auth: static bearer token (MCP_BEARER_TOKEN), constant-time compared, required on every request. An empty token fails closed (all requests 401) and logs a warning at startup.

  • Transport: TLS terminates at the tunnel edge; the origin listens on loopback only.

  • Host validation: DNS-rebinding protection rejects requests whose Host header is not loopback or in MCP_ALLOWED_HOSTS.

  • Path sandbox: vault tools resolve all paths and require them to stay inside the vault root; symlink escapes are rejected and file opens use O_NOFOLLOW on the final component. The sandbox guards against accidental and remote misuse; a hostile local process that races a parent-directory swap can still win (documented TOCTOU boundary — the vault is assumed to be a trusted single-user directory).

  • Config is read once at import: rotating the bearer token or changing allowed hosts requires a service restart.

  • Secrets: the Hermes API key and MCP token live in a 0600 env file outside this repo, never in code, logs, or commits.

  • Privacy note: recordings routed through the double-click sandbox transit the Pebble app's cloud agent. Single-click captures stay on-device. Sensitive thoughts belong on single-click.

Configuration (env)

Var

Default

Purpose

VAULT_PATH

Required. Vault root for the file tools

MCP_HOST / MCP_PORT

127.0.0.1 / 8765

Listen address

MCP_BEARER_TOKEN

Required; request auth token

MCP_ALLOWED_HOSTS

Comma-separated extra allowed Host values (the public tunnel hostname goes here)

HERMES_API_URL

http://127.0.0.1:8642/v1/chat/completions

ask_hermes target

HERMES_API_KEY

API server bearer key

RING_MODEL

pebble-ring

Model alias sent upstream (map it to a cheap model via the API server's model_routes)

RING_PERSONA_FILE

Optional path to a text file replacing the generic cloud-agent persona

HERMES_API_URL accepts any OpenAI-compatible chat completions endpoint, so ask_hermes works against OpenRouter directly, Ollama, or any other compatible API — Hermes is just the default.

Development

python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/pytest -v

Run locally: set the env vars above and python -m pebble_index_mcp.server.

Deployment

deploy/ contains a systemd user unit template and a cloudflared tunnel template (hostname and credentials filled in on the host, not in this repo). See docs/ring-checklist.md for the phone-side setup and test matrix.

License

MIT — see LICENSE.

Related MCP Connectors

Related MCP Servers