client

package
v0.0.20 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 9, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

README

client

MCP client implementation: HTTP transports, auth retry, reconnection, logging.

What belongs here

  • Client struct and options (NewClient, WithSSEClient, WithTransport, etc.)
  • HTTP transports: Streamable HTTP (streamableClientTransport), SSE (sseClientTransport)
  • Auth retry (DoWithAuthRetry) — 401 token refresh, 403 scope step-up
  • Reconnection (WithMaxRetries, WithReconnectBackoff)
  • Transport logging (WithClientLogging)
  • Server-to-client request handling (HandleServerRequest, WithSamplingHandler, WithElicitationHandler)
  • Notification callback (WithNotificationCallback)

Dependencies

  • core/ — protocol types (Request, Response, ToolDef, etc.)
  • Does NOT import server/

Usage

import (
    "github.com/panyam/mcpkit/client"
    "github.com/panyam/mcpkit/core"
)

c := client.NewClient("http://localhost:8787/mcp",
    core.ClientInfo{Name: "my-client", Version: "1.0"},
    client.WithSamplingHandler(mySamplingHandler),
)
c.Connect()
result, _ := c.ToolCall("greet", map[string]any{"name": "world"})

Extension support

c := client.NewClient(url, info,
    client.WithUIExtension(),  // advertise MCP Apps support
)
c.Connect()

if c.ServerSupportsUI() { /* server can serve app UIs */ }

modelTools, _ := c.ListToolsForModel() // excludes app-only tools
  • WithExtension(id, cap) — general extension advertisement
  • WithUIExtension() — convenience for MCP Apps
  • ServerSupportsExtension(id) / ServerSupportsUI() — detect server support
  • ListToolsForModel() — filters out tools with visibility ["app"] only

Transport interface

The client accepts any core.Transport via WithTransport(). This enables:

  • server.NewInProcessTransport for testing (no HTTP)
  • Custom transports for stdio, WebSocket, etc.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DoWithAuthRetry

func DoWithAuthRetry(
	ts core.TokenSource,
	buildReq func() (*http.Request, error),
	do func(*http.Request) (*http.Response, error),
) (*http.Response, error)

DoWithAuthRetry executes an HTTP request with automatic retry on 401/403. Wraps core.TokenSource into servicekit's callback-based auth retry.

On 401: calls ts.Token() to refresh, retries once. On 403: parses WWW-Authenticate for required scopes, calls core.ScopeAwareTokenSource.TokenForScopes if available, retries once.

func ExtractMethodFromJSON

func ExtractMethodFromJSON(data []byte) string

extractMethodFromJSON extracts the "method" field from a JSON-RPC envelope without full deserialization. Returns "<unknown>" if extraction fails.

func IsTransientError

func IsTransientError(err error) bool

isTransientError returns true if the error indicates a recoverable transport failure that may succeed on reconnection. Network errors (EOF, connection reset, refused) are transient. Auth errors (401/403) and JSON-RPC errors are NOT transient — the server responded, just said no.

func ResolveEndpointURL

func ResolveEndpointURL(baseSSEURL, endpointRef string) (string, error)

ResolveEndpointURL resolves an SSE endpoint event URL against the base SSE connection URL per RFC 3986. Delegates to servicekit's ResolveURL.

Types

type CallResult

type CallResult struct {
	Raw json.RawMessage
}

CallResult holds the raw JSON result from a JSON-RPC call.

func (*CallResult) JSON

func (r *CallResult) JSON() string

JSON returns the result as indented JSON.

func (*CallResult) Unmarshal

func (r *CallResult) Unmarshal(v any) error

Unmarshal decodes the result into the given value.

type Client

type Client struct {

	// ServerInfo is populated after Connect.
	ServerInfo core.ServerInfo
	// contains filtered or unexported fields
}

Client is an MCP client that communicates over Streamable HTTP or SSE.

func NewClient

func NewClient(url string, info core.ClientInfo, opts ...ClientOption) *Client

NewClient creates a new MCP client targeting the given server URL. By default uses Streamable HTTP. Use WithSSEClient() for SSE transport. Call Connect() to perform the protocol handshake.

func (*Client) Call

func (c *Client) Call(method string, params any) (*CallResult, error)

Call makes a JSON-RPC call and returns the parsed response.

func (*Client) Close

func (c *Client) Close() error

Close terminates the client session and transport.

func (*Client) Connect

func (c *Client) Connect() error

Connect establishes the transport and performs the MCP initialize handshake.

func (*Client) HandleServerRequest

func (c *Client) HandleServerRequest(req *core.Request) *core.Response

