1package tools
2
3import (
4 "context"
5 _ "embed"
6 "log/slog"
7 "strings"
8
9 "charm.land/fantasy"
10 "github.com/charmbracelet/crush/internal/agent/tools/mcp"
11)
12
13type ReadMCPResourceParams struct {
14 Name string `json:"name" description:"MCP name"`
15 URI string `json:"uri,omitempty" description:"Resource URI"`
16}
17
18type ListMCPResourceParams struct {
19 Name string `json:"name" description:"MCP name"`
20}
21
22const (
23 ReadMCPResourceToolName = "read_mcp_resource"
24 ListMCPResourceToolName = "list_mcp_resources"
25)
26
27//go:embed read_mcp_resource.md
28var readMCPResourceDescription []byte
29
30//go:embed list_mcp_resource.md
31var listMCPResourceDescription []byte
32
33func NewReadMCPResourceTool() fantasy.AgentTool {
34 return fantasy.NewAgentTool(
35 ReadMCPResourceToolName,
36 string(readMCPResourceDescription),
37 func(ctx context.Context, input ReadMCPResourceParams, call fantasy.ToolCall) (fantasy.ToolResponse, error) {
38 resource, err := mcp.ReadResource(ctx, input.Name, input.URI)
39 if err != nil {
40 return fantasy.NewTextErrorResponse(err.Error()), nil
41 }
42 var sb strings.Builder
43 for _, part := range resource {
44 if !strings.HasPrefix(part.MIMEType, "text/") {
45 slog.Warn("ignoring resource of type", "type", part.MIMEType)
46 continue
47 }
48 sb.WriteString(part.Text)
49 }
50 return fantasy.NewTextResponse(sb.String()), nil
51 },
52 )
53}
54
55func NewListMCPResourceTool() fantasy.AgentTool {
56 return fantasy.NewAgentTool(
57 ListMCPResourceToolName,
58 string(listMCPResourceDescription),
59 func(ctx context.Context, input ListMCPResourceParams, call fantasy.ToolCall) (fantasy.ToolResponse, error) {
60 for name, resources := range mcp.Resources() {
61 if name != input.Name {
62 continue
63 }
64 var sb strings.Builder
65 sb.WriteString("Resources available for " + input.Name + ":\n\n")
66 for _, res := range resources {
67 sb.WriteString("- " + res.URI + "\n")
68 }
69 return fantasy.NewTextResponse(sb.String()), nil
70 }
71 return fantasy.NewTextResponse("No resources found for " + input.Name), nil
72 },
73 )
74}