Anchor MCP
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Anchor MCPsearch my notes for project updates"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Anchor MCP
Implementation plan for a small MCP sidecar that exposes safe Anchor Notes tools to ChatGPT through a tunnel client running in the same Docker Compose stack as Anchor.
Research basis: Anchor upstream repository ZhFahim/anchor, default branch main, inspected 2026-08-20. Anchor is a Nest.js backend with authenticated REST endpoints under /api/*.
Goal
Run an MCP server next to Anchor so external assistants can list, search, read, create, update, import, and attach files to Anchor notes without exposing Anchor's database or private API directly.
Related MCP server: NotesBridge
Current Status
First milestone is implemented:
Streamable HTTP MCP endpoint at
POST /mcp.Health endpoint at
GET /healthz.Read-only Anchor tools:
anchor_list_notes,anchor_search_notes,anchor_get_note,anchor_list_tags,anchor_list_attachments.Optional MCP bearer guard using
ANCHOR_MCP_TOKEN.Anchor API calls use
ANCHOR_TOKENandANCHOR_BASE_URL.Dockerfile is included.
Write tools are intentionally not implemented yet.
Development
On NixOS, use nix-shell for Node/npm commands:
nix-shell -p nodejs --run 'npm install'
nix-shell -p nodejs --run 'npm run typecheck'
nix-shell -p nodejs --run 'npm run build'Run locally:
ANCHOR_BASE_URL=https://anchor.cri.su \
ANCHOR_TOKEN=... \
ANCHOR_MCP_TOKEN=... \
nix-shell -p nodejs --run 'npm run dev'The MCP endpoint is http://localhost:8000/mcp. If ANCHOR_MCP_TOKEN is set, callers must send Authorization: Bearer <token>.
Deployment Model
The intended stack has three services:
services:
anchor:
# Existing Anchor service.
anchor-mcp:
build: /path/to/anchor-mcp
environment:
ANCHOR_BASE_URL: http://anchor:3000
ANCHOR_TOKEN: ${ANCHOR_TOKEN}
ANCHOR_MCP_TOKEN: ${ANCHOR_MCP_TOKEN}
expose:
- "8000"
depends_on:
- anchor
chatgpt-tunnel-client:
# Outbound tunnel client.
environment:
MCP_TARGET_URL: http://anchor-mcp:8000/mcp
MCP_TARGET_TOKEN: ${ANCHOR_MCP_TOKEN}
depends_on:
- anchor-mcpThe MCP server should only be reachable on the Docker network. The tunnel client is the only external bridge.
Confirmed Anchor API Surface
All endpoints below are guarded by Anchor's AuthGuard and expect Authorization: Bearer <token>. The guard accepts Anchor tokens that resolve to an active user.
Notes:
POST /api/notesGET /api/notes?search=<query>&tagId=<tagId>&limit=<limit>GET /api/notes/:idPATCH /api/notes/:idDELETE /api/notes/:idDELETE /api/notes/:id/permanentPATCH /api/notes/:id/restoreGET /api/notes/trashGET /api/notes/archivePOST /api/notes/bulk/deletePOST /api/notes/bulk/archivePOST /api/notes/bulk/pinPOST /api/notes/bulk/tags
Tags:
POST /api/tagsGET /api/tagsGET /api/tags/:idGET /api/tags/:id/notesPATCH /api/tags/:idDELETE /api/tags/:id
Attachments:
POST /api/notes/:noteId/attachmentsGET /api/notes/:noteId/attachmentsGET /api/notes/:noteId/attachments/:idDELETE /api/notes/:noteId/attachments/:idPATCH /api/notes/:noteId/attachments/reorder
Import/export:
POST /api/import/notesPOST /api/import/notes/:noteId/attachmentsGET /api/export
Sync API:
POST /api/syncGET /api/sync/eventsas server-sent events
Sharing:
POST /api/notes/:id/sharesGET /api/notes/:id/sharesPATCH /api/notes/:id/shares/:shareIdDELETE /api/notes/:id/shares/:shareId
The MCP server should start with normal notes/tags/attachments/import endpoints. The sync API is useful for conflict-aware offline clients, but an MCP sidecar can avoid it initially.
Data Shapes
Create note body:
{
"title": "string",
"content": "optional string",
"isPinned": false,
"isArchived": false,
"background": "optional string",
"tagIds": ["tag-id"]
}Update note body is a partial create body plus optional optimistic lock:
{
"title": "optional string",
"content": "optional string",
"isPinned": false,
"isArchived": false,
"background": "optional string",
"tagIds": ["tag-id"],
"baseVersion": 1
}Anchor returns transformed notes with these important fields:
{
"id": "uuid",
"title": "string",
"content": "string or null",
"version": 1,
"isPinned": false,
"isArchived": false,
"background": null,
"state": "active",
"createdAt": "iso timestamp",
"updatedAt": "iso timestamp",
"userId": "uuid",
"tagIds": ["tag-id"],
"permission": "owner",
"attachmentCount": 0,
"imagePreviewIds": []
}Import notes body:
{
"notes": [
{
"ref": "external stable reference, max 256 chars",
"id": "optional uuid",
"title": "string",
"content": "stringified Quill Delta JSON",
"isPinned": false,
"isArchived": false,
"isTrashed": false,
"background": "optional background id",
"tagNames": ["tag name"],
"createdAt": "iso timestamp",
"updatedAt": "iso timestamp"
}
],
"tags": [{ "name": "tag", "color": "#8B5CF6" }],
"skipExisting": true
}Import result shape:
{
"results": [
{
"ref": "external reference",
"status": "created | skipped | remapped | failed",
"noteId": "uuid",
"warning": "optional string",
"error": "optional string"
}
],
"tags": { "created": 0, "reused": 0 }
}Attachment upload shapes:
Normal note upload: multipart
filefield toPOST /api/notes/:noteId/attachments.Import attachment upload: multipart
filepluspositionform field toPOST /api/import/notes/:noteId/attachments.Attachment response includes
id,noteId,type,originalFilename,mimeType,fileSize,position,uploadedByUserId, andcreatedAt.
Limits And Validation
Notes list limit:
GET /api/notesclampslimitto1..200.
Bulk limits:
noteIds: max 200.tagIds: max 50.
Import limits:
Notes per batch: 50.
Stringified Delta content length: 1,000,000 bytes/chars.
Title length: 1000.
Tags per note: 50.
Tags per import batch: 500.
Tag name length: 100.
Attachment limits:
Max file size: 50 MB.
Allowed images:
image/jpeg,image/png,image/webp,image/gif.Allowed audio:
audio/mpeg,audio/wav,audio/mp4,audio/x-m4a,audio/ogg,audio/aac,audio/webm.PDFs, JSON, ZIP, and generic
application/octet-streamare rejected by current source.
Background IDs allowed by import:
color_red,color_orange,color_yellow,color_green,color_teal,color_blue,color_dark_blue,color_purple,color_pink,color_brown.pattern_dots,pattern_grid,pattern_lines,pattern_waves,pattern_groceries,pattern_music,pattern_travel,pattern_code.
Content Format
Anchor stores note content as a string. Existing import work confirms this should be stringified Quill Delta JSON for rich-text import.
The MCP server should expose Markdown-friendly tools and convert Markdown to Quill Delta internally. It can also expose expert-mode native Delta tools later.
Recommended conversion policy:
anchor_create_noteaccepts Markdown, converts to Delta, callsPOST /api/notes.anchor_update_noteaccepts Markdown, converts to Delta, callsPATCH /api/notes/:idwith optionalbaseVersion.anchor_import_notesaccepts Markdown or native Delta, batches throughPOST /api/import/notes.anchor_get_notereturns raw content plus a best-effort text/Markdown projection for LLM readability.
Authentication Model
Anchor source uses bearer-token extraction from Authorization: Bearer <token>. The MCP sidecar should therefore maintain two auth layers:
ANCHOR_TOKEN: token used byanchor-mcpwhen calling Anchor.ANCHOR_MCP_TOKEN: token expected from the tunnel client before any MCP request is served.
The MCP server should never forward arbitrary caller tokens to Anchor.
Source References
Primary files inspected upstream:
server/src/notes/controllers/notes.controller.tsserver/src/notes/controllers/note-attachments.controller.tsserver/src/notes/controllers/note-shares.controller.tsserver/src/tags/tags.controller.tsserver/src/import-export/import.controller.tsserver/src/import-export/export.controller.tsserver/src/sync/sync.controller.tsserver/src/sync/sync-events.controller.tsserver/src/notes/dto/create-note.dto.tsserver/src/notes/dto/update-note.dto.tsserver/src/import-export/dto/import-notes.dto.tsserver/src/import-export/dto/import-attachment.dto.tsserver/src/notes/constants/notes.constants.tsserver/src/import-export/constants/import.constants.tsserver/src/notes/utils/note-transformer.util.tsserver/src/notes/utils/attachment-storage.util.ts
MCP Tools
Phase 1 read tools:
anchor_list_notes(limit, offset)anchor_search_notes(query, limit)anchor_get_note(note_id)anchor_list_tags()anchor_list_attachments(note_id)
Implemented tool details:
anchor_list_notessupportslimit,offset,include_content, andtag_id. Because Anchor only exposes limit-based listing,offset + limitmust be at most 200.anchor_search_notessupportsquery,limit,include_content, andtag_id.anchor_get_notesupportsnote_idandinclude_content.anchor_list_tagstakes no input.anchor_list_attachmentsreturns metadata only and does not download attachment bytes.
Phase 2 write tools:
anchor_create_note(title, markdown)anchor_update_note(note_id, markdown, base_version)anchor_import_notes(notes)anchor_create_tag(name, color)anchor_upload_attachment(note_id, file, filename, mime_type)
Phase 3 management tools:
anchor_archive_notes(note_ids)anchor_pin_notes(note_ids, is_pinned)anchor_add_tags(note_ids, tag_ids)anchor_export()if the tunnel client can handle a streamed archive.
Avoid or gate destructive tools:
anchor_delete_note(note_id, confirm)maps to soft delete and should requireconfirm=true.anchor_permanent_delete_note(note_id, confirm)should be omitted initially.anchor_delete_tag(tag_id, confirm)should be omitted initially.Do not expose a raw arbitrary HTTP proxy tool.
Security
Store
ANCHOR_TOKENonly in the Docker stack environment or.env; do not bake it into the image.Add a separate
ANCHOR_MCP_TOKENfor calls from the tunnel client toanchor-mcp.Bind the MCP server to the container network only; do not add Traefik labels unless intentionally exposing it.
Keep tools narrow and typed. Do not allow callers to choose arbitrary Anchor API paths.
Log request metadata, not note content or tokens.
Default to read-only tools until the tunnel auth path is verified.
Require explicit
confirm=truefor soft-delete and bulk destructive actions.Refuse permanent deletion unless a separate
ENABLE_DANGEROUS_TOOLS=truesetting is present.
Implementation Phases
Create a minimal TypeScript MCP HTTP server.
Add configuration from environment:
ANCHOR_BASE_URL,ANCHOR_TOKEN,ANCHOR_MCP_TOKEN, bind host/port.Implement
/healthzfor Docker and tunnel diagnostics.Implement a small Anchor API client with typed methods and no arbitrary path escape hatch.
Implement
anchor_list_notes,anchor_search_notes,anchor_get_note, andanchor_list_tags.Add response shaping that strips heavy fields unless explicitly requested.
Implement Markdown-to-Delta conversion helpers and tests.
Implement create/update with optional optimistic locking via
baseVersion.Implement import batching with the known import limits.
Implement attachment upload for allowed images/audio only.
Add Dockerfile and Compose example including the tunnel client placeholder.
Add tests with mocked Anchor responses and validation failures.
Add operational docs for rotating tokens and wiring the ChatGPT tunnel client.
Open Questions
Exact tunnel-client image, environment variables, and auth header format.
Whether Anchor can be configured or patched to allow PDFs and other file types.
Whether note content should be accepted as Markdown and converted to Quill Delta, or whether the MCP should expose Anchor's native content format directly.
Whether the tunnel client can pass binary payloads well enough for attachment upload and export download.
Whether
offsetshould be simulated client-side becauseGET /api/notesonly exposeslimit, not offset pagination.
Recommended First Milestone
Build a read-only MCP server with anchor_list_notes, anchor_search_notes, anchor_get_note, and anchor_list_tags. Deploy it privately in the Anchor stack behind the tunnel client. Add create/update/import only after the read path and authentication model are verified.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceMCP server for AI agents to read, write, and organize notes in a local-first, human-in-the-loop note-taking app.01MIT
- AlicenseNot gradedqualityAmaintenanceMCP server enabling ChatGPT to search, read, and write Apple Notes via a local Mac agent with a privacy-preserving relay.MIT
- AlicenseNot gradedqualityAmaintenanceA secure multi-tenant MCP proxy that exposes 81 tools for full CRUD, search, chat, podcast, and command management on the OpenNotebook API, enabling natural language interaction with notebooks, notes, sources, and more.GPL 3.0
- AlicenseNot gradedqualityBmaintenanceSelf-hosted MCP server for private Obsidian vaults on GitHub, exposing tools to search, read, write, and analyze Markdown notes and their link graph.MIT
Related MCP Connectors
Search, read, and write your Apple Notes from ChatGPT/Claude via a local Mac agent + MCP relay.
Search your AI chat history (ChatGPT, Claude, Codex) from any MCP client. Remote, private, read-only
Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/llego/anchor-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server