// Package mcp provides a native MCP (Model Context Protocol) server for PinchTab. package mcp import ( "bytes" "context" "encoding/json" "fmt" "io" "net/http" "net/url" "strings" "time" ) // Client is an HTTP client for PinchTab's REST API. type Client struct { BaseURL string Token string HTTPClient *http.Client } // NewClient creates a Client for the given PinchTab base URL. func NewClient(baseURL, token string) *Client { return &Client{ BaseURL: baseURL, Token: token, HTTPClient: &http.Client{ Timeout: 120 * time.Second, }, } } func (c *Client) url(path string) string { return c.BaseURL + path } func (c *Client) profileInstancePath(profile string) string { return "/profiles/" + url.PathEscape(profile) + "/instance" } func (c *Client) dashboardProfilesURL() string { return strings.TrimRight(c.BaseURL, "/") + "/dashboard/profiles" } func (c *Client) do(req *http.Request) ([]byte, int, error) { if c.Token != "" { req.Header.Set("Authorization", "Bearer "+c.Token) } resp, err := c.HTTPClient.Do(req) if err != nil { return nil, 0, fmt.Errorf("request %s %s: %w", req.Method, req.URL.Path, err) } defer func() { _ = resp.Body.Close() }() body, err := io.ReadAll(io.LimitReader(resp.Body, 10<<20)) // 10 MB limit if err != nil { return nil, resp.StatusCode, fmt.Errorf("read response: %w", err) } return body, resp.StatusCode, nil } // Get performs a GET request and returns the response body. func (c *Client) Get(ctx context.Context, path string, query url.Values) ([]byte, int, error) { u := c.url(path) if len(query) > 0 { u += "?" + query.Encode() } req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) if err != nil { return nil, 0, err } return c.do(req) } // Post performs a POST request with a JSON body. func (c *Client) Post(ctx context.Context, path string, payload any) ([]byte, int, error) { var body io.Reader if payload != nil { b, err := json.Marshal(payload) if err != nil { return nil, 0, fmt.Errorf("marshal payload: %w", err) } body = bytes.NewReader(b) } req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.url(path), body) if err != nil { return nil, 0, err } if payload != nil { req.Header.Set("Content-Type", "application/json") } return c.do(req) }