Skip to main content
Glama
static-md

static-md-e2e

Official
by static-md

static-md-e2e

A local MCP server that lets AI agents read and write your end-to-end encrypted static.md notes. It encrypts and decrypts on your computer. static.md only ever receives ciphertext, note ids and titles; it never gets a key or the text of an encrypted note.

agent (Claude Code, Claude Desktop, Cursor, VS Code, Codex…)
  │  plaintext, on your computer
static-md-e2e  ── holds the key, encrypts and decrypts
  │  ciphertext only, over HTTPS
static.md/mcp  ── stores and returns ciphertext; checks access, Pro and limits

The notes are the same ones you open in the browser: a note the agent creates opens on static.md with its link, and edits merge live with people typing in it.

Requirements

  • A static.md Pro account. Agent access to encrypted notes is a Pro feature.

  • A personal access token with notes:read and notes:write. Create one under Your account on static.md/agents. It's shown once: store it like a password.

  • Node.js 20 or newer.

The bridge works with agents that run on your computer. Chat apps in the browser (claude.ai, ChatGPT) have nowhere on your side to hold the key, so they can't use encrypted notes.

Related MCP server: Bruin

Setup

Claude Code

claude mcp add static-md-e2e -e STATIC_MD_TOKEN=smd_pat_… -- npx -y static-md-e2e

Claude Desktop (claude_desktop_config.json), Cursor (~/.cursor/mcp.json) and most other clients:

{
  "mcpServers": {
    "static-md-e2e": {
      "command": "npx",
      "args": ["-y", "static-md-e2e"],
      "env": { "STATIC_MD_TOKEN": "smd_pat_…" }
    }
  }
}

VS Code (.vscode/mcp.json), asking for the token instead of storing it in the file:

{
  "inputs": [{ "type": "promptString", "id": "static-md-token", "description": "static.md personal access token", "password": true }],
  "servers": {
    "static-md-e2e": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "static-md-e2e"],
      "env": { "STATIC_MD_TOKEN": "${input:static-md-token}" }
    }
  }
}

Codex (~/.codex/config.toml):

[mcp_servers.static-md-e2e]
command = "npx"
args = ["-y", "static-md-e2e"]
env = { STATIC_MD_TOKEN = "smd_pat_…" }

