Files
amcs/internal/tools/describe.go
Hein d0bfdbfbab feat(mcp): add describe_tools and annotate_tool functionality
* Implement DescribeTool for listing available MCP tools with annotations.
* Add UpsertToolAnnotation and GetToolAnnotations methods for managing tool notes.
* Create tool_annotations table for storing tool usage notes.
2026-04-02 13:51:09 +02:00

90 lines
2.5 KiB
Go

package tools
import (
"context"
"strings"
"github.com/modelcontextprotocol/go-sdk/mcp"
"git.warky.dev/wdevs/amcs/internal/store"
)
// ToolEntry describes a single registered MCP tool.
type ToolEntry struct {
Name string
Description string
Category string
}
// DescribeTool implements the describe_tools and annotate_tool MCP tools.
type DescribeTool struct {
store *store.DB
catalog []ToolEntry
}
func NewDescribeTool(db *store.DB, catalog []ToolEntry) *DescribeTool {
return &DescribeTool{store: db, catalog: catalog}
}
// describe_tools
type DescribeToolsInput struct {
Category string `json:"category,omitempty" jsonschema:"filter results to a single category (e.g. thoughts, projects, files, skills, chat, meta)"`
}
type AnnotatedToolEntry struct {
Name string `json:"name"`
Description string `json:"description"`
Category string `json:"category"`
Notes string `json:"notes,omitempty"`
}
type DescribeToolsOutput struct {
Tools []AnnotatedToolEntry `json:"tools"`
}
func (t *DescribeTool) Describe(ctx context.Context, _ *mcp.CallToolRequest, in DescribeToolsInput) (*mcp.CallToolResult, DescribeToolsOutput, error) {
annotations, err := t.store.GetToolAnnotations(ctx)
if err != nil {
return nil, DescribeToolsOutput{}, err
}
cat := strings.TrimSpace(strings.ToLower(in.Category))
entries := make([]AnnotatedToolEntry, 0, len(t.catalog))
for _, e := range t.catalog {
if cat != "" && e.Category != cat {
continue
}
entries = append(entries, AnnotatedToolEntry{
Name: e.Name,
Description: e.Description,
Category: e.Category,
Notes: annotations[e.Name],
})
}
return nil, DescribeToolsOutput{Tools: entries}, nil
}
// annotate_tool
type AnnotateToolInput struct {
ToolName string `json:"tool_name" jsonschema:"the exact name of the tool to annotate"`
Notes string `json:"notes" jsonschema:"your usage notes, reminders, or gotchas for this tool; pass empty string to clear"`
}
type AnnotateToolOutput struct {
ToolName string `json:"tool_name"`
}
func (t *DescribeTool) Annotate(ctx context.Context, _ *mcp.CallToolRequest, in AnnotateToolInput) (*mcp.CallToolResult, AnnotateToolOutput, error) {
if strings.TrimSpace(in.ToolName) == "" {
return nil, AnnotateToolOutput{}, errRequiredField("tool_name")
}
if err := t.store.UpsertToolAnnotation(ctx, in.ToolName, in.Notes); err != nil {
return nil, AnnotateToolOutput{}, err
}
return nil, AnnotateToolOutput{ToolName: in.ToolName}, nil
}