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.
This commit is contained in:
89
internal/tools/describe.go
Normal file
89
internal/tools/describe.go
Normal file
@@ -0,0 +1,89 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user