feat(§03): 实现 MCP Server 核心 - Storage/Service/Tool/MCP Protocol Layers
**Storage Layer:** - Database 类(aiosqlite + WAL + 并发保护) - WikiPage 数据模型 - fix_dirty_states 恢复机制 - FTS5 全文搜索支持 - 完整的 SQLite 表结构 **Service Layer:** - CacheService(LRU 缓存 + TTL + 大小限制) - QueryService(查询服务) - ParserService(Markdown 解析) - IndexerService(索引服务) - GraphService(链接图服务) **Tool Layer (8 个 MCP Tools):** - wiki_query - FTS5 全文搜索 + 标签过滤 - memory_bridge - 按工具来源浏览 - wiki_status - 索引状态 - wiki_lint - 健康审计 - cross_linker - 缺失链接发现 - tag_taxonomy - 标签一致性 - wiki_synthesize - 跨概念综合分析 - daily_update - 日常维护 + hot.md 生成 **MCP Protocol Layer:** - MCP 协议解析和封装 - 工具注册和路由 - 错误处理和日志 - stdio 模式支持 **配置和部署:** - requirements.txt - config.example.yaml - ecosystem.config.cjs (PM2) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
"""
|
||||
Tool Layer - cross_linker 工具
|
||||
|
||||
扫描 wiki,自动发现缺失的交叉引用。
|
||||
|
||||
参考设计文档:第 2.2 节
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Dict, Any, List
|
||||
from ..services import GraphService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CrossLinkerTool:
|
||||
"""cross_linker 工具实现"""
|
||||
|
||||
def __init__(self, graph_service: GraphService):
|
||||
self.graph_service = graph_service
|
||||
|
||||
async def handle(self, path: str = "", dry_run: bool = True) -> Dict[str, Any]:
|
||||
"""
|
||||
扫描 wiki,发现缺失的交叉引用
|
||||
|
||||
Args:
|
||||
path: 指定路径(空字符串表示全部)
|
||||
dry_run: 是否为模拟运行(不实际修改)
|
||||
|
||||
Returns:
|
||||
{
|
||||
"missing_links": [
|
||||
{
|
||||
"source": "practices/a.md",
|
||||
"target": "concepts/x",
|
||||
"suggestion": "Consider creating [[concepts/x]]"
|
||||
}
|
||||
],
|
||||
"total": 12,
|
||||
"dry_run": true
|
||||
}
|
||||
"""
|
||||
# 获取缺失的链接
|
||||
all_missing = await self.graph_service.find_missing_links()
|
||||
|
||||
# 过滤指定路径
|
||||
if path:
|
||||
missing_links = [(s, t) for s, t in all_missing if s == path or t == path]
|
||||
else:
|
||||
missing_links = all_missing
|
||||
|
||||
# 格式化结果
|
||||
missing_links_formatted = []
|
||||
for source, target in missing_links:
|
||||
missing_links_formatted.append({
|
||||
"source": source,
|
||||
"target": target,
|
||||
"suggestion": f"Consider creating [[{target}]] or updating the link in [[{source}]]"
|
||||
})
|
||||
|
||||
return {
|
||||
"missing_links": missing_links_formatted[:50], # 最多返回 50 条
|
||||
"total": len(missing_links),
|
||||
"dry_run": dry_run
|
||||
}
|
||||
|
||||
def get_schema(self) -> dict:
|
||||
"""返回 MCP Tool schema"""
|
||||
return {
|
||||
"name": "cross_linker",
|
||||
"description": "扫描 wiki,自动发现缺失的交叉引用",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "指定路径(空字符串表示全部)"
|
||||
},
|
||||
"dry_run": {
|
||||
"type": "boolean",
|
||||
"default": True,
|
||||
"description": "是否为模拟运行(不实际修改)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user