Doc Manager

Doc Manager

Zero-knowledge document vault backed by Azure Blob Storage with built-in MCP server. Client-side AES-256-GCM encryption, five tools (list, get, search, create, update), and OAuth-gated access for Claude.

Category
Visit Server

README

Doc Manager

<p align="center"> <a href="https://glama.ai/mcp/servers/giuliohome-org/doc-manager"> <img alt="doc-manager MCP server on Glama" src="https://glama.ai/mcp/servers/giuliohome-org/doc-manager/badges/card.svg" /> </a> </p>

A zero-knowledge document vault backed by Azure Blob Storage, with a built-in MCP server so you can add, read and search your docs straight from a Claude conversation.

<p align="center"> <img alt="Claude on the left creates a document through the Doc Manager MCP connector; the web UI on the right shows it instantly in the vault" src="https://github.com/user-attachments/assets/5deab74c-b3a0-4b17-b101-c0f287e2eb68" /> </p> <p align="center"><sub><i>Talk to your docs through Claude — create from chat, see it in the vault instantly.</i></sub></p>

  • Zero-knowledge by design — documents and attachments are encrypted in the browser with AES-256-GCM (PBKDF2-SHA256, 600k iterations); the password never leaves the client.
  • Talk to your docs — Claude (web, desktop, Claude Code) can list, fetch, search, create and update plaintext documents through the MCP endpoint.
  • One Rust binary — Rocket backend + React 19 / Vite 8 frontend, deployable to Azure Container Apps, plain Docker, or containerd + Kaniko in a homelab.

Talking to your docs through Claude

