MCP Notes is an MCP (Model Context Protocol) server for managing notes. It stores tagged notes in a directory of markdown files and exposes tools to manage them through the Model Context Protocol.
- Add Notes: Create new notes with titles, content, and tags
- Hierarchical Structure: Organize notes in a parent-child hierarchy with unlimited nesting levels
- Retrieve Notes: Get notes by filename, including nested notes
- Update Notes: Modify existing note content and tags by filename
- List Notes: View notes at any level of the hierarchy
- Delete Notes: Remove notes by filename with automatic cleanup of empty directories
- Move Notes: Relocate notes between directories with automatic reference updates
- Tag Management: Add and remove tags from existing notes
- File-based Storage: Notes are stored as markdown files in a hierarchical directory structure
- JSON Index: Fast lookups using separate JSON index files for each directory level
- Automatic Counting: Tracks children-count and descendant-count for notes with sub-notes
Install the package using pip:
pip install .For development, install with dev dependencies:
pip install -e ".[dev]"Start the MCP Notes server by specifying a directory to store notes:
mcp-notes --dir /path/to/notes/directoryThe server will create the directory if it doesn't exist and start listening for MCP connections.
The server exposes the following MCP tools:
Create a new note with title, content, and optional tags. Can be nested under a parent note.
title(str): Note titlecontent(str): Note contenttags(List[str], optional): Tags for the noteparent(str, optional): Parent note filename for hierarchical organization
Retrieve a note by filename, supporting nested paths.
filename(str): Note filename (e.g., "note.md" or "parent/child.md")
List notes at a specific hierarchy level. Returns note info including title, tags, and child counts.
parent(str, optional): Parent directory to list children from (omit for top-level)
Update existing note content and tags while preserving the title.
filename(str): Note filename to updatecontent(str): New note contenttags(List[str], optional): New tags for the note
Delete a note by filename with automatic cleanup of empty directories.
filename(str): Note filename to delete
Move a note to a different directory and update all references in other notes.
filename(str): Note filename to movetarget_folder(str, optional): Target directory (None for root)
Add new tags to an existing note, avoiding duplicates.
filename(str): Note filename to add tags totags(List[str]): Tags to add
Remove specified tags from an existing note.
filename(str): Note filename to remove tags fromtags(List[str]): Tags to remove
Example Usage:
# Create and organize notes
add_note(title="Project Alpha", content="Main project docs", tags=["project"])
add_note(title="Tasks", content="Task list", parent="project_alpha")
# Manage tags
add_tags(filename="project_alpha.md", tags=["urgent", "review"])
remove_tags(filename="project_alpha.md", tags=["review"])
# Move and reorganize
move_note(filename="project_alpha/tasks.md", target_folder="archive")Notes are organized in a hierarchical directory structure:
notes_directory/
├── notes_index.json # Index for top-level notes
├── project_alpha.md # Top-level note
├── personal_notes.md # Another top-level note
├── project_alpha/ # Subdirectory for project_alpha children
│ ├── notes_index.json # Index for project_alpha children
│ ├── meeting_notes.md # Child note
│ ├── tasks.md # Another child note
│ └── research/ # Sub-subdirectory for deeper nesting
│ ├── notes_index.json # Index for research notes
│ └── market_analysis.md # Grandchild note
└── personal_notes/ # Subdirectory for personal_notes children
├── notes_index.json # Index for personal_notes children
└── shopping_list.md # Child note
Each note is stored as a markdown file with the following format:
# Note Title
Tags: tag1, tag2, tag3
Note content goes here...Each directory maintains its own notes_index.json file for fast lookups within that level of the hierarchy. The index contains metadata for notes in that specific directory only, not for notes in subdirectories.
For notes that have child notes, the index automatically includes count information:
{
"Project Alpha": {
"filename": "project_alpha.md",
"tags": ["work", "project"],
"children-count": 3,
"descendant-count": 8
}
}- children-count: Number of immediate child notes (direct children only)
- descendant-count: Total number of all nested notes recursively
- Notes without children do not have these keys to keep the index clean
Create a virtual environment and install dependencies:
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -e ".[dev]"Run the test suite using pytest:
python -m pytestFormat code using ruff:
python -m ruff formatRun linting:
python -m ruff checkAuto-fix linting issues:
python -m ruff check --fixmcp-notes/
├── mcp_notes/
│ ├── __init__.py
│ ├── __main__.py # CLI entry point
│ ├── mcp_server.py # FastMCP server and tools
│ └── storage.py # Note storage management
├── tests/
├── pyproject.toml # Project configuration
├── ruff.toml # Linting configuration
└── README.md
- Python 3.8+
- FastMCP
- Model Context Protocol compatible client
This project is available under the MIT License.