78 lines
1.6 KiB
Go
78 lines
1.6 KiB
Go
package mcpserver
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
requestTimeout = 60 * time.Second
|
|
maxResponseSize = 8 << 20
|
|
)
|
|
|
|
type Client struct {
|
|
baseURL string
|
|
apiKey string
|
|
http *http.Client
|
|
}
|
|
|
|
type Response struct {
|
|
Status int
|
|
Body string
|
|
}
|
|
|
|
func NewClient(baseURL string, apiKey string, httpClient *http.Client) *Client {
|
|
if httpClient == nil {
|
|
httpClient = &http.Client{Timeout: requestTimeout}
|
|
}
|
|
return &Client{baseURL: strings.TrimRight(baseURL, "/"), apiKey: apiKey, http: httpClient}
|
|
}
|
|
|
|
func (c *Client) Do(ctx context.Context, method string, path string, query url.Values, body []byte, contentType string) (Response, error) {
|
|
target := c.baseURL + path
|
|
if len(query) > 0 {
|
|
target += "?" + query.Encode()
|
|
}
|
|
req, err := http.NewRequestWithContext(ctx, method, target, bytes.NewReader(body))
|
|
if err != nil {
|
|
return Response{}, err
|
|
}
|
|
if c.apiKey != "" {
|
|
req.Header.Set("Authorization", "Bearer "+c.apiKey)
|
|
}
|
|
if contentType != "" {
|
|
req.Header.Set("Content-Type", contentType)
|
|
}
|
|
res, err := c.http.Do(req)
|
|
if err != nil {
|
|
return Response{}, err
|
|
}
|
|
defer res.Body.Close()
|
|
raw, err := io.ReadAll(io.LimitReader(res.Body, maxResponseSize))
|
|
if err != nil {
|
|
return Response{}, err
|
|
}
|
|
return Response{Status: res.StatusCode, Body: string(raw)}, nil
|
|
}
|
|
|
|
func (r Response) Failed() bool {
|
|
return r.Status < 200 || r.Status > 299
|
|
}
|
|
|
|
func (r Response) Describe() string {
|
|
text := strings.TrimSpace(r.Body)
|
|
if r.Status == http.StatusNoContent || text == "" {
|
|
return fmt.Sprintf("HTTP %d", r.Status)
|
|
}
|
|
if r.Failed() {
|
|
return fmt.Sprintf("HTTP %d: %s", r.Status, text)
|
|
}
|
|
return text
|
|
}
|