| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- package tools
- import (
- "context"
- "fmt"
- "charm.land/fantasy"
- "github.com/charmbracelet/crush/internal/agent/tools/mcp"
- "github.com/charmbracelet/crush/internal/permission"
- )
- // GetMCPTools gets all the currently available MCP tools.
- func GetMCPTools(permissions permission.Service, wd string) []*Tool {
- var result []*Tool
- for mcpName, tools := range mcp.Tools() {
- for _, tool := range tools {
- result = append(result, &Tool{
- mcpName: mcpName,
- tool: tool,
- permissions: permissions,
- workingDir: wd,
- })
- }
- }
- return result
- }
- // Tool is a tool from a MCP.
- type Tool struct {
- mcpName string
- tool *mcp.Tool
- permissions permission.Service
- workingDir string
- providerOptions fantasy.ProviderOptions
- }
- func (m *Tool) SetProviderOptions(opts fantasy.ProviderOptions) {
- m.providerOptions = opts
- }
- func (m *Tool) ProviderOptions() fantasy.ProviderOptions {
- return m.providerOptions
- }
- func (m *Tool) Name() string {
- return fmt.Sprintf("mcp_%s_%s", m.mcpName, m.tool.Name)
- }
- func (m *Tool) MCP() string {
- return m.mcpName
- }
- func (m *Tool) MCPToolName() string {
- return m.tool.Name
- }
- func (m *Tool) Info() fantasy.ToolInfo {
- parameters := make(map[string]any)
- required := make([]string, 0)
- if input, ok := m.tool.InputSchema.(map[string]any); ok {
- if props, ok := input["properties"].(map[string]any); ok {
- parameters = props
- }
- if req, ok := input["required"].([]any); ok {
- // Convert []any -> []string when elements are strings
- for _, v := range req {
- if s, ok := v.(string); ok {
- required = append(required, s)
- }
- }
- } else if reqStr, ok := input["required"].([]string); ok {
- // Handle case where it's already []string
- required = reqStr
- }
- }
- return fantasy.ToolInfo{
- Name: m.Name(),
- Description: m.tool.Description,
- Parameters: parameters,
- Required: required,
- }
- }
- func (m *Tool) Run(ctx context.Context, params fantasy.ToolCall) (fantasy.ToolResponse, error) {
- sessionID := GetSessionFromContext(ctx)
- if sessionID == "" {
- return fantasy.ToolResponse{}, fmt.Errorf("session ID is required for creating a new file")
- }
- permissionDescription := fmt.Sprintf("execute %s with the following parameters:", m.Info().Name)
- p := m.permissions.Request(
- permission.CreatePermissionRequest{
- SessionID: sessionID,
- ToolCallID: params.ID,
- Path: m.workingDir,
- ToolName: m.Info().Name,
- Action: "execute",
- Description: permissionDescription,
- Params: params.Input,
- },
- )
- if !p {
- return fantasy.ToolResponse{}, permission.ErrorPermissionDenied
- }
- content, err := mcp.RunTool(ctx, m.mcpName, m.tool.Name, params.Input)
- if err != nil {
- return fantasy.NewTextErrorResponse(err.Error()), nil
- }
- return fantasy.NewTextResponse(content), nil
- }
|