Skip to main content
Glama

notes-mcp-server

A Model Context Protocol server that gives an AI assistant a persistent, searchable notebook. Claude (or any MCP client) can save notes, find them with full-text search, update and tag them — stored locally in a single SQLite file.

You:    remember that we chose pgvector over qdrant because ops already runs Postgres
Claude: [add_note] Saved as note #12, tagged "architecture".

You:    why did we pick pgvector again?
Claude: [search_notes "pgvector"] → note #12: "...chose [pgvector] over qdrant because ops already runs Postgres"

Built on the official Python SDK (mcp 2.x, MCPServer).

Tools

Tool

Annotation

Purpose

search_notes(query, tag?, limit?)

read-only

Full-text search over title, body and tags; best match first, matching words [bracketed] in the snippet

get_note(note_id)

read-only

Full text of one note

list_tags()

read-only

Tags in use with counts

add_note(title, body, tags?)

write

Create a note

update_note(note_id, title?, body?, tags?)

write

Change only the fields passed

delete_note(note_id)

destructive

Permanent delete — the server instructions tell the model to confirm with the user first

Resources: notes://recent (ten latest notes) and notes://{id} (one note as markdown).

Every tool returns structured output with a JSON schema, so clients get typed fields rather than text to parse.

Related MCP server: upnote-mcp

Design notes

Search is safe against FTS syntax in user input. SQLite FTS5 treats quotes, *, -, NOT and NEAR(...) as operators; passing a model's query straight into MATCH either throws or silently changes the meaning. Every word is quoted as a literal before matching. The test suite throws hostile strings at it to prove nothing raises.

Ranking favours titles. bm25() is weighted 10 : 1 : 5 for title : body : tags, and the Porter tokenizer matches building to builds. The FTS index is kept in sync with triggers on insert, update and delete.

Errors are useful to the model, not leaky. Expected failures (missing note, empty title, malformed tag) are raised as ToolError, so the model sees note 404 does not exist and can recover. Anything unexpected is left to the SDK, which reports a generic error without exposing internals.

Thread-safe store. The SDK runs synchronous tools in a worker-thread pool, while a default SQLite connection only works on the thread that opened it — the server would fail on its second call. The store opens the connection with check_same_thread=False and serialises access with a lock. This bug was invisible in unit tests of the store and only showed up when the tests went through a real MCP client, which is why most server tests do.

Input limits. Titles up to 200 characters, bodies up to 20,000, tags restricted to [a-z0-9_-], search results capped at 50.

Install

pip install git+https://github.com/HlebYakhnitski/notes-mcp-server

Claude Desktop

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "notes": {
      "command": "notes-mcp",
      "env": { "NOTES_DB": "~/.notes-mcp/notes.db" }
    }
  }
}

On Windows, if notes-mcp is not on PATH, use "command": "python", "args": ["-m", "notes_mcp.server"].

Any other client

The server speaks MCP over stdio: python -m notes_mcp.server. The database path comes from NOTES_DB (default ~/.notes-mcp/notes.db).

Development

pip install -e ".[dev]"
pytest

31 tests. The storage layer is tested directly; the server is tested through the SDK's Client connected in-process, which exercises tool schemas, structured output, annotations, error reporting and resources exactly as a real client sees them. A concurrency test writes from eight threads at once.

License

MIT

Available Tools

6 tools
add_noteC

Create a note. Tags are optional lowercase labels used for filtering.

NameRequiredDescriptionDefault
bodyYes
tagsNo
titleYes

Output Schema

NameRequiredDescription
idYes
bodyYes
tagsYes
titleYes
created_atYes
updated_atYes

TDQS

C2.9/5.0
Behavior2/5

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

Annotations already declare readOnlyHint=false and destructiveHint=false, so the bar is lower, but the description adds little: it doesn't say whether the created note is returned, whether duplicate titles are allowed, whether tags must already exist, or what tags do at write time. Only the tag-format rule (lowercase, optional) adds behavioral value.

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

Conciseness4/5

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

Two short sentences with the core action front-loaded and no filler. The second sentence is doing real work on the only non-obvious parameter.

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

Completeness3/5

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

An output schema exists, so return values needn't be described, and annotations cover the safety profile. Still, for a 3-parameter creation tool with 0% schema description coverage, the definition leaves required-ness, duplicate handling, and tag prerequisites unaddressed.

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 0%, so the description must carry the load. It does explain the 'tags' parameter (optional, lowercase, filtering semantics), but says nothing about 'title' or 'body' beyond the names, and doesn't state that both are required.

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

Purpose4/5

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