handleServerRequest dispatches an incoming server-to-client JSON-RPC request to the appropriate registered handler (sampling or elicitation). Returns a JSON-RPC response to send back to the server.

func (*Client) ListResourceTemplates

func (c *Client) ListResourceTemplates() ([]core.ResourceTemplate, error)

ListResourceTemplates returns all registered resource templates.

func (*Client) ListResources

func (c *Client) ListResources() ([]core.ResourceDef, error)

ListResources returns all registered static resources.

func (*Client) ListTools

func (c *Client) ListTools() ([]core.ToolDef, error)

ListTools returns all registered tool definitions.

func (*Client) ListToolsForModel

func (c *Client) ListToolsForModel() ([]core.ToolDef, error)

ListToolsForModel returns tools visible to the LLM, filtering out tools that are only visible to apps (visibility: ["app"]). Tools with no visibility set (nil/empty) are included — the default means visible to both model and app. This is a client-side convenience; the server always returns all tools.

func (*Client) ReadResource

func (c *Client) ReadResource(uri string) (string, error)

ReadResource reads a resource by URI and returns the first text content.

func (*Client) ServerSupportsExtension

func (c *Client) ServerSupportsExtension(id string) bool

ServerSupportsExtension checks whether the server advertised support for the given extension ID in its initialize response. Call after Connect().

func (*Client) ServerSupportsUI

func (c *Client) ServerSupportsUI() bool

ServerSupportsUI checks whether the server advertised MCP Apps (io.modelcontextprotocol/ui) support. Convenience wrapper around ServerSupportsExtension.

func (*Client) SessionID

func (c *Client) SessionID() string

SessionID returns the current session ID.

func (*Client) SetTransport

func (c *Client) SetTransport(t core.Transport)