Keep the regular static.md server (https://static.md/mcp) connected too: it handles notes that aren't encrypted, whiteboards and sharing.

Tools

Tool

What it does

read_encrypted_note

Decrypts a note and returns its markdown, marked as untrusted user content.

create_encrypted_note

Encrypts new markdown with a fresh key, creates the note, optionally in a folder, and returns its full link (…#key=…).

update_encrypted_note

Appends to a note or replaces it. Only the change is encrypted and sent, so it merges with live edits.

Examples

Ask in plain words; the agent picks the tool and its arguments.

You ask

The agent calls

Save these meeting notes as an encrypted note in my work/launch folder.

create_encrypted_note { "title": "Launch sync", "markdown": "# Launch sync\n\n- Ship Friday", "folder": "work/launch" }

Add "Budget approved" to https://static.md/md/k3v9qa#key=…

update_encrypted_note { "note": "https://static.md/md/k3v9qa#key=…", "markdown": "Budget approved", "mode": "append" }

What does my encrypted note k3v9qa say? (key saved on this computer)

read_encrypted_note { "note": "k3v9qa" }

Creating a note answers with its full link, https://static.md/md/<id>#key=…, and where static.md filed it (in /work/launch).

Folders

create_encrypted_note takes an optional folder, the same as static.md's other create tools: a path such as work/launch or /work/launch. Leave it out, or give /, for the top level. A folder exists while something is in it, so a new one needs no setup.

  • Folder names use letters A–Z, digits, -, _ and ., separated by /, up to 10 levels of 64 characters each.

  • shared_with_me can't be a top-level folder: static.md lists notes others share with you there.

  • Folder names aren't encrypted, like titles. Keep anything private out of them.

The bridge checks the folder with static.md's rules before it encrypts anything, so a folder static.md would refuse fails with the reason and nothing is sent. To list encrypted notes by folder, or move one, use static.md's regular server (list_my_notes, move_item): it sees titles and folders, never the text.

Giving the agent a key

A note's key is the 8 emojis after #key= in its link. There are two ways to hand it over:

  1. Paste the full link into the chat. Simple. The key then sits in the conversation, so your AI provider sees it (it sees the note's text anyway when the agent reads it). The bridge keeps keys from links in memory only, for as long as it runs.

  2. Save the key on this computer and give the agent only the id. The key never enters the conversation. Run this and paste the note's full link when asked (read from stdin, so the key stays out of your shell history):

    npx static-md-e2e key add

    Keys are saved in ~/.config/static-md/e2e-keys.json, readable by your user only (STATIC_MD_E2E_KEYS sets another path). key list shows saved note ids, key remove <id> forgets one.

Whatever the agent creates comes back as a full link: keep it. static.md can't recover a lost key.

What each party sees

static.md

Your AI provider

This computer

Note text

❌ ciphertext only

✅ what the agent reads or writes

✅ in memory

Key

❌ never

only if you paste the link

✅ memory, or the key file if you save it

Title and folder

✅ titles and folders aren't encrypted

✅

✅

Metadata

✅ ids, owner, sharing, sizes, update times, the token used, IP

static.md's server tools have no parameter that takes a key, and they refuse text that contains a #key= link, so a key can't end up stored next to a note by accident. A changed or forged update fails AES-GCM authentication and is left out of what the agent reads (the answer says how many). The bridge won't edit a note when any of its updates fail to decrypt, since the web app won't open a note with an update it can't decrypt. Messages from static.md reach the agent fenced as untrusted, like note text.

The format

The bridge has no secret logic. To write your own client:

  • Key: the 8 emojis from #key= (the web app's 840-emoji alphabet, exported here as EMOJI_ALPHABET). AES-256 key = SHA-256 of the 8 emojis joined, as UTF-8.

  • A stored update: base64 of IV (12 random bytes) ‖ AES-256-GCM ciphertext ‖ tag (16 bytes). The plaintext is a Yjs update.

  • A note: all of its stored updates. Decrypt each one and apply them all to one Y.Doc, in any order. The markdown is doc.getText('codemirror').

  • static.md's MCP tools (https://static.md/mcp): read_note_ciphertext returns the updates as JSON (static.md/e2e-note/v1). create_note_ciphertext creates a note from its first encrypted update, optionally in a folder. write_note_ciphertext adds one, and the owner can compact the note with it.

Development

pnpm install
pnpm test
pnpm build

License

MIT

Available Tools

3 tools
create_encrypted_noteCreate an encrypted noteA

Creates an end-to-end encrypted static.md note owned by the user, optionally in a folder: the markdown is encrypted on this computer with a new key, and static.md stores only the ciphertext. Returns the full link, whose #key= part is the only way to open the note. Titles and folder names are stored unencrypted. Needs Pro.

NameRequiredDescriptionDefault
titleNoShort title, stored unencrypted on static.md (it keeps the first 32 characters)
folderNoFolder to put the note in, such as "work/launch"; it is made if it doesn't exist yet. Names use letters A-Z, digits, "-", "_" and ".", up to 10 levels. Stored unencrypted, like the title. Default: the top level ("/")
markdownNoThe note's markdown, encrypted here before it is sent

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, it discloses critical behavioral details: encryption happens locally with a new key, the server only stores ciphertext, titles and folder names are unencrypted, a Pro plan is required, and the returned #key= fragment is the only way to open the note. That last point is a non-obvious, high-impact consequence the agent could not infer from the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core action and then layers in the encryption model, return value, metadata exposure, and plan requirement. Every clause carries operational meaning, and the single dense sentence remains readable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a three-parameter mutating tool with no output schema, it covers the essential gaps: where encryption occurs, what the server stores, what the return value contains, what metadata is exposed in plaintext, and the Pro prerequisite. No critical caller decision is left uninformed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents title, folder, and markdown thoroughly, including length limits and folder naming rules. The description repeats that titles and folder names are unencrypted and adds that markdown is encrypted before sending, but these details mostly duplicate or lightly extend the schema, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource — creates an end-to-end encrypted static.md note owned by the user — and immediately explains the distinguishing mechanism (local encryption, server stores only ciphertext). It is easily separable from the read_encrypted_note and update_encrypted_note siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear context for when this applies: creating a new encrypted note, optionally inside a folder, and requires a Pro account. It does not explicitly state when not to use it or route the agent to update_encrypted_note for existing notes, but the creation context is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_encrypted_noteRead an encrypted noteA
Read-only

Returns the markdown of an end-to-end encrypted static.md note, decrypted on this computer with the key from its link. static.md sends only ciphertext and never gets the key. The note is written by users and comes back marked as untrusted data. Needs Pro.

NameRequiredDescriptionDefault
keyNoThe note's 8-emoji key, when it came separately from the link
noteYesThe note's link with its #key= part (https://static.md/md/<id>#key=…), or its id when its key is saved on this computer

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint and openWorldHint annotations, it discloses important behavior: decryption happens locally with the key from the link, static.md only sees ciphertext, and returned user-written content is marked as untrusted data. It also adds the Pro-plan requirement, which is exactly the kind of context annotations do not cover.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is short and front-loaded: it states the return value first, then the security model, then the trust marking and plan requirement. Every sentence adds useful information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter read-only tool with no output schema, the description covers what comes back, how decryption works, the trust level of the returned content, and the Pro requirement. Nothing an agent needs to call it correctly appears to be missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both the note link/id field and the optional 8-emoji key field are already well documented in the schema. The description reinforces that the key comes from the link but does not add syntax or edge-case details beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: it returns the markdown of an end-to-end encrypted static.md note, decrypted locally. That is precise enough for an agent to distinguish this read operation from the create/update siblings without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies the tool is for reading an existing encrypted note and notes that it needs Pro, which is a useful prerequisite. However, it gives no explicit when-to-use or when-not-to-use guidance and never mentions the create_encrypted_note or update_encrypted_note alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_encrypted_noteUpdate an encrypted noteA
Destructive

Changes the markdown of an end-to-end encrypted static.md note, encrypting the change on this computer. mode "append" adds text on a new line at the end; mode "replace" makes the note exactly the given markdown. Edits merge live with people typing in the note. Needs edit access and Pro.

NameRequiredDescriptionDefault
keyNoThe note's 8-emoji key, when it came separately from the link
modeYes"append" adds to the end; "replace" overwrites the whole note
noteYesThe note's link with its #key= part (https://static.md/md/<id>#key=…), or its id when its key is saved on this computer
markdownYesMarkdown to append, or the complete new note for "replace"

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond destructiveHint=true it explains what destruction looks like ('replace makes the note exactly the given markdown'), discloses that edits merge live with concurrent typers (explaining non-idempotency in practice), that encryption happens on this computer, and that edit access plus Pro are required. That is substantive context annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, front-loaded with the action and resource, then mode semantics, then concurrency and prerequisites. No sentence is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers what an agent needs to call it safely: auth prerequisites, client-side encryption, destructive replace semantics, and live-merge concurrency. It does not say what happens on a concurrent conflict or what the call returns, though there is no output schema to lean on.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% so the baseline is 3, but the description adds detail the schema lacks: 'append' places text on a new line at the end, and 'replace' means the result is exactly the given markdown. It says nothing extra about key or note.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (changes the markdown) and a specific resource (an end-to-end encrypted static.md note), plus where the encryption happens. It is unmistakably distinct from read_encrypted_note and create_encrypted_note.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The two modes are spelled out with their effect on the note ('append' adds a new line at the end, 'replace' makes the note exactly the given markdown), and 'Needs edit access and Pro' gives an explicit precondition. It never names a sibling tool as an alternative, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.2.0
    • First observedcreate_encrypted_note
    • First observedread_encrypted_note
    • First observedupdate_encrypted_note

TDQS

A4.4/5.0

Scored across 3 tools

Disambiguation5/5

Each tool maps to a single distinct CRUD action on the same resource (encrypted note), with clear boundaries between reading, creating, and updating. There is no plausible way to confuse them, and the mode parameter on update is scoped to that tool only.

Naming Consistency5/5

All three names follow a strict verb_noun pattern with a shared, stable noun phrase: read_encrypted_note, create_encrypted_note, update_encrypted_note. Predictable and easy to guess the missing operations from.

Tool Count4/5

Three tools is on the thin side, but each is substantial and covers a distinct lifecycle stage, so nothing feels redundant. A slight under-provisioning is the only issue.

Completeness3/5

The domain is note management, and the surface covers create, read, and update, but there is no delete/remove tool and no way to list or discover the user's notes or folders — agents cannot enumerate notes without an out-of-band link. These are notable gaps for a full note lifecycle.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    MCP server for AI agents to read, write, and organize notes in a local-first, human-in-the-loop note-taking app.
    6 npm
    2
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    A local-first MCP server that gives AI assistants long-term memory by storing, searching, and recalling notes as Markdown files on your machine.
    5 npm
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    A fully offline, secure MCP server that enables AI agents to search, read, write, and list local markdown notes using SQLite FTS5, with directory traversal protection.
    1
    -