States a specific verb and resource ("Create a note") that maps cleanly onto the CRUD sibling set (get_note, update_note, delete_note). It doesn't explicitly contrast itself with update_note or explain whether the note is created in a shared store, so it stops short of full sibling differentiation.

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

Usage Guidelines2/5

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

No statement of when to use this versus update_note or how it relates to search_notes/list_tags. The only usage-adjacent hint is that tags are 'used for filtering', which implicitly points at search_notes but never says so.

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

delete_noteA
DestructiveIdempotent

Permanently delete a note. Confirm with the user first.

NameRequiredDescriptionDefault
note_idYes

Output Schema

NameRequiredDescription
deleted_idYes

TDQS

A3.8/5.0
Behavior4/5

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

Annotations already declare destructiveHint=true and idempotentHint=true, so the safety profile is known. The description adds value beyond them by stating the deletion is permanent and that user confirmation is required, which is exactly the behavioral context an agent needs before invoking a destructive tool.

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?

Two short sentences with zero waste: the operation is front-loaded and the confirmation requirement follows immediately. Nothing could be removed without losing meaning.

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?

An output schema exists, so return values need not be explained, and annotations cover the destructive/idempotent profile. What is slightly missing is behavior on a nonexistent or already-deleted note_id, though idempotency is declared so the agent can infer safe retry semantics.

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 0%, so the single required parameter note_id is undocumented in both schema and description. However, the parameter is self-evident (an integer note identifier) and the description's scope word "note" aligns with it, so the gap is minor rather than harmful.

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

Purpose4/5

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

States a specific verb (delete), resource (note), and effect (permanently), so the agent knows exactly what the tool does and that it is irreversible. It does not explicitly name a sibling such as update_note to contrast with, but the destructive framing makes it distinguishable from the other note tools.

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?

"Confirm with the user first" is a procedural constraint rather than a when-to-use rule, and there is no explicit guidance on when to choose delete_note over e.g. update_note. Usage is implied by the destructive nature of the operation rather than stated.

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

get_noteB
Read-only

Return the full text of one note.

NameRequiredDescriptionDefault
note_idYes

Output Schema

NameRequiredDescription
idYes
bodyYes
tagsYes
titleYes
created_atYes
updated_atYes

TDQS

B3/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds only that the full text (not a summary) is returned, which is modest added value; it says nothing about what happens for a missing or unauthorized note_id.

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

Conciseness4/5

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

A single front-loaded sentence with zero padding; appropriately sized, though its terseness is achieved partly by omitting necessary detail.

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

Completeness3/5

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

An output schema exists, so return values needn't be explained. However, for a tool whose only parameter is undocumented in the schema, the description should at minimum explain how to source the note_id; that gap leaves it only minimally complete.

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

Parameters2/5

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

Schema coverage is 0% — note_id has no description in the schema — so the description must compensate and does not. It never clarifies that note_id is a required integer identifier or how an agent should obtain one (e.g., via search_notes).

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

Purpose4/5

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

States a specific verb and resource: 'Return the full text of one note.' The singular 'one note' implicitly contrasts with the sibling search_notes, but no sibling is named, so an agent must infer the boundary itself.

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

Usage Guidelines2/5

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

No when-to-use or when-not-to-use guidance, no mention of alternatives like search_notes for finding notes or list_tags. The agent gets no routing signal beyond the bare purpose.

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

list_tagsA
Read-only

All tags in use, with how many notes carry each one.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.5/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds one piece of real value beyond that — each tag comes with a note count — but says nothing about whether deleted/archived notes are counted, whether the list is sorted, or whether it's paginated.

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?

A single short sentence with no wasted words; the key information (tag list plus per-tag counts) is front-loaded. Nothing is padded or repeated from structured fields.

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?

With a read-only annotation, an output schema to explain the return shape, and no parameters, this is nearly complete. The only remaining gap is scoping detail — which notes the counts include and whether results are ordered — which the output schema may or may not cover.

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?

The tool takes zero parameters, so per the baseline a 4 applies. The description correctly implies there is nothing to filter or scope, which matches the empty schema.

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

Purpose4/5

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

The description clearly states the resource (tags) and the payload (count of notes per tag), so an agent knows it's an enumeration of tags with usage counts. It doesn't explicitly differentiate from siblings, but the sibling list is all note CRUD, so the distinction is implicit rather than stated.

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

Usage Guidelines2/5

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

There is no when-to-use guidance, no mention of alternatives (e.g., search_notes for filtering by tag), and no statement of prerequisites or context. The agent must infer that this is a discovery/lookup helper for finding tag names before another call.

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

search_notesA
Read-only

Full-text search over titles, bodies and tags, best match first. Matching words are wrapped in [brackets] in the snippet. Optionally filter by one tag.

