notes-mcp
This server acts as a virtual sticky notes manager, allowing you to create, store, search, and manage plain Markdown notes on your local machine via an MCP client. Key capabilities include:
Add notes (
add_note): Save a note with a title, optional Markdown body, and optional tags.List notes (
list_notes): View a summary of notes (IDs, titles, tags, and a blurb), sorted by most recently updated; optionally filter by a specific tag.Search notes (
search_notes): Find notes by case-insensitive text search in titles/bodies, combined with tag filters; you can require matching all tags or any of them (match_all).Read a note (
get_note): Retrieve the full Markdown content of a note by its ID.Delete notes (
delete_note): Permanently remove a note by ID; the ID is freed for future reuse.Browse resources: Access all notes as an index (
notes://all), a tag usage summary (notes://tags), or the full source of an individual note (note://{note_id}).Summarize notes (prompt): Use
summarize_notesto gather notes (optionally filtered by tag), group them by theme, and extract tasks or open questions.
Notes are stored locally as plain Markdown files ({id}.md) in ~/.notes-mcp/notes/ (or a configurable directory) with secure file permissions (0600). The server validates note IDs to prevent directory traversal attacks, though notes are not encrypted. This setup enables direct access and editing of notes outside the server as well.
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., "@notes-mcpsave a note about the project meeting tomorrow"
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.
notes-mcp: Virtual Sticky Notes
for Mac
An MCP server that keeps notes on your own machine, stored as plain Markdown files. Connect it to Claude Code or Claude Desktop and you can say "save a note about this" or "what did I write down about the migration?" in the middle of a conversation.
What it exposes
MCP servers offer three kinds of things to a client. This one uses all three, because they do different jobs:
Tools are verbs. They are actions the model decides to take. Writing and deleting notes belongs here.
Resources are nouns. They are content the client can pull into context, addressed by URI. The model does not have to "decide" to call them; you or the client can attach them directly.
Prompts are reusable message templates the user invokes deliberately, usually from a menu.
Tools
Tool | Arguments | Returns |
|
| The new note's id |
|
| A Markdown table: id, title, tags, and a short blurb |
|
| Matching notes with a short snippet |
|
| One note in full, including its body |
|
| Confirmation |
search_notes matches query against note titles and bodies, case-insensitively, and ANDs that
with the tag filter. match_all decides whether a note needs every tag listed or just one of them.
Resources
URI | Contents |
| An index of every note: id, title, tags |
| Every tag in use, with how many notes carry it |
| One note's full Markdown source |
note://{note_id} is a resource template — the client fills in {note_id} to read a specific
note, rather than the server listing all of them up front. Since ids are small integers, that
means note://5 for the fifth note.
Prompt
summarize_notes(tag) gathers your notes, groups them by theme, and pulls out anything that looks
like a task or an open question. Pass a tag to narrow it, or leave it empty for everything.
Related MCP server: MCP Notes Server
Setup
Requires uv and Python 3.10+.
git clone https://github.com/pdegner/notes-mcp.git
cd notes-mcp
uv syncClaude Code
claude mcp add notes -- uv --directory /full/path/to/notes-mcp run notes-mcpClaude Desktop
Add this to claude_desktop_config.json:
{
"mcpServers": {
"notes": {
"command": "uv",
"args": ["--directory", "/full/path/to/notes-mcp", "run", "notes-mcp"]
}
}
}Where your virtual sticky notes live
In ~/.notes-mcp/notes/, one Markdown file per note, named {id}.md. Set NOTES_MCP_DIR to put
them elsewhere.
---
id: '5'
title: Dentist appointment
tags:
- errands
- health
created: '2026-07-30T17:19:20Z'
updated: '2026-07-30T17:19:20Z'
---
Tuesday 3pm, Dr. Okafor.Ids are assigned in order starting from 1. Deleting a note frees its number, and the next note
you write gets the lowest free number rather than the next-highest — so if you delete note 3 out
of five notes, the next note you add becomes the new 3, not 6.
Because a note is just a Markdown file, you can read, edit, grep, or back it up without this
server involved. Hand-edited files are read back fine, including a tags: work, urgent shorthand
instead of a YAML list.
Your notes stay on this machine. They live outside this repository, so git never sees them and
they are never committed or pushed — the repo holds code only. The notes directory is created
0700 and each note file 0600, so other accounts on the machine cannot read them.
They are stored as plain text, not encrypted. That protects against other local users and against accidentally publishing them; it does not protect against anyone who has your login, admin access to the machine, or a backup that copies your home directory. Treat them like sticky notes on your desk, and don't put passwords in them.
Design notes
A few decisions worth explaining:
List and search return metadata, not bodies. Only get_note returns note text. If
list_notes returned full bodies, a directory of a few hundred notes would flood the model's
context on a single call. Search returns a short snippet around the match instead, which is enough
for the model to pick the right note and then ask for it.
Note ids are validated before they touch the filesystem. Ids arrive as tool arguments, which
means they come from a model and are untrusted input. Every id is checked against
^[a-z0-9][a-z0-9-]*$ before it is turned into a path, so ../../etc/passwd is rejected rather
than resolved. That pattern is broader than the plain integers the server assigns on purpose: a
hand-named file dropped into the notes directory stays readable even though the server would never
generate an id like that itself. Writes go to a temp file and are then atomically renamed, so an
interrupted write can't truncate an existing note.
A note's id never changes for as long as it exists. These are meant to work like sticky notes:
you write one down, and if you end up checking it often, note://5 is a fixed address you can
always go back to, not something that drifts as other notes come and go. Ids are only ever handed
out at creation, so nothing renumbers a note out from under you. Deleting a note frees its number
for the next note written after it, rather than leaving a permanent gap; the store scans
existing filenames on every add_note call and picks the smallest positive integer not already in
use (an O(n) scan, fine for a personal notes directory, not for thousands of notes). That reuse is
what keeps ids low and memorable instead of growing forever, but it only ever assigns a freed
number to a brand-new note, never to one that's still around.
Nothing prints to stdout. On the stdio transport, file descriptor 1 carries the JSON-RPC
message stream, so anything else written there corrupts the framing. The Python SDK does defend
against this — mcp.server.stdio claims fd 1 for the transport and repoints the process's own
stdout at stderr — but that only happens when the SDK opens the stream itself, and other MCP
implementations don't all do it. Treating stdout as reserved and sending logs to stderr is the
portable discipline rather than a workaround for one library's behavior.
Development
uv run pytest # 59 tests
uv run ruff check . # lint
uv run ruff format . # formatLicense
MIT
Available Tools
5 toolsadd_noteA
Save a new note.
Args:
title: Short title for the note.
content: The body of the note, as Markdown.
tags: Optional labels for grouping, e.g. ["work", "ideas"].
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | ||
| title | Yes | ||
| content | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Since no annotations are provided, the description must disclose behavioral traits. It only says 'Save a new note' and explains parameters, without mentioning return behavior, idempotency, or side effects like persistence or interaction with other tools. This is a significant gap for a create operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and front-loaded with the action 'Save a new note.', followed by clear, minimal parameter documentation. There is no fluff or redundant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple create operation, the description covers all necessary invocation details: required parameters, optional tags, and content format. An output schema exists, so the absence of return-value descriptions is acceptable. The tool is fully invocable based on this description.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has no descriptions (0% coverage), but the description compensates by explaining each parameter: title is a short title, content is the body in Markdown, and tags are optional labels with an example array. This meets the need for parameter meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb 'Save' and clearly identifies the resource as 'a new note'. This distinguishes it from sibling tools like list_notes, get_note, and delete_note, which operate on existing notes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit guidance on when to use this tool versus alternatives. The description only states the action and lists parameters, so usage is implied rather than clearly contextualized. It does not mention any exclusions or direct the user to other tools for different needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_noteA
Delete a note permanently.
Args:
note_id: The note's id, as returned by list_notes or search_notes.
| Name | Required | Description | Default |
|---|---|---|---|
| note_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full responsibility for behavioral disclosure. It adds 'permanently,' indicating irreversibility, which is valuable, but it omits important details like error handling, idempotency, auth requirements, and side effects. The output schema exists but is not referenced, so the description only minimally covers the behavioral profile.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely concise: one opening sentence and a one-line argument explanation. Information is front-loaded, with no wasted words or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple single-parameter delete tool, the description covers the core operation and parameter provenance. However, with no annotations, it lacks details about edge cases (e.g., non-existent note, permissions) and doesn't mention what the response contains (though an output schema exists). It's adequate but not thorough.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema provides no description for note_id (0% coverage), so the description must compensate. It does so by explaining the note_id is 'as returned by list_notes or search_notes,' giving the agent a clear source for a valid value. This adds meaningful context beyond the schema's bare title.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states the exact action: 'Delete a note permanently.' This is a specific verb (delete), resource (note), and qualifier (permanently), which clearly distinguishes it from siblings like add_note, list_notes, search_notes, and get_note.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implicitly guides usage by stating the note_id must come from 'list_notes or search_notes,' providing a clear prerequisite. While it doesn't explicitly mention alternatives or when-not-to-use, the context is clear enough for a straightforward delete operation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_noteA
Read one note in full, including its body.
Args:
note_id: The note's id, as returned by list_notes or search_notes.
| Name | Required | Description | Default |
|---|---|---|---|
| note_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It discloses that the full note including body is returned, but doesn't mention error handling, permissions, or side effects (though 'Read' implies non-destructive). Basic transparency only.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences: a clear purpose statement followed by a concise parameter explanation. No redundant phrases, perfectly front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter read tool with an output schema, the description is mostly complete. It could mention what happens for invalid IDs, but the output schema covers return values. Slight gap but not substantial.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema coverage, the description fully compensates by explaining note_id as 'The note's id, as returned by list_notes or search_notes.' This adds crucial provenance and format context beyond the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Read one note in full, including its body.' This specific verb+resource distinguishes it from siblings like list_notes (likely summaries) and search_notes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides guidance that the note_id comes from list_notes or search_notes, implying a workflow. However, it doesn't explicitly say when to prefer this over alternatives, though the purpose is clear enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_notesA
List saved notes, most recently updated first.
Returns titles and tags only, not note bodies. Call get_note to read one.
Args:
tag: Optional tag to filter by.
| Name | Required | Description | Default |
|---|---|---|---|
| tag | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden of disclosure. It adds valuable behavioral context: results are ordered by 'most recently updated first' and the response omits note bodies. It does not detail pagination or auth, but for a simple read-only list, this is sufficient and goes beyond a bare statement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is efficiently structured: a clear first line, a brief note on return value and alternatives, and a concise parameter description. No wasted words, and the most important information is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple list tool with one optional parameter and an output schema present, the description provides all necessary context: purpose, ordering, response contents, and parameter behavior. It is complete for its complexity band.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero description coverage for the 'tag' parameter. The description compensates fully by stating 'Optional tag to filter by', giving clear semantics that the schema lacks. This is exactly what parameter descriptions should provide.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function with a specific verb and resource: 'List saved notes'. It also distinguishes itself from siblings by noting it returns only titles and tags, and explicitly points to get_note for reading a full note. This makes the purpose unambiguous and distinct.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit guidance to use get_note when a full note body is needed, and implies list is for overview. It does not mention search_notes as an alternative for searching, but the listing with optional tag filter is clear. This is strong but not fully exhaustive in covering all sibling alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_notesA
Find notes by text and/or tags.
Returns matching notes with a short snippet, not their full bodies. Call
get_note to read one in full.
Args:
query: Text to look for in note titles and bodies (case-insensitive).
tags: Only return notes carrying these tags.
match_all: If true, a note must have every listed tag; otherwise any one
of them is enough.
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | ||
| query | No | ||
| match_all | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden. It discloses the key behavioral trait that results are snippets, not full bodies, and explains tag matching semantics (match_all). It also notes case-insensitivity for query. It does not mention edge cases like empty query behavior or result limits, but the main behaviors are covered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and well-structured, with a clear opening sentence and an Args section that maps directly to each parameter. Every sentence earns its place, and there is no redundancy or padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the presence of an output schema and the tool's moderate complexity, the description covers the essential behavior (snippet returns, parameter semantics) and directs users to get_note for full text. It does not explain what happens when both query and tags are omitted, but this is a minor gap. Overall, it is complete enough for effective use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must explain parameters. It does so thoroughly: query specifies text in titles and bodies with case-insensitivity, tags restrict results to notes with those tags, and match_all defines AND vs OR semantics. This adds significant meaning beyond the raw schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description starts with 'Find notes by text and/or tags', which clearly states the tool's function and its distinguishing aspect from siblings like list_notes (which likely lists all) and get_note (which retrieves a single note). The verb 'find' and resource 'notes' are specific and unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly directs users to call get_note to read a full note, implying search_notes is for discovery and snippet preview. It does not explicitly contrast with list_notes, but the snippet behavior makes the use case clear. This is strong guidance, though not exhaustive.
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. Dates show when Glama detected each change.
5 tool updates
v0.1.0- First observed
add_note - First observed
delete_note - First observed
get_note - First observed
list_notes - First observed
search_notes
TDQS
Each tool has a clearly distinct purpose: adding, listing (with metadata only), searching (with snippets), getting full content, and deleting. The list and search tools are complementary rather than overlapping, with explicit guidance to call get_note for full bodies.
Tool names follow a consistent verb_noun pattern, but there is a minor inconsistency in pluralization: add_note, get_note, and delete_note use singular while list_notes and search_notes use plural. Despite this, the pattern is predictable and easy to follow.
Five tools is well-scoped for a notes server, covering the essential operations (create, read, list, search, delete) without unnecessary bloat. Each tool has a clear role and contributes to the overall functionality.
The tool surface covers most of the CRUD lifecycle (add, list, get, search, delete) but lacks an update/edit operation, which is a common requirement for notes. This is a minor gap that can be worked around by deleting and re-adding, but it is not ideal.
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 Connectors
Markdown-based note-taking with a hosted MCP server. Your notes serve you and your AI.
- TaprootOAuthcom.taproothq
Persistent memory layer for AI tools. Save and recall notes across Claude and other MCP clients.
Google Keep-style notes app with an MCP server for AI agents to read/write notes.
An MCP server that used to create notes
Related MCP Servers
- FlicenseAqualityBmaintenanceA local MCP server for managing Markdown notes, enabling create, list, read, search, summarize, and delete operations through natural language.61-
- AlicenseNot gradedqualityDmaintenanceA beginner-friendly MCP server for managing personal notes. Enables Claude to create, list, read, search, update, and delete notes saved as Markdown files.MIT
- AlicenseAqualityCmaintenanceA note-taking MCP server for Claude-based agents that provides persistent markdown files for easily referable notes, supporting create, read, update, append, and delete operations.5Apache 2.0
- AlicenseAqualityAmaintenanceMCP server that gives Claude Code and other MCP clients persistent memory using plain Markdown notes stored on your disk and optionally synced to cloud storage (iCloud, OneDrive, Google Drive, Dropbox).361MIT
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/pdegner/notes-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server