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.
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.
- Register a GitHub OAuth App. GitHub → Settings → Developer
settings → OAuth Apps → New OAuth App. Set:
- Authorization callback URL:
https://claude.ai/api/mcp/auth_callback - Copy the Client ID and generate a Client Secret.
- Authorization callback URL:
- 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=trueOAUTH_ALLOWED_USERSis required — an empty allowlist refuses to start, so a misconfiguration cannot silently let any GitHub user in. - 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 the401+WWW-Authenticatefrom/mcp, fetches our well-known metadata, walks you throughgithub.com/login/oauth/authorize, and forwards the resulting bearer on every subsequent call. The server validates each request by callinghttps://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.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。