SetTransport sets the transport for the client. Use when the transport needs to reference the client (e.g., InProcessTransport with ServerRequestHandler that delegates to the client's sampling/elicitation handlers). Must be called before Connect().

func (*Client) SetURL

func (c *Client) SetURL(url string)

SetURL updates the client's target URL. Used in reconnection tests to simulate DNS/load balancer changes.

func (*Client) SubscribeResource

func (c *Client) SubscribeResource(uri string) error

SubscribeResource subscribes to change notifications for a resource URI. The server will send notifications/resources/updated when the resource changes.

func (*Client) ToolCall

func (c *Client) ToolCall(name string, args any) (string, error)

ToolCall invokes a tool and returns the first text content.

func (*Client) URL

func (c *Client) URL() string

URL returns the client's target URL.

func (*Client) UnsubscribeResource

func (c *Client) UnsubscribeResource(uri string) error

UnsubscribeResource removes a subscription for a resource URI.

type ClientAuthError

type ClientAuthError = ssehttp.AuthRetryError

ClientAuthError is returned by the client transport when the server rejects a request with 401 or 403 and the transport has exhausted its retry budget.

type ClientOption

type ClientOption func(*Client)

ClientOption configures a Client.

func WithClientBearerToken

func WithClientBearerToken(token string) ClientOption

WithClientBearerToken sets a static bearer token for all client requests.

func WithClientLogging

func WithClientLogging(logger *log.Logger) ClientOption

WithClientLogging enables debug logging of all client transport operations. Every connect, call, notify, and close is logged with method name, latency, and error details. Pass nil to use the default logger.

Example:

client := mcpkit.NewClient(url, info,
    mcpkit.WithClientLogging(log.Default()),
)

func WithElicitationHandler

func WithElicitationHandler(h ElicitationHandler) ClientOption

WithElicitationHandler registers a handler for server-to-client elicitation requests. When set, the client advertises the "elicitation" capability during initialization.

func WithExtension

func WithExtension(id string, cap core.ClientExtensionCap) ClientOption

WithExtension advertises support for an extension during the initialize handshake. The extension ID and capability are included in the client's capabilities.extensions map, allowing the server to detect client support via core.ClientSupportsExtension(ctx, id) in tool handlers.

func WithGetSSEStream

func WithGetSSEStream() ClientOption

WithGetSSEStream enables a background GET SSE stream on the Streamable HTTP endpoint after Connect(). The stream receives server-initiated notifications (list-changed, log messages, resource updates) that arrive outside POST request-response cycles. Only applies to Streamable HTTP transport; ignored for SSE and in-memory transports.

The notification callback (set via WithNotificationCallback) must be goroutine-safe when WithGetSSEStream is enabled, as notifications may arrive concurrently from both the GET SSE stream and POST SSE responses.

func WithMaxRetries

func WithMaxRetries(n int) ClientOption

WithMaxRetries sets the maximum number of reconnection attempts on transient transport failure. Default 0 (reconnection disabled). Each retry includes a full reconnect + initialize handshake.

Example:

client := mcpkit.NewClient(url, info,
    mcpkit.WithMaxRetries(3),
    mcpkit.WithReconnectBackoff(time.Second),
)

func WithNotificationCallback

func WithNotificationCallback(fn func(method string, params any)) ClientOption

WithNotificationCallback sets a callback for server-to-client notifications (logging, progress, resource updates). Works across all transports.

func WithReconnectBackoff

func WithReconnectBackoff(d time.Duration) ClientOption

WithReconnectBackoff sets the base delay for exponential backoff between reconnection attempts. Default 1s. Actual delay is base * 2^attempt + jitter.

func WithSSEClient

func WithSSEClient() ClientOption

WithSSEClient configures the client to use SSE transport instead of Streamable HTTP. The URL should point to the SSE endpoint (e.g., "http://localhost:8787/mcp/sse").

func WithSamplingHandler

func WithSamplingHandler(h SamplingHandler) ClientOption

WithSamplingHandler registers a handler for server-to-client sampling requests. When set, the client advertises the "sampling" capability during initialization.

func WithStdioTransport

func WithStdioTransport(r io.Reader, w io.Writer) ClientOption

WithStdioTransport configures a Client to use stdio transport over the given reader/writer pair. Unlike WithTransport(NewStdioTransport(...)), this option wires the client's sampling/elicitation handlers and notification callback into the stdio transport automatically.

func WithTokenSource

func WithTokenSource(ts core.TokenSource) ClientOption

WithTokenSource sets a dynamic token source for all client requests. Use this for OAuth flows where tokens are refreshed automatically.

func WithTransport

func WithTransport(t core.Transport) ClientOption

WithTransport sets a core.Transport for the client, bypassing the default HTTP transport creation. Use with server.NewInProcessTransport for testing or embedded scenarios.

Example:

transport := server.NewInProcessTransport(srv)
c := client.New("memory://", info, client.WithTransport(transport))

func WithUIExtension

func WithUIExtension() ClientOption

WithUIExtension is a convenience wrapper that advertises MCP Apps (io.modelcontextprotocol/ui) support with the standard app MIME type.

type ElicitationHandler

type ElicitationHandler func(context.Context, core.ElicitationRequest) (core.ElicitationResult, error)

ElicitationHandler handles a server-to-client elicitation/create request. The client prompts the user for input and returns the result.

type HTTPStatusError

type HTTPStatusError = ssehttp.HTTPStatusError

HTTPStatusError is returned when the server responds with a non-2xx HTTP status code that is not 401/403 (those are handled by DoWithAuthRetry). This allows IsTransientError to classify 5xx responses as retriable.

type SamplingHandler

SamplingHandler handles a server-to-client sampling/createMessage request. The client performs LLM inference and returns the result.

type StdioTransport

type StdioTransport struct {
	// contains filtered or unexported fields
}

StdioTransport implements core.Transport over Content-Length framed JSON-RPC. Messages are read from r and written to w using the same framing as the MCP stdio server transport (Content-Length: N\r\n\r\n<body>).

func NewStdioTransport

func NewStdioTransport(r io.Reader, w io.Writer) *StdioTransport

NewStdioTransport creates a client transport that communicates via Content-Length framed JSON-RPC over the given reader/writer pair.

Typically the reader is connected to the server's stdout and the writer to the server's stdin (or pipe ends in tests).

Example:

cmd := exec.Command("my-mcp-server")
stdin, _ := cmd.StdinPipe()
stdout, _ := cmd.StdoutPipe()
cmd.Start()
transport := client.NewStdioTransport(stdout, stdin)
c := client.NewClient("stdio://", info, client.WithTransport(transport))

func (*StdioTransport) Call

func (t *StdioTransport) Call(ctx context.Context, req *core.Request) (*core.Response, error)

Call sends a JSON-RPC request and waits for the matching response.

func (*StdioTransport) Close

func (t *StdioTransport) Close() error

Close shuts down the transport and waits for the read loop to exit.

func (*StdioTransport) Connect

func (t *StdioTransport) Connect(ctx context.Context) error

Connect starts the background read loop.

func (*StdioTransport) Notify

func (t *StdioTransport) Notify(ctx context.Context, req *core.Request) error

Notify sends a JSON-RPC notification (no response expected).

func (*StdioTransport) SessionID

func (t *StdioTransport) SessionID() string

SessionID returns "stdio" for the stdio transport.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL