mcp_tool.goā¢4.53 kB
package client
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"github.com/mcpjungle/mcpjungle/pkg/types"
)
// ListTools fetches the list of tools, optionally filtered by server name.
// If server is an empty string, this method fetches all tools.
func (c *Client) ListTools(server string) ([]*types.Tool, error) {
u, _ := c.constructAPIEndpoint("/tools")
req, _ := c.newRequest(http.MethodGet, u, nil)
if server != "" {
q := req.URL.Query()
q.Add("server", server)
req.URL.RawQuery = q.Encode()
}
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to send request to %s: %w", req.URL.String(), err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, c.parseErrorResponse(resp)
}
var tools []*types.Tool
if err := json.NewDecoder(resp.Body).Decode(&tools); err != nil {
return nil, fmt.Errorf("failed to decode response: %w", err)
}
return tools, nil
}
// EnableTools enables a tool or all tools provided by an MCP server.
func (c *Client) EnableTools(name string) ([]string, error) {
u, _ := c.constructAPIEndpoint("/tools/enable")
req, err := c.newRequest(http.MethodPost, u, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
q := req.URL.Query()
q.Add("entity", name)
req.URL.RawQuery = q.Encode()
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to send request to %s: %w", req.URL.String(), err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, c.parseErrorResponse(resp)
}
var tools []string
if err := json.NewDecoder(resp.Body).Decode(&tools); err != nil {
return nil, fmt.Errorf("failed to decode API response: %w", err)
}
return tools, nil
}
// DisableTools disables a tool or all tools provided by an MCP server.
func (c *Client) DisableTools(name string) ([]string, error) {
u, _ := c.constructAPIEndpoint("/tools/disable")
req, err := c.newRequest(http.MethodPost, u, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
q := req.URL.Query()
q.Add("entity", name)
req.URL.RawQuery = q.Encode()
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to send request to %s: %w", req.URL.String(), err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, c.parseErrorResponse(resp)
}
var tools []string
if err := json.NewDecoder(resp.Body).Decode(&tools); err != nil {
return nil, fmt.Errorf("failed to decode API response: %w", err)
}
return tools, nil
}
// GetTool fetches a specific tool by its name.
func (c *Client) GetTool(name string) (*types.Tool, error) {
u, _ := c.constructAPIEndpoint("/tool")
req, _ := c.newRequest(http.MethodGet, u, nil)
q := req.URL.Query()
q.Add("name", name)
req.URL.RawQuery = q.Encode()
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to send request to %s: %w", req.URL.String(), err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, c.parseErrorResponse(resp)
}
var tool types.Tool
if err := json.NewDecoder(resp.Body).Decode(&tool); err != nil {
return nil, fmt.Errorf("failed to decode response: %w", err)
}
return &tool, nil
}
// InvokeTool sends a JSON payload to invoke a tool.
// For now, this function only supports invoking tools that return a string response.
func (c *Client) InvokeTool(name string, input map[string]any) (*types.ToolInvokeResult, error) {
// We need to insert the tool name into the POST payload
// In order not to mutate the user-supplied input, create a shallow copy of the input
// and add the name field to it.
payload := make(map[string]any, len(input)+1)
for k, v := range input {
payload[k] = v
}
payload["name"] = name
body, _ := json.Marshal(payload)
u, _ := c.constructAPIEndpoint("/tools/invoke")
req, err := c.newRequest(http.MethodPost, u, bytes.NewReader(body))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("request to server failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, c.parseErrorResponse(resp)
}
var result *types.ToolInvokeResult
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, fmt.Errorf("failed to decode response: %w", err)
}
return result, nil
}