HedgeDoc MCP Multitenant Proxy Server
by homeserverhq
README.md
# HedgeDoc MCP Multitenant Proxy Server
This repository contains a Model Context Protocol (MCP) server that acts
as a secure, multi-tenant proxy between an AI Assistant and the HedgeDoc
backend API. It exposes **27 MCP tools** covering 5 resource domains
with full CRUD and permission management.
## โจ Features
- **๐ Identity Passthrough** โ Extracts the `Authorization: Bearer <token>`
header from incoming HTTP requests and forwards it to the HedgeDoc API
without server-side authentication.
- **๐ฅ Multi-Tenancy** โ Uses Python `contextvars` to maintain thread-safe
user identity isolation, ensuring all AI-driven actions are scoped to
the authenticated user's permissions.
- **๐ Full HedgeDoc Coverage** โ 27 tools mapped to HedgeDoc API endpoints
across 5 resource domains.
- **โก TOON Optimization** โ Bulk list responses are automatically compressed
using TOON (Token-Optimized Object Notation) to reduce token consumption
and maximize context window efficiency.
- **๐ Efficient Gets** โ GET responses return only commonly used fields by
default. Full objects are available via an `include_all_fields` flag.
- **๐งช Comprehensive Testing** โ 39 automated tests covering all tool
domains, run via the test runner pipeline.
- **๐ท๏ธ Tool Annotations** โ All tools expose standard MCP ToolAnnotations hints (readOnlyHint, destructiveHint, idempotentHint, openWorldHint). The tags field carries grouping metadata (basic/primary/advanced + hedgedoc).
## ๐ง Environment Variables
| Variable | Required | Description |
|----------|----------|-------------|
| `HEDGEDOC_BASE_URL` | Yes | Docker-internal URL of the HedgeDoc API (e.g. `http://hedgedoc-backend:3000`). |
| `MCP_SERVER_PORT` | Yes | Port number the MCP server listens on. |
| `ALLOW_ALL_AGGREGATE` | No | When `true`, aggregate listing tools honor the `include_all_fields` parameter. When `false` (default), the parameter is silently forced to `False` for aggregate list operations. |
| `IS_STATEFUL` | No | When `true`, uses stateful Streamable HTTP with session tracking. When `false` (default), uses stateless mode. |
| `HEDGEDOC_PUBLIC_URL` | No | Public-facing URL for `note_url` in responses. Defaults to `HEDGEDOC_BASE_URL` if not set. |
## ๐ฆ Installation & Local Development
1. Ensure you have Python 3.12+ installed.
2. Install dependencies:
```bash
pip install fastmcp httpx pydantic uvicorn toon-mcp-server
```
3. Run the server:
```bash
export HEDGEDOC_BASE_URL=http://localhost:7462
export HEDGEDOC_PUBLIC_URL=https://hedgedoc.example.com
export MCP_SERVER_PORT=80
python -m src.main
```
## ๐ณ Docker Deployment
Build and run the server using Docker:
```bash
docker build -t hedgedoc-mcp:latest .
docker run -d --name hedgedoc-mcp \
-e HEDGEDOC_BASE_URL="http://hedgedoc-backend:3000" \
-e HEDGEDOC_PUBLIC_URL="https://hedgedoc.example.com" \
-e MCP_SERVER_PORT=80 \
-e IS_STATEFUL=false \
hedgedoc-mcp:latest
The MCP server serves at `http://hedgedoc-mcp:80/mcp` (Streamable HTTP).
```
## โ ๏ธ Important Notes
- **๐ `include_all_fields`** โ The `include_all_fields` parameter (available
on all `get_*` and `list_*` tools) controls whether all available fields
are included in responses. Defaults to `False` for performance; set to
`True` only when additional fields are needed.
- **โก TOON Compression** โ All bulk list responses are automatically
compressed using TOON to reduce token consumption by 30โ60%.
- **๐ Required Fields & Defaults** โ Each `create_*` tool requires specific
key fields. All other fields default to empty strings or reasonable values.
The owner field is automatically set to the authenticated user for most
resources.
## ๐ ๏ธ API Tool Mapping
The server implements 27 MCP tools organized into the following categories:
### ๐ Notes Core (6 tools)
- `create_note` โ Create a new note from markdown content
- `get_note_by_id` โ Get a single note by ID or alias
- `update_note` โ Update an existing note's content
- `delete_note_by_id` โ Delete a note by ID or alias
- `get_note_content` โ Get raw markdown content of a note
- `get_note_metadata` โ Get a note's metadata (title, tags, etc.)
### ๐ Notes Advanced (7 tools)
- `list_note_media` โ List all media files attached to a note
- `list_note_revisions` โ List all revisions of a note
- `get_note_revision_by_id` โ Get a specific revision by UUID
- `revert_to_revision` โ Revert a note to a previous revision
- `add_alias` โ Add an alias to a note
- `make_alias_primary` โ Set an alias as primary or non-primary
- `remove_alias` โ Remove an alias from a note
### ๐ Notes Permissions (6 tools)
- `get_note_permissions` โ Get a note's permission settings
- `set_note_user_permission` โ Set a user's permission on a note
- `remove_note_user_permission` โ Remove a user's permission from a note
- `set_note_group_permission` โ Set a group's permission on a note
- `remove_note_group_permission` โ Remove a group's permission from a note
- `change_note_owner` โ Change the owner of a note
### ๐ Notes Listing (4 tools)
- `list_all_my_notes` โ List notes owned by the current user
- `list_all_shared_notes` โ List notes shared with the current user
- `list_all_public_notes` โ List public notes visible to the current user
- `list_all_pinned_notes` โ List notes pinned by the current user
### ๐ค Profile & Media (4 tools)
- `get_my_profile` โ Get the current user's profile information
- `list_all_my_media` โ List all media files owned by the current user
- `get_media_by_id` โ Get a single media file by UUID
- `delete_media_by_id` โ Delete a media file by UUID
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues