mcp-notes-server
This server lets you manage a persistent personal notes collection through MCP tools.
Add a note with a title, content, and up to 10 optional tags.
List notes newest first, optionally filtered by a single tag.
Search notes by keywords across titles, tags, and bodies, with a configurable result limit.
Permanently delete a note by its id.
Click on "Deploy 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., "@mcp-notes-serverSave a note titled RAG chunking: use 800-char chunks with overlap, tagged rag."
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.
mcp-notes-server
A complete reference Model Context Protocol (MCP) server in TypeScript: 6 tools, resources and a prompt, backed by a persistent, searchable notes file. Small enough to read in one sitting, and tested end to end over real stdio.
What is MCP?
The Model Context Protocol is an open standard that lets AI apps (like Claude) talk to outside programs in one uniform way, a bit like USB-C for AI. Instead of custom glue for every assistant, you write one MCP server that offers tools (actions the AI can run), resources (data it can read) and prompts (reusable templates), and any MCP client can discover and use them.
Learn MCP step by step: ai-engineer-roadmap / 06-mcp
Related MCP server: mcp-server-example
Architecture
flowchart LR
C["MCP client<br/>(Claude Desktop, Claude Code, Inspector)"] -- "JSON-RPC over stdio" --> S["mcp-notes-server<br/>(dist/index.js)"]
S --> N[("notes.json")]Tools
Tool | What it does | Hints |
| Save a note with title, content and optional tags | Writes |
| Fetch one note by id | Read-only |
| List notes newest first, optionally by tag | Read-only |
| Keyword search over titles, tags and bodies (title matches rank highest) | Read-only |
| Edit title, content and/or tags (tags replace existing ones) | Writes, idempotent |
| Permanently delete a note by id | Destructive |
Errors (unknown id, malformed id, empty update) come back as isError results with a clear message, never as crashes.
Resources and prompts
Type | Name / URI | Description |
Resource |
| Every note, newest first, as plain text |
Resource template |
| One note by id; each note is also listed individually |
Prompt |
| Asks the model to summarise your notes, flag duplicates and suggest better tags |
Notes are stored in a JSON file (~/.mcp-notes/notes.json by default, override with NOTES_FILE). Writes are atomic (temp file + rename).
Quick start
git clone https://github.com/techsaurabh-394/mcp-notes-server.git
cd mcp-notes-server
npm install
npm run build
npm testUse with Claude Desktop
Add this to your Claude Desktop config (claude_desktop_config.json), using the absolute path to your clone:
{
"mcpServers": {
"notes": {
"command": "node",
"args": ["/absolute/path/to/mcp-notes-server/dist/index.js"],
"env": { "NOTES_FILE": "/absolute/path/to/notes.json" }
}
}
}Restart Claude Desktop, then try:
"Save a note titled RAG chunking with the content use 800-char chunks with overlap, tag it rag."
"Search my notes for chunking."
"Change the tags on that note to rag and search."
Use with Claude Code
claude mcp add notes -- node /absolute/path/to/mcp-notes-server/dist/index.js
# optional: custom storage file
claude mcp add notes --env NOTES_FILE=/absolute/path/to/notes.json -- node /absolute/path/to/mcp-notes-server/dist/index.jsRun claude mcp list to confirm. Other MCP clients (Cursor, etc.) work the same way: point them at node dist/index.js over stdio.
Test with the MCP Inspector
npm run build
npx @modelcontextprotocol/inspector node dist/index.jsOpen the printed URL to browse and call the tools, resources and prompt interactively.
Testing
npm test builds and runs the node:test suite: store unit tests plus an end-to-end test that spawns the built server over stdio with the SDK client and exercises initialize, every tool, resources and prompts. CI runs it on Node 22.
Security design
No shell, no SQL, no network: the server only reads and writes one JSON file.
Path handling: the file path comes from the operator (
NOTES_FILE), never from tool input. Note ids are validated (^[a-f0-9]{8}$) and only compared against stored ids, never used as paths.stdout is the protocol channel: all logging goes to stderr.
Validation: every tool input is checked with
zod(length and count limits); bad input returns an error result.Annotations: read-only tools are marked
readOnlyHint,delete_noteisdestructiveHint, so clients can show the right confirmation UI.Atomic writes avoid a half-written notes file.
Project layout
src/index.ts MCP server: tools, resources, prompt
src/store.ts NoteStore: JSON-file persistence and search
src/test/store.test.ts unit tests
src/test/e2e.test.ts end-to-end test over stdio
.github/workflows/ci.yml GitHub Actions CILicense
MIT, built by Saurabh Pathak.
Roadmap (contributions welcome)
update_notetool (edit title, content, tags)Resources (
notes://all,notes://{id}) and areview_notespromptOptional SQLite backend for large note collections
Semantic search using embeddings
Publish to npm so it runs with
npx mcp-notes-serverStreamable HTTP transport for remote clients
If this is useful, a star helps others find it.
Support this project
If this is useful, a star helps others find it, and you can support more free open-source work:
Available Tools
4 toolsadd_noteAdd noteB
Save a new note. Returns the note id. Use tags to group related notes.
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | Optional tags | |
| title | Yes | Short title | |
| content | Yes | Body of the note |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations the description carries the full behavioral burden. It usefully discloses that the call returns the note id (compensating for the missing output schema), but says nothing about permissions, persistence, failure behavior, or the 10-tag cap enforced by the schema.
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?
Three short, front-loaded sentences with no filler: the action, the return value, and the tag tip. Every sentence earns its place.
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 additive create tool with a fully documented schema, the description covers the essentials and even compensates for the absent output schema by naming the returned id. It stops short of stating any permissions or error behavior, which is a minor gap given the tool's simplicity.
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 description coverage is 100%, so title and content are already documented in the schema and the baseline is 3. The tag sentence adds a small amount of intent ('group related notes') but does not explain format, syntax, or interaction with other fields.
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?
States a specific verb and resource ('Save a new note') plus the return value, so the agent immediately knows this is a creation tool. It does not differentiate itself from siblings like list_notes or search_notes, though the verb makes the distinction obvious.
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?
'Use tags to group related notes' is advice about a parameter, not about when to invoke this tool versus its siblings. There is no stated precondition, no exclusion, and no alternative named, so an agent gets no routing guidance beyond the obvious verb.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_noteDelete noteADestructive
Permanently delete one note by id. This cannot be undone.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Note id from list_notes or search_notes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The destructiveHint=true annotation already signals a write operation, but the description adds useful specificity: the deletion is permanent and irreversible. It stops short of mentioning permission requirements, error behavior for missing ids, or cascading effects.
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?
Two short sentences, zero filler, with the permanence warning front-loaded. Every sentence earns its place.
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 destructive tool, the description plus annotations and schema cover the essentials. It could be slightly richer by noting what happens when the id does not exist, but nothing critical is missing.
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 description coverage is 100%, with the 'id' parameter already documented as coming from list_notes or search_notes. The description's 'by id' adds no new meaning beyond the schema, so the baseline 3 applies.
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?
States a specific verb ('delete'), resource ('note'), scope ('one'), and identifier ('by id'), which cleanly distinguishes it from add_note, list_notes, and search_notes. An agent can identify the operation 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives no when-to-use guidance, no alternatives, and no prerequisites. It only implies that the tool deletes, leaving the agent to infer the appropriate context from the name alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_notesList notesARead-only
List notes, newest first. Optionally filter by a single tag.
| Name | Required | Description | Default |
|---|---|---|---|
| tag | No | Only notes with this tag |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already tells the agent this is a safe read. The description adds genuinely useful traits beyond that: the default sort order ('newest first') and the constraint that only one tag can be supplied. It does not mention pagination, result limits, or ordering controls, which matters for a list endpoint.
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?
Two short sentences, zero waste, with the ordering behavior front-loaded and the filter constraint second. Nothing is repeated from the name or title.
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 zero-required-parameter read tool with an annotated safety profile and no output schema, the description covers what is needed to invoke it. The only real gap is the absence of any hint about result size or pagination for a potentially unbounded list.
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 description coverage is 100% for the single 'tag' parameter, so the baseline is 3. The description adds a small nuance the schema does not convey: only a single tag is accepted, not a set.
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?
States a specific verb and resource ('List notes') plus ordering ('newest first') and an optional filter. It is clear on its own, but it never differentiates itself from the sibling search_notes, which an agent could easily confuse with a filtered list.
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?
'Optionally filter by a single tag' implies the intended usage, but there is no explicit guidance on when to use this versus search_notes or when a tag filter is preferable to a search query. Usage must be inferred.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_notesSearch notesARead-only
Keyword search across note titles, tags and bodies. Returns the best matches with full content.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results (default 5) | |
| query | Yes | Space-separated keywords |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already tells the agent this is a safe read. The description adds genuine value beyond annotations by disclosing that results are relevance-ranked ('best matches') and returned with full content rather than snippets, but it says nothing about result-count behavior or what happens when the query matches nothing.
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?
Two tight sentences, front-loaded with the search scope and then the return shape. No filler, though the second sentence is thin relative to the room available.
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?
With no output schema, the description usefully compensates by stating that matches come back ranked with full content. Combined with the fully documented input schema and readOnly annotation, an agent has enough to call this correctly.
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 100%, so both parameters (query, limit) are already documented in structured form. The description only echoes the query semantics ('keyword') and adds nothing about the limit or the interaction between limit and result ranking, so baseline 3 applies.
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?
States a specific verb and resource ('Keyword search across note titles, tags and bodies'), making it immediately distinguishable from the CRUD siblings add_note/list_notes/delete_note. It does not explicitly name a sibling, but the search-vs-mutate distinction is unmistakable.
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?
Keyword search implies when to use it, but the description never addresses the obvious overlap with list_notes (browse vs. query) nor states any prerequisite. Usage context is left to inference rather than made explicit.
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.
4 tool updates
v1.0.0- First observed
add_note - First observed
delete_note - First observed
list_notes - First observed
search_notes
TDQS
Scored across 4 tools
Each tool maps to a clearly distinct operation: create, enumerate, keyword-search, and delete. There is no overlap between search_notes and list_notes since one is keyword-based and the other is enumerative with tag filtering, and descriptions make the boundaries explicit.
All tools follow a verb_noun snake_case pattern (add_note, list_notes, search_notes, delete_note), which is highly predictable. The only minor deviation is singular 'note' in add/delete versus plural 'notes' in list/search, but this reflects natural object plurality rather than a convention break.
Four tools is a tight, well-scoped surface for a simple notes server, with each tool earning its place. It sits at the low end of the typical 3-15 range, and the absence of any modification tool makes it feel slightly under-provisioned rather than bloated.
The surface covers create, read/list, search, and delete, but there is no update/edit tool, so an agent cannot modify an existing note's title, body, or tags without deleting and recreating it. Retrieval by id is also only implicitly available via search, leaving a notable lifecycle gap.
Maintenance
Related MCP Connectors
- TaprootOAuthcom.taproothq
Persistent memory layer for AI tools. Save and recall notes across Claude and other MCP clients.
Save notes in seconds. Your AI can then search, read, write and tag them over MCP.
MCP-native notes and memory for ChatGPT, Claude, and other AI tools.
Google Keep-style notes app with an MCP server for AI agents to read/write notes.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceProvides persistent, searchable memory for MCP-compatible AI coding tools, allowing notes added from one tool to be retrieved from another.-
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to manage in-memory notes by listing, fetching, and creating notes through MCP tools over stdio.64 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables managing plain-text notes on disk through MCP resources, tools, and prompts, so natural-language requests can create, read, search, delete, and summarize notes via an interactive client.MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to read, search, create, update, and remove locally stored personal notes organized by themes and subt themes, with backlink navigation, all through MCP tools.MIT