The same Rust process exposes a Streamable-HTTP [Model Context Protocol] (https://modelcontextprotocol.io) server at /mcp, gated by an OAuth 2.1 flow against an upstream identity provider (currently GitHub — Auth0 reserved for a future round, the code is provider-shaped). Encrypted documents stay private (their content is never returned to Claude); plaintext documents become first-class citizens in the chat.

Tools

Tool What it does Available in MCP_READ_ONLY
list_documents List every doc with id, title, encrypted flag, attachment info, size yes
get_document Fetch one plaintext document by id; refuses encrypted ones yes
search_documents Case-insensitive substring search over titles (always) and plaintext content yes
get_attachment Fetch the file attached to a doc (filename, bytes, base64, UTF-8 if applicable) yes
create_document Create a new plaintext document; returns the new id no
update_document Replace content (and optionally title) of a plaintext document no
add_attachment Attach a file (text or base64-encoded binary) to a doc; replaces any existing no
delete_document Delete a document and all its blobs (main, title, attachment); irreversible no
delete_attachment Delete only the attachment of a document, leaving the document itself intact no

Encrypted documents are surfaced to Claude with encrypted: true so it can discover them by title, but their contents and writes are refused server-side. That keeps the zero-knowledge guarantee intact: encrypted = "private to me", plaintext = "shareable with Claude".

Add it to Claude

Claude.ai's custom-connector advanced settings accept an OAuth Client ID + Client Secret (only those two fields), so Claude.ai runs the full OAuth 2.1 + PKCE flow itself and our server only needs to (a) advertise the IdP via well-known metadata and (b) validate the resulting bearer.

  1. Register a GitHub OAuth App. GitHub → SettingsDeveloper settingsOAuth AppsNew OAuth App. Set:
    • Authorization callback URL: https://claude.ai/api/mcp/auth_callback
    • Copy the Client ID and generate a Client Secret.
  2. Configure the server (env vars on the container app):
    export OAUTH_PROVIDER=github
    export OAUTH_PUBLIC_BASE_URL=https://doc-manager.giuliohome.com
    export OAUTH_ALLOWED_USERS=giuliohome     # comma-separated GitHub logins
    # optional — disables create/update tools:
    export MCP_READ_ONLY=true
    
    OAUTH_ALLOWED_USERS is required — an empty allowlist refuses to start, so a misconfiguration cannot silently let any GitHub user in.
  3. Add the connector in Claude.ai — Settings → Connectors → Add custom connector, URL https://doc-manager.giuliohome.com/mcp, then Advanced settings → paste the GitHub OAuth App's Client ID and Client Secret. The first request triggers the OAuth dance: Claude.ai sees the 401 + WWW-Authenticate from /mcp, fetches our well-known metadata, walks you through github.com/login/oauth/authorize, and forwards the resulting bearer on every subsequent call. The server validates each request by calling https://api.github.com/user (5-min cache, SHA-256-hashed token key).

If OAUTH_PROVIDER is unset the endpoint replies 503 Service Unavailable, so the MCP surface is fully opt-in.


Building the frontend

cd frontend
npm i
npm run build
cd ..

Running with Docker

docker build -t giuliohome/doc-manager:latest .
export AZURE_STORAGE_ACCOUNT=youraccount
export AZURE_STORAGE_ACCESS_KEY=yourkey
export RUST_ROCKET_EXACT_ORIGIN=http://localhost:8080
# optional — enables the MCP endpoint:
export OAUTH_PROVIDER=github
export OAUTH_PUBLIC_BASE_URL=http://localhost:8080
export OAUTH_ALLOWED_USERS=your-github-login
docker run -p 8080:8080 \
  -e AZURE_STORAGE_ACCOUNT \
  -e AZURE_STORAGE_ACCESS_KEY \
  -e RUST_ROCKET_EXACT_ORIGIN \
  -e OAUTH_PROVIDER \
  -e OAUTH_PUBLIC_BASE_URL \
  -e OAUTH_ALLOWED_USERS \
  giuliohome/doc-manager:latest

TL;DR — containerd + Kaniko (homelab)

sudo mkdir /kcache
sudo ctr i pull gcr.io/kaniko-project/warmer:latest
sudo ctr run --net-host --rm --mount type=bind,src=$(pwd),dst=/workspace,options=rbind:rw --mount type=bind,src=/kcache,dst=/cache,options=rbind:rw gcr.io/kaniko-project/warmer:latest kaniko-warmer /kaniko/warmer --cache-dir=/cache --image=docker.io/rust:1-slim-bookworm --skip-tls-verify-registry index.docker.io --dockerfile=/workspace/Dockerfile

sudo ctr i pull gcr.io/kaniko-project/executor:latest
sudo ctr run --net-host --rm --mount type=bind,src=$(pwd),dst=/workspace,options=rbind:rw --mount type=bind,src=/kcache,dst=/cache,options=rbind:rw gcr.io/kaniko-project/executor:latest kaniko-executor /kaniko/executor -cache-dir=/cache --dockerfile=/workspace/Dockerfile --context=/workspace --no-push --skip-tls-verify --build-arg pkg=docs-app --tarPath=/workspace/doc-manager-latest.tar --destination=giuliohome/doc-manager:latest --cache=true --cache-repo=giuliohome/doc-manager:latest --no-push-cache

sudo ctr image import doc-manager-latest.tar
sudo ctr c create --net-host docker.io/giuliohome/doc-manager:latest doc-manager
sudo ctr t start doc-manager

<img width="1906" alt="image" src="https://github.com/user-attachments/assets/e8c7cecb-adac-4f5f-9f94-143b0e867e3d" />

<img width="1897" alt="image" src="https://github.com/user-attachments/assets/64cfae0f-47fa-40b5-a743-b0f02e160b78" />

Configuration reference

Env var Required Purpose
AZURE_STORAGE_ACCOUNT yes Azure Storage account name (container documents is auto-created)
AZURE_STORAGE_ACCESS_KEY yes Storage access key
RUST_ROCKET_EXACT_ORIGIN yes CORS origin for the React frontend
OAUTH_PROVIDER no (enables MCP) github (Auth0 reserved for future)
OAUTH_PUBLIC_BASE_URL with OAUTH_PROVIDER Public base URL of this server, e.g. https://doc-manager.giuliohome.com
OAUTH_ALLOWED_USERS with OAUTH_PROVIDER Comma-separated GitHub logins; must list at least one user — empty refuses to start
MCP_READ_ONLY no (default false) When true/1/yes, hides create/update MCP tools
MCP_PUBLIC_INTROSPECT no (auto) Opens /mcp for unauthenticated tools/list only (calls are 403'd) so registries like Glama can probe. Auto-on when both AZURE_STORAGE_ACCOUNT and OAUTH_PROVIDER are unset; set 0 to force-disable.
MCP_STDIO no (default false) When true/1/yes (or pass --stdio), runs as a stdio MCP server (newline-delimited JSON-RPC on stdin/stdout) instead of starting the HTTP listener. Used by registries that wrap servers with mcp-proxy.

End-to-end tests

See the e2e repo.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured