475 lines
13 KiB
Go
475 lines
13 KiB
Go
package main
|
||
|
||
import (
|
||
"sort"
|
||
"strconv"
|
||
)
|
||
|
||
// Tool 定义了 MCP 工具的元数据和执行逻辑
|
||
type Tool struct {
|
||
Name string
|
||
Description string
|
||
InputSchema map[string]interface{}
|
||
Handler func(args map[string]interface{}) (string, error)
|
||
}
|
||
|
||
// ToolRegistry 存储所有已注册的工具
|
||
var ToolRegistry = make(map[string]Tool)
|
||
|
||
func (s *TaoServer) RegisterTools() {
|
||
// 1) query_memory
|
||
ToolRegistry["query_memory"] = Tool{
|
||
Name: "query_memory",
|
||
Description: "在知识海洋中进行全文检索(默认 exact;causal 时可传 related_terms 作为关联词数组;默认不搜索归档区,需 include_archive=true 才会搜索 _Archive)",
|
||
InputSchema: map[string]interface{}{
|
||
"type": "object",
|
||
"properties": map[string]interface{}{
|
||
"q": map[string]interface{}{"type": "string", "description": "关键词"},
|
||
"mode": map[string]interface{}{"type": "string", "enum": []string{"exact", "causal"}, "default": "exact"},
|
||
"related_terms": map[string]interface{}{"type": "array", "items": map[string]interface{}{"type": "string"}, "description": "关联词数组(仅 mode=causal)"},
|
||
"include_archive": map[string]interface{}{"type": "boolean", "default": false},
|
||
},
|
||
"required": []string{"q"},
|
||
},
|
||
Handler: func(args map[string]interface{}) (string, error) {
|
||
q, _ := args["q"].(string)
|
||
includeArchive := false
|
||
if v, ok := args["include_archive"]; ok {
|
||
if b, ok := v.(bool); ok {
|
||
includeArchive = b
|
||
}
|
||
}
|
||
mode := "exact"
|
||
if v, ok := args["mode"].(string); ok && v != "" {
|
||
mode = v
|
||
}
|
||
related := []string{}
|
||
if v, ok := args["related_terms"]; ok {
|
||
if arr, ok := v.([]interface{}); ok {
|
||
for _, t := range arr {
|
||
if s, ok := t.(string); ok && s != "" {
|
||
related = append(related, s)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
results, _ := s.SearchMemoryAdvanced(q, related, mode == "causal", includeArchive)
|
||
return stringsJoin(results, "\n\n"), nil
|
||
},
|
||
}
|
||
|
||
// 2) get_week_data
|
||
ToolRegistry["get_week_data"] = Tool{
|
||
Name: "get_week_data",
|
||
Description: "获取指定周的所有原始素材用于炼化",
|
||
InputSchema: map[string]interface{}{
|
||
"type": "object",
|
||
"properties": map[string]interface{}{
|
||
"weekOffset": map[string]interface{}{"type": "integer", "default": 0},
|
||
},
|
||
},
|
||
Handler: func(args map[string]interface{}) (string, error) {
|
||
offset := 0
|
||
if val, ok := args["weekOffset"]; ok {
|
||
switch t := val.(type) {
|
||
case float64:
|
||
offset = int(t)
|
||
case int:
|
||
offset = t
|
||
case string:
|
||
if n, err := strconv.Atoi(t); err == nil {
|
||
offset = n
|
||
}
|
||
}
|
||
}
|
||
return s.GetWeekData(offset)
|
||
},
|
||
}
|
||
|
||
// 3) record_summary
|
||
ToolRegistry["record_summary"] = Tool{
|
||
Name: "record_summary",
|
||
Description: "将炼化后的周精华存入 Week_Summary.md(若缺失‘炼丹笔记’结构将自动套用模板)",
|
||
InputSchema: map[string]interface{}{
|
||
"type": "object",
|
||
"properties": map[string]interface{}{
|
||
"content": map[string]interface{}{"type": "string"},
|
||
"weekOffset": map[string]interface{}{"type": "integer", "default": 0},
|
||
},
|
||
"required": []string{"content"},
|
||
},
|
||
Handler: func(args map[string]interface{}) (string, error) {
|
||
content, _ := args["content"].(string)
|
||
offset := 0
|
||
if val, ok := args["weekOffset"]; ok {
|
||
switch t := val.(type) {
|
||
case float64:
|
||
offset = int(t)
|
||
case int:
|
||
offset = t
|
||
case string:
|
||
if n, err := strconv.Atoi(t); err == nil {
|
||
offset = n
|
||
}
|
||
}
|
||
}
|
||
content = s.ApplyWeeklyTemplateIfMissing(content, offset)
|
||
return s.RecordSummary(content, offset)
|
||
},
|
||
}
|
||
|
||
// 4) capture_idea
|
||
ToolRegistry["capture_idea"] = Tool{
|
||
Name: "capture_idea",
|
||
Description: "捕获瞬时灵感/知识片段,自动归档并可附标签",
|
||
InputSchema: map[string]interface{}{
|
||
"type": "object",
|
||
"properties": map[string]interface{}{
|
||
"content": map[string]interface{}{"type": "string", "description": "灵感内容"},
|
||
"tags": map[string]interface{}{"type": "array", "items": map[string]interface{}{"type": "string"}, "description": "可选标签"},
|
||
},
|
||
"required": []string{"content"},
|
||
},
|
||
Handler: func(args map[string]interface{}) (string, error) {
|
||
content, _ := args["content"].(string)
|
||
tags := []string{}
|
||
if v, ok := args["tags"]; ok {
|
||
if arr, ok := v.([]interface{}); ok {
|
||
for _, t := range arr {
|
||
if s, ok := t.(string); ok && s != "" {
|
||
tags = append(tags, s)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return s.CaptureIdea(content, tags)
|
||
},
|
||
}
|
||
|
||
// 5) get_month_data
|
||
ToolRegistry["get_month_data"] = Tool{
|
||
Name: "get_month_data",
|
||
Description: "获取指定月份的周总结素材",
|
||
InputSchema: map[string]interface{}{
|
||
"type": "object",
|
||
"properties": map[string]interface{}{
|
||
"monthOffset": map[string]interface{}{"type": "integer", "default": 0},
|
||
},
|
||
},
|
||
Handler: func(args map[string]interface{}) (string, error) {
|
||
offset := 0
|
||
if val, ok := args["monthOffset"]; ok {
|
||
switch t := val.(type) {
|
||
case float64:
|
||
offset = int(t)
|
||
case int:
|
||
offset = t
|
||
case string:
|
||
if n, err := strconv.Atoi(t); err == nil {
|
||
offset = n
|
||
}
|
||
}
|
||
}
|
||
return s.GetMonthData(offset)
|
||
},
|
||
}
|
||
|
||
// 6) record_month_summary
|
||
ToolRegistry["record_month_summary"] = Tool{
|
||
Name: "record_month_summary",
|
||
Description: "写入月总结 Month_Summary.md",
|
||
InputSchema: map[string]interface{}{
|
||
"type": "object",
|
||
"properties": map[string]interface{}{
|
||
"content": map[string]interface{}{"type": "string"},
|
||
"monthOffset": map[string]interface{}{"type": "integer", "default": 0},
|
||
},
|
||
"required": []string{"content"},
|
||
},
|
||
Handler: func(args map[string]interface{}) (string, error) {
|
||
content, _ := args["content"].(string)
|
||
offset := 0
|
||
if val, ok := args["monthOffset"]; ok {
|
||
switch t := val.(type) {
|
||
case float64:
|
||
offset = int(t)
|
||
case int:
|
||
offset = t
|
||
case string:
|
||
if n, err := strconv.Atoi(t); err == nil {
|
||
offset = n
|
||
}
|
||
}
|
||
}
|
||
return s.RecordMonthSummary(content, offset)
|
||
},
|
||
}
|
||
|
||
// 7) get_quarter_data
|
||
ToolRegistry["get_quarter_data"] = Tool{
|
||
Name: "get_quarter_data",
|
||
Description: "获取指定季度的月总结素材",
|
||
InputSchema: map[string]interface{}{
|
||
"type": "object",
|
||
"properties": map[string]interface{}{
|
||
"quarterOffset": map[string]interface{}{"type": "integer", "default": 0},
|
||
},
|
||
},
|
||
Handler: func(args map[string]interface{}) (string, error) {
|
||
offset := 0
|
||
if val, ok := args["quarterOffset"]; ok {
|
||
switch t := val.(type) {
|
||
case float64:
|
||
offset = int(t)
|
||
case int:
|
||
offset = t
|
||
case string:
|
||
if n, err := strconv.Atoi(t); err == nil {
|
||
offset = n
|
||
}
|
||
}
|
||
}
|
||
return s.GetQuarterData(offset)
|
||
},
|
||
}
|
||
|
||
// 8) record_quarter_summary
|
||
ToolRegistry["record_quarter_summary"] = Tool{
|
||
Name: "record_quarter_summary",
|
||
Description: "写入季总结 Quarter_Summary.md",
|
||
InputSchema: map[string]interface{}{
|
||
"type": "object",
|
||
"properties": map[string]interface{}{
|
||
"content": map[string]interface{}{"type": "string"},
|
||
"quarterOffset": map[string]interface{}{"type": "integer", "default": 0},
|
||
},
|
||
"required": []string{"content"},
|
||
},
|
||
Handler: func(args map[string]interface{}) (string, error) {
|
||
content, _ := args["content"].(string)
|
||
offset := 0
|
||
if val, ok := args["quarterOffset"]; ok {
|
||
switch t := val.(type) {
|
||
case float64:
|
||
offset = int(t)
|
||
case int:
|
||
offset = t
|
||
case string:
|
||
if n, err := strconv.Atoi(t); err == nil {
|
||
offset = n
|
||
}
|
||
}
|
||
}
|
||
return s.RecordQuarterSummary(content, offset)
|
||
},
|
||
}
|
||
|
||
// 9) get_semiannual_data
|
||
ToolRegistry["get_semiannual_data"] = Tool{
|
||
Name: "get_semiannual_data",
|
||
Description: "获取指定半年的季度总结素材",
|
||
InputSchema: map[string]interface{}{
|
||
"type": "object",
|
||
"properties": map[string]interface{}{
|
||
"halfOffset": map[string]interface{}{"type": "integer", "default": 0},
|
||
},
|
||
},
|
||
Handler: func(args map[string]interface{}) (string, error) {
|
||
offset := 0
|
||
if val, ok := args["halfOffset"]; ok {
|
||
switch t := val.(type) {
|
||
case float64:
|
||
offset = int(t)
|
||
case int:
|
||
offset = t
|
||
case string:
|
||
if n, err := strconv.Atoi(t); err == nil {
|
||
offset = n
|
||
}
|
||
}
|
||
}
|
||
return s.GetSemiannualData(offset)
|
||
},
|
||
}
|
||
|
||
// 10) record_semiannual_summary
|
||
ToolRegistry["record_semiannual_summary"] = Tool{
|
||
Name: "record_semiannual_summary",
|
||
Description: "写入半年总结 Semiannual_Summary.md",
|
||
InputSchema: map[string]interface{}{
|
||
"type": "object",
|
||
"properties": map[string]interface{}{
|
||
"content": map[string]interface{}{"type": "string"},
|
||
"halfOffset": map[string]interface{}{"type": "integer", "default": 0},
|
||
},
|
||
"required": []string{"content"},
|
||
},
|
||
Handler: func(args map[string]interface{}) (string, error) {
|
||
content, _ := args["content"].(string)
|
||
offset := 0
|
||
if val, ok := args["halfOffset"]; ok {
|
||
switch t := val.(type) {
|
||
case float64:
|
||
offset = int(t)
|
||
case int:
|
||
offset = t
|
||
case string:
|
||
if n, err := strconv.Atoi(t); err == nil {
|
||
offset = n
|
||
}
|
||
}
|
||
}
|
||
return s.RecordSemiannualSummary(content, offset)
|
||
},
|
||
}
|
||
|
||
// 11) get_year_data
|
||
ToolRegistry["get_year_data"] = Tool{
|
||
Name: "get_year_data",
|
||
Description: "获取指定年度的半年总结素材",
|
||
InputSchema: map[string]interface{}{
|
||
"type": "object",
|
||
"properties": map[string]interface{}{
|
||
"yearOffset": map[string]interface{}{"type": "integer", "default": 0},
|
||
},
|
||
},
|
||
Handler: func(args map[string]interface{}) (string, error) {
|
||
offset := 0
|
||
if val, ok := args["yearOffset"]; ok {
|
||
switch t := val.(type) {
|
||
case float64:
|
||
offset = int(t)
|
||
case int:
|
||
offset = t
|
||
case string:
|
||
if n, err := strconv.Atoi(t); err == nil {
|
||
offset = n
|
||
}
|
||
}
|
||
}
|
||
return s.GetYearData(offset)
|
||
},
|
||
}
|
||
|
||
// 12) record_year_summary
|
||
ToolRegistry["record_year_summary"] = Tool{
|
||
Name: "record_year_summary",
|
||
Description: "写入年度总结 Year_Summary.md",
|
||
InputSchema: map[string]interface{}{
|
||
"type": "object",
|
||
"properties": map[string]interface{}{
|
||
"content": map[string]interface{}{"type": "string"},
|
||
"yearOffset": map[string]interface{}{"type": "integer", "default": 0},
|
||
},
|
||
"required": []string{"content"},
|
||
},
|
||
Handler: func(args map[string]interface{}) (string, error) {
|
||
content, _ := args["content"].(string)
|
||
offset := 0
|
||
if val, ok := args["yearOffset"]; ok {
|
||
switch t := val.(type) {
|
||
case float64:
|
||
offset = int(t)
|
||
case int:
|
||
offset = t
|
||
case string:
|
||
if n, err := strconv.Atoi(t); err == nil {
|
||
offset = n
|
||
}
|
||
}
|
||
}
|
||
return s.RecordYearSummary(content, offset)
|
||
},
|
||
}
|
||
|
||
// 13) housekeep_memory
|
||
ToolRegistry["housekeep_memory"] = Tool{
|
||
Name: "housekeep_memory",
|
||
Description: "归档指定月份的原始记录(需月总结完成)",
|
||
InputSchema: map[string]interface{}{
|
||
"type": "object",
|
||
"properties": map[string]interface{}{
|
||
"target_month": map[string]interface{}{"type": "string", "description": "YYYY-MM"},
|
||
},
|
||
"required": []string{"target_month"},
|
||
},
|
||
Handler: func(args map[string]interface{}) (string, error) {
|
||
target, _ := args["target_month"].(string)
|
||
return s.HousekeepMemory(target)
|
||
},
|
||
}
|
||
|
||
// 14) inspect_and_propose
|
||
ToolRegistry["inspect_and_propose"] = Tool{
|
||
Name: "inspect_and_propose",
|
||
Description: "检视 tao_mcp_go 与灵感库,生成补丁建议清单(不自动应用)",
|
||
InputSchema: map[string]interface{}{
|
||
"type": "object",
|
||
"properties": map[string]interface{}{
|
||
"repo_path": map[string]interface{}{"type": "string", "description": "仓库路径(可选,默认 tao_mcp_go)"},
|
||
},
|
||
},
|
||
Handler: func(args map[string]interface{}) (string, error) {
|
||
repo, _ := args["repo_path"].(string)
|
||
return s.InspectAndPropose(repo)
|
||
},
|
||
}
|
||
|
||
// 15) record_daily
|
||
ToolRegistry["record_daily"] = Tool{
|
||
Name: "record_daily",
|
||
Description: "写入当日记忆流(日记/对话碎片)",
|
||
InputSchema: map[string]interface{}{
|
||
"type": "object",
|
||
"properties": map[string]interface{}{
|
||
"content": map[string]interface{}{"type": "string"},
|
||
"karma": map[string]interface{}{"type": "integer", "default": 1},
|
||
},
|
||
"required": []string{"content"},
|
||
},
|
||
Handler: func(args map[string]interface{}) (string, error) {
|
||
content, _ := args["content"].(string)
|
||
karma := 1
|
||
if v, ok := args["karma"]; ok {
|
||
switch t := v.(type) {
|
||
case float64:
|
||
karma = int(t)
|
||
case int:
|
||
karma = t
|
||
case string:
|
||
if n, err := strconv.Atoi(t); err == nil {
|
||
karma = n
|
||
}
|
||
}
|
||
}
|
||
return s.RecordDaily(content, karma)
|
||
},
|
||
}
|
||
}
|
||
|
||
func buildToolList() []map[string]interface{} {
|
||
var toolList []map[string]interface{}
|
||
for _, t := range ToolRegistry {
|
||
toolList = append(toolList, map[string]interface{}{
|
||
"name": t.Name,
|
||
"description": t.Description,
|
||
"inputSchema": t.InputSchema,
|
||
})
|
||
}
|
||
sort.Slice(toolList, func(i, j int) bool {
|
||
return toolList[i]["name"].(string) < toolList[j]["name"].(string)
|
||
})
|
||
return toolList
|
||
}
|
||
|
||
func stringsJoin(items []string, sep string) string {
|
||
if len(items) == 0 {
|
||
return ""
|
||
}
|
||
out := items[0]
|
||
for i := 1; i < len(items); i++ {
|
||
out = out + sep + items[i]
|
||
}
|
||
return out
|
||
}
|