NameRequiredDescriptionDefault
tagNo
limitNo
queryYes

Output Schema

NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true and openWorldHint=false, so safety is covered; the description adds genuinely new behavioral detail in the ranked ordering and the [brackets] highlighting convention in snippets. It stops short of covering pagination/limit behavior or what happens with zero matches. No contradiction with 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?

Two short sentences, no filler; the core purpose and result ordering come first and the snippet-format detail follows. Every clause carries information an agent needs.

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?

Output schema exists, so return values need not be described, and the ranking plus bracket highlighting fill the main behavioral gap. The omission of limit semantics and any routing guidance versus siblings are the only remaining holes for a read-only three-parameter search tool.

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 0%, so the description must compensate: it usefully clarifies that 'query' spans titles, bodies and tags, and that 'tag' accepts only one value (not a list). It says nothing about 'limit', leaving one of three parameters unexplained in both schema and description.

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

Purpose4/5

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

States a specific verb (full-text search) plus the fields searched (titles, bodies, tags) and the result ordering (best match first), which clearly separates it from get_note. It never names a sibling or states that it takes a free-text query rather than an identifier, so differentiation is implied rather than explicit.

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 closing line 'Optionally filter by one tag' gives a usage hint for one parameter, but there is no guidance on when to search versus fetching a known note by ID or listing tags, and no exclusions. Usage is inferable from the name and purpose statement only.

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

update_noteA

Change a note. Only the fields you pass are updated; passing tags replaces all tags.

NameRequiredDescriptionDefault
bodyNo
tagsNo
titleNo
note_idYes

Output Schema

NameRequiredDescription
idYes
bodyYes
tagsYes
titleYes
created_atYes
updated_atYes

TDQS

A3.7/5.0
Behavior4/5

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

Annotations only say readOnlyHint=false and destructiveHint=false; the description adds the crucial nuance that tags are wholesale replaced rather than merged, which is effectively a data-loss behavior the annotations do not convey. It stops short of stating failure behavior for a bad note_id or whether fields can be cleared.

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?

Two tight sentences, no filler, and the most surprising constraint (tag replacement) is placed where it will be read before invocation.

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

Completeness3/5

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

An output schema exists so return values need no explanation, and the mutation model is covered. Missing is what happens when note_id doesn't resolve, and how the anyOf-null defaults interact with intent to clear a field — an agent could easily mis-call this.

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 0%, so the description carries the burden. It does explain the omit-means-unchanged rule and the tags replacement rule, but says nothing about title vs body, the required note_id, or whether passing null clears a field versus skipping it — a real ambiguity given every optional param defaults to null.

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

Purpose4/5

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

"Change a note" gives a clear verb+resource and the object is unambiguous given siblings add_note/get_note/delete_note. It doesn't explicitly differentiate itself from the other note tools, but the mutation semantics set it apart well enough.

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 establishes partial-update semantics ("Only the fields you pass are updated"), which tells the agent how to invoke it, but never says when to prefer it over siblings or what prerequisites exist (e.g. note must already exist). Usage is implied rather than guided.

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. 6 tool updatesv0.1.0
    • First observedadd_note
    • First observeddelete_note
    • First observedget_note
    • First observedlist_tags
    • First observedsearch_notes
    • First observedupdate_note

TDQS

A3.7/5.0

Scored across 6 tools

Disambiguation5/5

Each tool maps to a distinct resource-action pair: create, full-text search, retrieve, update, delete, and tag enumeration. The only near-neighbors (search_notes vs list_tags) are clearly separated by purpose (content matching vs tag inventory). No two tools appear interchangeable.

Naming Consistency5/5

All names follow a strict snake_case verb_noun pattern (add_note, search_notes, get_note, update_note, delete_note, list_tags). The convention is predictable and the verbs accurately signal semantics (add vs get vs update vs delete).

Tool Count5/5

Six tools is well-scoped for a notes server: full CRUD plus search and tag listing, with no filler or redundant variants. Every tool earns its place in a core workflow.

Completeness4/5

CRUD, full-text search with tag filtering, and tag inventory cover the essential note lifecycle with no dead ends for typical workflows. Minor gap: there is no plain list_notes for enumerating notes without a search term, and no tag rename/delete operation, though both are largely workable via search and update_note.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI assistants to search, read, create, update, and remove personal markdown notes stored locally, providing persistent memory across sessions.
    84 npm
    2
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables AI agents to read and write UpNote notes locally via SQLite and URL schemes, supporting search, creation, editing, and organization.
    19
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides AI assistants with tools to create, list, search, tag, and delete notes stored in a local SQLite database.
    -