使用说明
备注MCP服务器
一种本地笔记模型上下文协议(MCP)服务器,提供智能笔记管理,具有标记存储和强大的搜索功能。
特性
- Markdown存储:笔记存储为带有frontmatter元数据的markdown文件
- 智能索引:基于CSV的索引,用于快速检索和搜索
- 强大的搜索功能:具有相关性评分和模糊匹配的全文搜索
- 语义搜索:使用嵌入的AI驱动的基于意义的搜索(查找概念上相似的注释)
- 混合搜索:结合关键字和语义搜索以获得最佳结果
- 基于ULID的命名:按时间顺序排序的唯一标识符
- 数据库就绪:结构设计便于迁移到关系数据库
- MCP工具:笔记管理的四个核心工具
快速开始
安装
pip install -e .
配置
创建配置文件 .notes_config.yaml:
notes:
directory: "~/notes"
max_file_size: 10485760 # 10MB
auto_rebuild_index: true
index_rebuild_interval: 3600 # 1 hour
search:
max_results: 50
fuzzy_threshold: 0.8
stop_words_file: "stopwords.txt"
security:
validate_paths: true
sanitize_input: true
运行服务器
本地开发
# Activate virtual environment
source venv/bin/activate
# Run the MCP server
notes-mcp
MCP服务器配置
服务器可以通过以下方式配置:
- 配置文件:
.notes_config.yaml(推荐) - 环境变量:覆盖配置文件设置
- 命令行参数:运行时覆盖
配置文件示例:
notes:
directory: "~/.notes"
max_file_size: 10485760 # 10MB
auto_rebuild_index: true
index_rebuild_interval: 3600 # 1 hour
search:
max_results: 50
fuzzy_threshold: 0.8
stop_words_file: "stopwords.txt"
security:
validate_paths: true
sanitize_input: true
环境变量:
export NOTES_DIR="~/my-notes"
export SEARCH_MAX_RESULTS=100
export SEARCH_FUZZY_THRESHOLD=0.7
MCP服务器集成
克劳德桌面版
-
安装软件包:
cd /path/to/notes-mcp pip install -e . -
配置Claude桌面:
- 打开克劳德桌面设置
- 添加MCP服务器配置:
{ "mcpServers": { "notes-mcp": { "command": "notes-mcp", "args": [], "env": { "NOTES_DIR": "~/.notes" } } } } -
重新启动克劳德桌面 加载MCP服务器
帆板运动
-
安装软件包:
cd /path/to/notes-mcp pip install -e . -
配置Windsurf:
- 打开Windsurf设置
- 添加MCP服务器:
{ "name": "notes-mcp", "command": "notes-mcp", "args": [], "env": { "NOTES_DIR": "~/notes" } } -
重新启动Windsurf 启用MCP工具
其他MCP客户端
服务器遵循MCP规范,可以与任何兼容MCP的客户端集成。使用以下服务器配置:
{
"name": "notes-mcp",
"command": "notes-mcp",
"args": [],
"env": {
"NOTES_DIR": "~/notes"
}
}
用法示例
创建笔记
# Using the MCP tools in Claude
create_note(
title="Project Planning",
content="# Project Planning\n\n## Goals\n- Define objectives\n- Set timeline",
tags=["planning", "project"]
)
搜索笔记
# Find notes by content
search_note(query="planning")
# Find notes by tags
find_note(tags=["project", "urgent"])
# Get recent notes
find_note(limit=10)
管理笔记
# Get a specific note
get_note(identifier="01H8X9V2P3R5Y7T8Q0W2E4R6T8Y0U2I3")
# Update a note
# (Note: This would be implemented through the MCP tools)
服务器命令
这 notes-mcp 命令支持多个选项:
# Run with custom config file
notes-mcp --config /path/to/config.yaml
# Run with custom notes directory
notes-mcp --notes-dir /path/to/notes
# Show server status
notes-mcp --status
# Rebuild index
notes-mcp --rebuild-index
# Validate index integrity
notes-mcp --validate-index
MCP工具
create_note
使用自动索引创建新笔记。
参数:
title(必填):备注标题content(必填):Markdown内容tags(可选):用户定义标签friendly_name(可选):自定义友好名称date(可选):自定义日期
get_note
通过ULID或文件名检索特定注释。
参数:
identifier(必填):ULID或文件名include_metadata(可选):包括前端元数据include_content(可选):包括注释正文
find_note
按日期范围、标签或友好名称模式查找笔记。
参数:
date_from(可选):开始日期(YYYYMMDDHHmmss)date_to(可选):结束日期(YYYYMMDDHHmmss)tags(可选):按标签筛选friendly_name_pattern(可选):用于友好名称的正则表达式模式limit(可选):最大结果(默认值:50)
search_note
在笔记内容和元数据中进行全文搜索。
参数:
query(必填):搜索查询search_in(可选):搜索目标[“内容”、“标题”、“标签”、“摘要”]fuzzy(可选):启用模糊匹配(默认值:true)limit(可选):最大结果(默认值:50)
网络观众
用于浏览笔记的轻量级web界面。
快速开始
# Install frontend dependencies
just web-install
# Option 1: Development mode (with hot reload)
# Terminal 1: Start backend
just web-server
# Terminal 2: Start frontend dev server
just web-dev
# Open http://localhost:5173
# Option 2: Production mode
just web
# Open http://localhost:8000
特性
- 基于卡片的布局显示最后12个注释
- 模糊匹配的全文搜索
- 按标签筛选
- 按日期或标题排序
- 带语法高亮显示的Markdown渲染
- 带有词频的统计面板
技术栈
- 前端:Svelte+Vite(通过电容器/Tauri便携式到手机/台式机)
- 后端:FastAPI
- 标记语言:marked.js
看 WEB.md 详细文档。
文件结构
注释以文件名格式存储: <ULID>_<YYYYMMDDHHmmss>_<friendly_name>.md
例子: 01H8X9V2P3R5Y7T8Q0W2E4R6T8Y0U2I3_20260120143000_meeting_notes.md
每张便条都包含前言:
---
title: Project Meeting Notes
date: 2026-01-20
tags: project;meeting;urgent
ulid: 01H8X9V2P3R5Y7T8Q0W2E4R6T8Y0U2I3
---
# Project Meeting Notes
Meeting content in markdown format...
索引格式
这 .notes_index.csv 文件包含用于快速搜索的元数据:
ulid|date_key|friendly_name|title|tags|frequent_words|summary|file_path|created_at|updated_at|last_accessed|file_size|checksum
建筑
服务器完全基于文件,没有数据库。存储分为三层:
存储层
- Markdown文件 --每个音符都是
.md带有YAML frontmatter(标题、标签、时间戳)和编码ULID、日期键和友好名称的文件名的文件。 - CSV文本索引 (
.notes_index.csv)--一个平面CSV文件,镜像笔记元数据,无需读取每个markdown文件即可快速查找。由文件锁保护,用于并发写入。 - FAISS语义索引 (
.semantic_index.faiss+.semantic_metadata.json)--通过以下方式生成的向量嵌入bge-small-en-v1.5(384 dim)存储在FAISS中IndexFlatL2指数。可选;在以下情况下优雅地禁用faiss或sentence-transformers未安装。
搜索管道
┌─────────┐
│ Query │
└────┬────┘
│
┌─────────────┴──────────────┐
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Keyword Search │ │ Semantic Search │
└────────┬────────┘ └────────┬────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ Load all notes from │ │ Encode query with │
│ CSV index into │ │ bge-small-en-v1.5 │
│ memory │ │ (384-dim embedding) │
└─────────┬───────────┘ └──────────┬──────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ Per note, per field:│ │ FAISS IndexFlatL2 │
│ │ │ brute-force L2 │
│ fuzzy=false: │ │ nearest-neighbour │
│ substring match │ │ search │
│ +0.5 word-boundary│ └───────────┬─────────┘
│ │ │
│ fuzzy=true: │ ▼
│ partial_ratio │ ┌──────────────────────┐
│ token_set_ratio │ │ Convert L2 distance │
│ best of two / 100 │ │ to similarity (0–1): │
└─────────┬───────────┘ │ │
│ │ sim = 1 - (d / 10.0) │
▼ │ score = sim × 2.0 │
┌─────────────────────┐ └───────────┬──────────┘
│ Apply field weights:│ │
│ │ │
│ title ×3.0 │ │
│ source_dir ×3.0 │ │
│ source_repo ×3.0 │ │
│ tags ×2.0 │ │
│ summary ×1.5 │ │
│ content ×1.0 │ │
└─────────┬───────────┘ │
│ │
▼ │
┌─────────────────────┐ │
│ Recency boost: │ │
│ │ │
│ factor = 1 - (days │ │
│ since update /365)│ │
│ score += score │ │
│ × factor × 0.2 │ │
│ (max +20% boost) │ │
└─────────┬───────────┘ │
│ │
▼ ▼
keyword_score semantic_score
│ │
└──────────┬───────────────────┘
│
▼
┌────────────────────────────┐
│ Hybrid merge │
│ │
│ combined = keyword × 0.5 │
│ + semantic × 0.5 │
│ │
│ (weights are configurable) │
└─────────────┬──────────────┘
│
▼
┌────────────────────────────┐
│ Sort by combined score │
│ (descending), return top N │
└────────────────────────────┘
这两条路径独立运行,并在最后合并:
- 关键字路径:从CSV索引中加载所有笔记,使用精确子字符串匹配或模糊匹配对每个字段进行评分(
thefuzz图书馆与partial_ratio+token_set_ratio),应用字段权重(标题/source_dir/source_repo×3,标签×2,摘要×1.5,内容×1)和最近度提升(最大+20%)。 - 语义路径:使用索引时使用的相同句子变换器模型对查询进行编码,对FAISS索引执行暴力L2最近邻搜索,并将距离转换为归一化的相似性得分。
- 合并:使用加权加法将两条路径的每个音符的分数合并,然后按分数降序排序。只有一条路径找到的注释仍然会出现(缺少的路径贡献0)。
重新索引
NoteManager.rebuild_index() 精心策划全面重建:
- 截断CSV并重新扫描所有
*.md从notes目录中提取文件,解析frontmatter并计算校验和。 - 获取新构建的笔记列表并将其传递给
SemanticEngine.rebuild_index(),通过重新编码每个音符,从头开始创建一个新的FAISS索引。
A. validate_index 命令检测孤立文件(在磁盘上,但不在CSV中)和丢失文件(在CSV中,但已从磁盘中删除)。
已知限制
此实现专为个人使用而设计,最多可包含几百个音符。以下限制适用:
扩展
- 每次搜索都会将整个CSV加载到内存中 并线性扫描。超过1000个音符时,性能会明显下降。
- 更新和删除重写整个CSV文件。 没有就地行编辑。
add_note扫描完整的CSV 在附加之前进行重复检查——每次插入O(n)。- 无分页 上
get_all_notes--总是将所有内容加载到内存中。 - 无缓存 --每次重复搜索都会重新读取和解析CSV。
指标一致性
- CSV索引和FAISS索引是独立更新的,没有交易保证。两次写入之间的崩溃可能会使它们不同步。
get_all_notes()不获取文件锁,因此读取可以与正在进行的写入竞争。- 重新索引要么全有,要么全无;没有仅检测更改文件的增量同步。
语义搜索
IndexFlatL2每个查询的暴力破解次数为O(n)。FAISS提供了近似指标(试管婴儿、HNSW),可以提高大型采集的性能。- 使用L2距离,但句子变换器模型通常针对余弦相似性进行优化。规范嵌入或切换到
IndexFlatIP会更准确。
模糊搜索
- 用途
thefuzz(纯Python Levenshtein)在长文本字段上运行缓慢,尤其是content。大型文档不会短路。 - 模糊阈值是一个单一的全局值,没有逐场调整。
故障排除
常见问题
服务器无法启动
# Check if MCP library is installed
pip install mcp>=1.25.0
# Verify the server can start
notes-mcp --status
注释未出现在搜索中
# Rebuild the index
notes-mcp --rebuild-index
# Validate index integrity
notes-mcp --validate-index
权限错误
- 确保notes目录存在并且可写
- 检查文件权限:
chmod 755 ~/notes
MCP客户端连接问题
- 验证服务器是否正在运行:
notes-mcp --status - 检查stderr输出是否有错误(日志转到stderr)
- 确保MCP客户端配置中的命令路径正确
语义搜索
语义搜索根据意义而不仅仅是关键字来查找笔记。它使用AI嵌入来理解查询的上下文和意图。
运作原理
- 创建或更新注释时,其内容将转换为矢量嵌入
- 嵌入内容存储在FAISS索引中(
.semantic_index.faiss) - 搜索查询也被转换为嵌入,并与注释嵌入进行比较
- 结果按语义相似性排序
启用语义搜索
默认情况下启用语义搜索。要配置:
search:
enable_semantic: true # Enable/disable semantic search
semantic_model: "bge-small-en-v1.5" # Embedding model to use
semantic_weight: 0.5 # Weight in hybrid search (0-1)
keyword_weight: 0.5 # Weight in hybrid search (0-1)
查询示例
无语义搜索(仅关键字):
Query: "project planning"
Results: Only notes containing exact words "project" or "planning"
使用语义搜索:
Query: "project planning"
Results:
- "Project planning" (keyword match)
- "Quarterly roadmap and objectives" (semantically similar)
- "Team goal-setting session" (semantically similar)
- "Sprint retrospective notes" (loosely related)
演出
- 第一次搜索:约2-3秒(从缓存加载模型)
- 后续搜索:50-100ms
- 存储空间:FAISS索引中每张钞票约1 KB
- 型号:33 MB(缓存在
~/.cache/huggingface)
禁用语义搜索
要仅使用关键字搜索(如果内存有限,速度会更快):
search_engine = SearchEngine(config=config)
search_engine.enable_semantic = False
results = search_engine.search_notes("query")
调试模式
运行测试脚本以验证服务器功能:
python test_mcp_server.py
发展
项目结构
notes-mcp/
├── notes_mcp/
│ ├── __init__.py
│ ├── server.py # MCP server implementation
│ ├── note.py # Note model
│ ├── note_manager.py # High-level note operations
│ ├── index_manager.py # CSV index management
│ ├── search_engine.py # Search and text analysis
│ ├── config.py # Configuration management
│ ├── utils.py # Utility functions
│ └── web/ # Web viewer
│ ├── app.py # FastAPI backend
│ └── frontend/ # Svelte frontend
├── tests/ # Test suite (146 tests)
├── examples/ # Usage examples
└── requirements.txt
运行测试
# Run all tests
pytest
# Run with coverage report
pytest --cov=notes_mcp --cov-report=html
# Run specific test file
pytest tests/test_search_engine.py -v
代码覆盖率
当前覆盖范围: 88% (不包括CLI工具)
pytest --cov=notes_mcp --cov-report=term-missing
API 参考
Python API
from notes_mcp.note_manager import NoteManager
from notes_mcp.search_engine import SearchEngine
from notes_mcp.config import Config
# Initialise
config = Config()
note_manager = NoteManager(config)
search_engine = SearchEngine(note_manager, config)
# Create a note
note = note_manager.create_note(
title="My Note",
content="Note content here",
tags=["tag1", "tag2"]
)
# Search notes
results = search_engine.search_notes("query", fuzzy=True)
for result in results:
print(f"{result.note.title}: {result.score}")
# Find notes by criteria
notes = search_engine.find_notes(
tags=["project"],
date_from="20260101",
date_to="20261231"
)
搜索引擎方法
| 方法 | 说明 |
|---|---|
search_notes(query, search_in, fuzzy, limit) |
带有相关性评分的全文搜索 |
find_notes(date_from, date_to, tags, pattern, limit) |
按条件筛选笔记 |
fuzzy_match(text, query, threshold) |
计算模糊匹配分数 |
advanced_search(query, tags, date_from, date_to, fuzzy, boost_tags, limit) |
搜索与增强相结合 |
文本分析器方法
| 方法 | 说明 |
|---|---|
tokenize_text(text) |
将文本拆分为标记 |
remove_stop_words(words) |
过滤掉常用词 |
extract_keywords(text, max_keywords) |
提取重要关键字 |
generate_summary(text, max_sentences) |
创建文本摘要 |
calculate_word_frequency(text) |
统计单词出现次数 |
许可证
MIT许可证-有关详细信息,请参阅许可证文件。
