Full Blog TOC

Full Blog Table Of Content with Keywords Available HERE

Sunday, April 12, 2026

MCP Client in GO and Stub


 


In the following post we present creation of MCP Client in GO including API, implementation, and stub. This method of providing APIs is critical for a successful testing which should not access any external entity. Note that in this case, we also provide a factory API, implementation, and stub further enabling the code to create MCP client even when it is running in the tests scope.


MCP Client

The client API:

type McpToolInfo struct {
ToolName string
ToolDescription string
InputSchema string
OutputSchema string
}

type McpClientApi interface {
ListTools() []*McpToolInfo
CloseSession()
}

The implementation:

// static - to use connection pool for all servers
var staticWebClient = web.ProduceClientImpl(core.Config.McpConnectionTimeout)

type McpClientImpl struct {
session *mcp.ClientSession
context context.Context
}

func ProduceMcpClientImpl(
mcpServerUrl string,
) *McpClientImpl {
m := &McpClientImpl{
context: context.Background(),
}

client := mcp.NewClient(
&mcp.Implementation{
Name: "my-go-client",
Version: "1.0.0",
},
nil,
)

transport := &mcp.StreamableClientTransport{
Endpoint: mcpServerUrl,
HTTPClient: staticWebClient.UsedClient(),
}

session, err := client.Connect(m.context, transport, nil)
kiterr.RaiseIfError(err)

m.session = session
return m
}

func (m *McpClientImpl) ListTools() []*McpToolInfo {
parameters := mcp.ListToolsParams{}
tools, err := m.session.ListTools(m.context, &parameters)
kiterr.RaiseIfError(err)

var result []*McpToolInfo
for _, tool := range tools.Tools {
info := McpToolInfo{
ToolName: tool.Name,
ToolDescription: tool.Description,
InputSchema: fmt.Sprintf("%v", tool.InputSchema),
OutputSchema: fmt.Sprintf("%v", tool.OutputSchema),
}
result = append(result, &info)
}

return result
}

func (m *McpClientImpl) CloseSession() {
err := m.session.Close()
m.session = nil
kiterr.RaiseIfError(err)
}

And the stub:

type McpClientStub struct {
}

func ProduceMcpClientStub(
mcpServerUrl string,
) *McpClientStub {
return &McpClientStub{}
}

func (m *McpClientStub) ListTools() []*McpToolInfo {
return []*McpToolInfo{
{
ToolName: "tool-1",
ToolDescription: "the best tool",
InputSchema: "my-schema-input",
OutputSchema: "my-schema-output",
},
}
}

func (m *McpClientStub) CloseSession() {
}

MCP Client Factory

The factory API:

import "radware.com/mcpp/commons/mcp/client"

type McpClientFactoryApi interface {
ProduceMcpClient(
mcpServerUrl string,
) client.McpClientApi
}

The factory implementation:

type McpClientFactoryImpl struct {
}

func ProduceMcpClientFactoryImpl() *McpClientFactoryImpl {
return &McpClientFactoryImpl{}
}

func (f *McpClientFactoryImpl) ProduceMcpClient(
mcpServerUrl string,
) client.McpClientApi {
return client.ProduceMcpClientImpl(mcpServerUrl)
}

And the stub:

type McpClientFactoryStub struct {
}

func ProduceMcpClientFactoryStub() *McpClientFactoryStub {
return &McpClientFactoryStub{}
}

func (f *McpClientFactoryStub) ProduceMcpClient(
mcpServerUrl string,
) client.McpClientApi {
return client.ProduceMcpClientStub(mcpServerUrl)
}