mcp
MCP Server
Model Context Protocol (MCP) сервер для интеграции заметок с AI-агентами (Claude, Cursor, etc).
Endpoint
POST /_system/mcp
Content-Type: application/json
JSON-RPC 2.0 протокол.
Tools
Базовые
| Tool | Описание | Параметры |
|---|---|---|
search |
Hybrid search по заметкам | query: string |
similar |
Похожие заметки (vector search) | text: string, limit?: number |
Динамические методы
Заметки с mcp_method в frontmatter становятся callable tools.
Frontmatter формат
---
free: true # обязательно для публичного доступа
mcp_method: code-review # имя метода (tool name)
mcp_description: "Детальный code review" # описание для tools/list
---
Контент заметки - это то, что вернётся при вызове метода.
Может содержать любой текст, шаблоны, инструкции.
Примеры использования
tools/list
Request:
{
"jsonrpc": "2.0",
"method": "tools/list",
"id": 1
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "search",
"description": "Search notes by query",
"inputSchema": {
"type": "object",
"properties": {
"query": {"type": "string"}
},
"required": ["query"]
}
},
{
"name": "similar",
"description": "Find similar notes by text",
"inputSchema": {
"type": "object",
"properties": {
"text": {"type": "string"},
"limit": {"type": "number"}
},
"required": ["text"]
}
},
{
"name": "code-review",
"description": "Детальный code review"
}
]
}
}
tools/call search
Request:
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "search",
"arguments": {
"query": "golang error handling"
}
},
"id": 2
}
Response:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "Found 3 notes:\n\n1. Error Handling in Go\n /programming/go-errors\n\n2. ..."
}
]
}
}
tools/call {method}
Request:
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "code-review",
"arguments": {}
},
"id": 3
}
Response:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "Контент заметки code-review..."
}
]
}
}
Фильтрация заметок
- search/similar: все заметки с
free: true - dynamic methods: заметки с
free: trueИmcp_methodзаданным
План имплементации
Story 1: Поля в NoteView
Добавить в internal/model/note.go:
type NoteView struct {
// ... existing fields ...
MCPMethod string // from frontmatter mcp_method
MCPDescription string // from frontmatter mcp_description
}
Добавить extraction в ExtractMetaData():
func (n *NoteView) extractMCPFields() {
if method, ok := n.RawMeta["mcp_method"].(string); ok {
n.MCPMethod = method
}
if desc, ok := n.RawMeta["mcp_description"].(string); ok {
n.MCPDescription = desc
}
}
Story 2: MCP Endpoint
Создать internal/case/mcp/:
internal/case/mcp/
├── endpoint.go # HTTP handler, JSON-RPC routing
├── resolve.go # main logic
├── tools.go # tools/list implementation
├── search.go # search tool
├── similar.go # similar tool
└── method.go # dynamic method dispatch
endpoint.go:
package mcp
type Endpoint struct{}
func (*Endpoint) Path() string {
return "/_system/mcp"
}
func (*Endpoint) Method() string {
return http.MethodPost
}
Story 3: tools/list
func (h *Handler) ListTools(env Env) ListToolsResult {
tools := []Tool{
{Name: "search", Description: "Search notes", InputSchema: searchSchema},
{Name: "similar", Description: "Find similar notes", InputSchema: similarSchema},
}
// Add dynamic methods from notes
for _, note := range env.LiveNoteViews().List {
if note.Free && note.MCPMethod != "" {
tools = append(tools, Tool{
Name: note.MCPMethod,
Description: note.MCPDescription,
})
}
}
return ListToolsResult{Tools: tools}
}
Story 4: tools/call search
Переиспользовать internal/case/searchnotes/:
func (h *Handler) CallSearch(env Env, query string) CallToolResult {
results := searchnotes.Resolve(ctx, env, searchnotes.Input{Query: query})
// Filter to free notes only
// Format as text response
return CallToolResult{Content: [...]}
}
Story 5: tools/call similar
Переиспользовать существующий vector search:
func (h *Handler) CallSimilar(env Env, text string, limit int) CallToolResult {
// Get embedding for text
// Find similar notes by vector
// Filter to free notes
// Format response
}
Story 6: tools/call {method}
func (h *Handler) CallMethod(env Env, methodName string) CallToolResult {
for _, note := range env.LiveNoteViews().List {
if note.Free && note.MCPMethod == methodName {
return CallToolResult{
Content: []Content{{Type: "text", Text: string(note.Content)}},
}
}
}
return ErrorResult{Code: -32601, Message: "Method not found"}
}
Фаза 2 (будущее)
Marketplace для промптов:
- Платные методы (
price: 0.01в frontmatter) - Авторизация пользователей
- Трекинг usage для billing
- Discovery:
search_marketplacetool - Per-author endpoints:
/_system/mcp/{username}