Skip to content

Feature/pagination functionality #107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package client

import (
"context"
"encoding/json"
"fmt"

"github.com/mark3labs/mcp-go/mcp"
)
Expand All @@ -18,12 +20,25 @@ type MCPClient interface {
// Ping checks if the server is alive
Ping(ctx context.Context) error

// ListResourcesByPage manually list resources by page.
ListResourcesByPage(
ctx context.Context,
request mcp.ListResourcesRequest,
) (*mcp.ListResourcesResult, error)

// ListResources requests a list of available resources from the server
ListResources(
ctx context.Context,
request mcp.ListResourcesRequest,
) (*mcp.ListResourcesResult, error)

// ListResourceTemplatesByPage manually list resource templates by page.
ListResourceTemplatesByPage(
ctx context.Context,
request mcp.ListResourceTemplatesRequest,
) (*mcp.ListResourceTemplatesResult,
error)

// ListResourceTemplates requests a list of available resource templates from the server
ListResourceTemplates(
ctx context.Context,
Expand All @@ -43,6 +58,12 @@ type MCPClient interface {
// Unsubscribe cancels notifications for a specific resource
Unsubscribe(ctx context.Context, request mcp.UnsubscribeRequest) error

// ListPromptsByPage manually list prompts by page.
ListPromptsByPage(
ctx context.Context,
request mcp.ListPromptsRequest,
) (*mcp.ListPromptsResult, error)

// ListPrompts requests a list of available prompts from the server
ListPrompts(
ctx context.Context,
Expand All @@ -55,6 +76,12 @@ type MCPClient interface {
request mcp.GetPromptRequest,
) (*mcp.GetPromptResult, error)

// ListToolsByPage manually list tools by page.
ListToolsByPage(
ctx context.Context,
request mcp.ListToolsRequest,
) (*mcp.ListToolsResult, error)

// ListTools requests a list of available tools from the server
ListTools(
ctx context.Context,
Expand All @@ -81,4 +108,23 @@ type MCPClient interface {

// OnNotification registers a handler for notifications
OnNotification(handler func(notification mcp.JSONRPCNotification))

sendRequest(ctx context.Context, method string, params interface{}) (*json.RawMessage, error)
}

func listByPage[T any](
ctx context.Context,
client MCPClient,
request mcp.PaginatedRequest,
method string,
) (*T, error) {
response, err := client.sendRequest(ctx, method, request.Params)
if err != nil {
return nil, err
}
var result T
if err := json.Unmarshal(*response, &result); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &result, nil
}
135 changes: 104 additions & 31 deletions client/sse.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,42 +410,77 @@ func (c *SSEMCPClient) Ping(ctx context.Context) error {
return err
}

func (c *SSEMCPClient) ListResources(
// ListResourcesByPage manually list resources by page.
func (c *SSEMCPClient) ListResourcesByPage(
ctx context.Context,
request mcp.ListResourcesRequest,
) (*mcp.ListResourcesResult, error) {
response, err := c.sendRequest(ctx, "resources/list", request.Params)
result, err := listByPage[mcp.ListResourcesResult](ctx, c, request.PaginatedRequest, "resources/list")
if err != nil {
return nil, err
}
return result, nil
}

var result mcp.ListResourcesResult
if err := json.Unmarshal(*response, &result); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
func (c *SSEMCPClient) ListResources(
ctx context.Context,
request mcp.ListResourcesRequest,
) (*mcp.ListResourcesResult, error) {
result, err := c.ListResourcesByPage(ctx, request)
if err != nil {
return nil, err
}
for result.NextCursor != "" {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
request.Params.Cursor = result.NextCursor
newPageRes, err := c.ListResourcesByPage(ctx, request)
if err != nil {
return nil, err
}
result.Resources = append(result.Resources, newPageRes.Resources...)
result.NextCursor = newPageRes.NextCursor
}
}
return result, nil
}

return &result, nil
func (c *SSEMCPClient) ListResourceTemplatesByPage(
ctx context.Context,
request mcp.ListResourceTemplatesRequest,
) (*mcp.ListResourceTemplatesResult, error) {
result, err := listByPage[mcp.ListResourceTemplatesResult](ctx, c, request.PaginatedRequest, "resources/templates/list")
if err != nil {
return nil, err
}
return result, nil
}

func (c *SSEMCPClient) ListResourceTemplates(
ctx context.Context,
request mcp.ListResourceTemplatesRequest,
) (*mcp.ListResourceTemplatesResult, error) {
response, err := c.sendRequest(
ctx,
"resources/templates/list",
request.Params,
)
result, err := c.ListResourceTemplatesByPage(ctx, request)
if err != nil {
return nil, err
}

var result mcp.ListResourceTemplatesResult
if err := json.Unmarshal(*response, &result); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
for result.NextCursor != "" {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
request.Params.Cursor = result.NextCursor
newPageRes, err := c.ListResourceTemplatesByPage(ctx, request)
if err != nil {
return nil, err
}
result.ResourceTemplates = append(result.ResourceTemplates, newPageRes.ResourceTemplates...)
result.NextCursor = newPageRes.NextCursor
}
}

return &result, nil
return result, nil
}

func (c *SSEMCPClient) ReadResource(
Expand Down Expand Up @@ -476,21 +511,40 @@ func (c *SSEMCPClient) Unsubscribe(
return err
}

func (c *SSEMCPClient) ListPrompts(
func (c *SSEMCPClient) ListPromptsByPage(
ctx context.Context,
request mcp.ListPromptsRequest,
) (*mcp.ListPromptsResult, error) {
response, err := c.sendRequest(ctx, "prompts/list", request.Params)
result, err := listByPage[mcp.ListPromptsResult](ctx, c, request.PaginatedRequest, "prompts/list")
if err != nil {
return nil, err
}
return result, nil
}

var result mcp.ListPromptsResult
if err := json.Unmarshal(*response, &result); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
func (c *SSEMCPClient) ListPrompts(
ctx context.Context,
request mcp.ListPromptsRequest,
) (*mcp.ListPromptsResult, error) {
result, err := c.ListPromptsByPage(ctx, request)
if err != nil {
return nil, err
}

return &result, nil
for result.NextCursor != "" {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
request.Params.Cursor = result.NextCursor
newPageRes, err := c.ListPromptsByPage(ctx, request)
if err != nil {
return nil, err
}
result.Prompts = append(result.Prompts, newPageRes.Prompts...)
result.NextCursor = newPageRes.NextCursor
}
}
return result, nil
}

func (c *SSEMCPClient) GetPrompt(
Expand All @@ -505,21 +559,40 @@ func (c *SSEMCPClient) GetPrompt(
return mcp.ParseGetPromptResult(response)
}

func (c *SSEMCPClient) ListTools(
func (c *SSEMCPClient) ListToolsByPage(
ctx context.Context,
request mcp.ListToolsRequest,
) (*mcp.ListToolsResult, error) {
response, err := c.sendRequest(ctx, "tools/list", request.Params)
result, err := listByPage[mcp.ListToolsResult](ctx, c, request.PaginatedRequest, "tools/list")
if err != nil {
return nil, err
}
return result, nil
}

var result mcp.ListToolsResult
if err := json.Unmarshal(*response, &result); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
func (c *SSEMCPClient) ListTools(
ctx context.Context,
request mcp.ListToolsRequest,
) (*mcp.ListToolsResult, error) {
result, err := c.ListToolsByPage(ctx, request)
if err != nil {
return nil, err
}

return &result, nil
for result.NextCursor != "" {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
request.Params.Cursor = result.NextCursor
newPageRes, err := c.ListToolsByPage(ctx, request)
if err != nil {
return nil, err
}
result.Tools = append(result.Tools, newPageRes.Tools...)
result.NextCursor = newPageRes.NextCursor
}
}
return result, nil
}

func (c *SSEMCPClient) CallTool(
Expand Down
Loading