summaryrefslogtreecommitdiffhomepage
path: root/internal/llm/agent/mcp-tools.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/llm/agent/mcp-tools.go')
-rw-r--r--internal/llm/agent/mcp-tools.go198
1 files changed, 0 insertions, 198 deletions
diff --git a/internal/llm/agent/mcp-tools.go b/internal/llm/agent/mcp-tools.go
deleted file mode 100644
index 601fdf705..000000000
--- a/internal/llm/agent/mcp-tools.go
+++ /dev/null
@@ -1,198 +0,0 @@
-package agent
-
-import (
- "context"
- "encoding/json"
- "fmt"
-
- "github.com/sst/opencode/internal/config"
- "github.com/sst/opencode/internal/llm/tools"
- "github.com/sst/opencode/internal/permission"
- "github.com/sst/opencode/internal/version"
- "log/slog"
-
- "github.com/mark3labs/mcp-go/client"
- "github.com/mark3labs/mcp-go/mcp"
-)
-
-type mcpTool struct {
- mcpName string
- tool mcp.Tool
- mcpConfig config.MCPServer
- permissions permission.Service
-}
-
-type MCPClient interface {
- Initialize(
- ctx context.Context,
- request mcp.InitializeRequest,
- ) (*mcp.InitializeResult, error)
- ListTools(ctx context.Context, request mcp.ListToolsRequest) (*mcp.ListToolsResult, error)
- CallTool(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error)
- Close() error
-}
-
-func (b *mcpTool) Info() tools.ToolInfo {
- return tools.ToolInfo{
- Name: fmt.Sprintf("%s_%s", b.mcpName, b.tool.Name),
- Description: b.tool.Description,
- Parameters: b.tool.InputSchema.Properties,
- Required: b.tool.InputSchema.Required,
- }
-}
-
-func runTool(ctx context.Context, c MCPClient, toolName string, input string) (tools.ToolResponse, error) {
- defer c.Close()
- initRequest := mcp.InitializeRequest{}
- initRequest.Params.ProtocolVersion = mcp.LATEST_PROTOCOL_VERSION
- initRequest.Params.ClientInfo = mcp.Implementation{
- Name: "OpenCode",
- Version: version.Version,
- }
-
- _, err := c.Initialize(ctx, initRequest)
- if err != nil {
- return tools.NewTextErrorResponse(err.Error()), nil
- }
-
- toolRequest := mcp.CallToolRequest{}
- toolRequest.Params.Name = toolName
- var args map[string]any
- if err = json.Unmarshal([]byte(input), &args); err != nil {
- return tools.NewTextErrorResponse(fmt.Sprintf("error parsing parameters: %s", err)), nil
- }
- toolRequest.Params.Arguments = args
- result, err := c.CallTool(ctx, toolRequest)
- if err != nil {
- return tools.NewTextErrorResponse(err.Error()), nil
- }
-
- output := ""
- for _, v := range result.Content {
- if v, ok := v.(mcp.TextContent); ok {
- output = v.Text
- } else {
- output = fmt.Sprintf("%v", v)
- }
- }
-
- return tools.NewTextResponse(output), nil
-}
-
-func (b *mcpTool) Run(ctx context.Context, params tools.ToolCall) (tools.ToolResponse, error) {
- sessionID, messageID := tools.GetContextValues(ctx)
- if sessionID == "" || messageID == "" {
- return tools.ToolResponse{}, fmt.Errorf("session ID and message ID are required for creating a new file")
- }
- permissionDescription := fmt.Sprintf("execute %s with the following parameters: %s", b.Info().Name, params.Input)
- p := b.permissions.Request(
- ctx,
- permission.CreatePermissionRequest{
- SessionID: sessionID,
- Path: config.WorkingDirectory(),
- ToolName: b.Info().Name,
- Action: "execute",
- Description: permissionDescription,
- Params: params.Input,
- },
- )
- if !p {
- return tools.NewTextErrorResponse("permission denied"), nil
- }
-
- switch b.mcpConfig.Type {
- case config.MCPStdio:
- c, err := client.NewStdioMCPClient(
- b.mcpConfig.Command,
- b.mcpConfig.Env,
- b.mcpConfig.Args...,
- )
- if err != nil {
- return tools.NewTextErrorResponse(err.Error()), nil
- }
- return runTool(ctx, c, b.tool.Name, params.Input)
- case config.MCPSse:
- c, err := client.NewSSEMCPClient(
- b.mcpConfig.URL,
- client.WithHeaders(b.mcpConfig.Headers),
- )
- if err != nil {
- return tools.NewTextErrorResponse(err.Error()), nil
- }
- return runTool(ctx, c, b.tool.Name, params.Input)
- }
-
- return tools.NewTextErrorResponse("invalid mcp type"), nil
-}
-
-func NewMcpTool(name string, tool mcp.Tool, permissions permission.Service, mcpConfig config.MCPServer) tools.BaseTool {
- return &mcpTool{
- mcpName: name,
- tool: tool,
- mcpConfig: mcpConfig,
- permissions: permissions,
- }
-}
-
-var mcpTools []tools.BaseTool
-
-func getTools(ctx context.Context, name string, m config.MCPServer, permissions permission.Service, c MCPClient) []tools.BaseTool {
- var stdioTools []tools.BaseTool
- initRequest := mcp.InitializeRequest{}
- initRequest.Params.ProtocolVersion = mcp.LATEST_PROTOCOL_VERSION
- initRequest.Params.ClientInfo = mcp.Implementation{
- Name: "OpenCode",
- Version: version.Version,
- }
-
- _, err := c.Initialize(ctx, initRequest)
- if err != nil {
- slog.Error("error initializing mcp client", "error", err)
- return stdioTools
- }
- toolsRequest := mcp.ListToolsRequest{}
- tools, err := c.ListTools(ctx, toolsRequest)
- if err != nil {
- slog.Error("error listing tools", "error", err)
- return stdioTools
- }
- for _, t := range tools.Tools {
- stdioTools = append(stdioTools, NewMcpTool(name, t, permissions, m))
- }
- defer c.Close()
- return stdioTools
-}
-
-func GetMcpTools(ctx context.Context, permissions permission.Service) []tools.BaseTool {
- if len(mcpTools) > 0 {
- return mcpTools
- }
- for name, m := range config.Get().MCPServers {
- switch m.Type {
- case config.MCPStdio:
- c, err := client.NewStdioMCPClient(
- m.Command,
- m.Env,
- m.Args...,
- )
- if err != nil {
- slog.Error("error creating mcp client", "error", err)
- continue
- }
-
- mcpTools = append(mcpTools, getTools(ctx, name, m, permissions, c)...)
- case config.MCPSse:
- c, err := client.NewSSEMCPClient(
- m.URL,
- client.WithHeaders(m.Headers),
- )
- if err != nil {
- slog.Error("error creating mcp client", "error", err)
- continue
- }
- mcpTools = append(mcpTools, getTools(ctx, name, m, permissions, c)...)
- }
- }
-
- return mcpTools
-}