What it is
MCP (Model Context Protocol) is a standard way for an LLM application to discover and call tools exposed by an external server. In practice, it lets you treat remote capabilities (APIs, databases, CLIs, internal services) as tools that your agent can call.
Phero’s mcp package adapts an MCP client session into Phero’s llm.Tool values, so the
agent loop can call MCP tools the same way it calls in-process tools.
How it’s used
In practice, you connect to an MCP server, list its tools, convert them to agent tools, and then run the agent. The examples/mcp example shows the full flow.
// From examples/mcp (edited for brevity)
ctx := context.Background()
client := gomcp.NewClient(&gomcp.Implementation{Name: "myclient", Version: "1.0.0"}, nil)
// Launch MCP server as a subprocess and connect over stdio
command := "./examples/mcp/server/server"
cmd := exec.CommandContext(ctx, command)
transport := &gomcp.CommandTransport{Command: cmd}
session, err := client.Connect(ctx, transport, nil)
if err != nil {
panic(err)
}
defer session.Close()
mcpServer := mcp.New(session)
tools, err := mcpServer.AsTools(ctx, nil)
if err != nil {
panic(err)
}
llmClient := /* any llm.LLM */
a, _ := agent.New(llmClient, "MCP Agent", "An agent that uses tools from an MCP server.")
for _, tool := range tools {
_ = a.AddTool(tool)
}
res, _ := a.Run(ctx, "Give me a random quote.")
fmt.Println(res)
Example: run an MCP server over stdio
The repo includes an end-to-end example under
examples/mcp.
The server exposes a single tool: get_random_quote.
1) Build the server
# from repo root
make -C ./examples/mcp/server build
# binary created at:
# ./examples/mcp/server/server
2) Run the client
# IMPORTANT: run from the repo root (client uses a relative path)
go run ./examples/mcp
Client side (connect + expose tools to an agent)
ctx := context.Background()
client := gomcp.NewClient(&gomcp.Implementation{Name: "myclient", Version: "1.0.0"}, nil)
// Launch MCP server as a subprocess and connect over stdio
command := "./examples/mcp/server/server"
cmd := exec.CommandContext(ctx, command)
transport := &gomcp.CommandTransport{Command: cmd}
session, err := client.Connect(ctx, transport, nil)
if err != nil {
panic(err)
}
defer session.Close()
mcpServer := mcp.New(session)
tools, err := mcpServer.AsTools(ctx, nil)
if err != nil {
panic(err)
}
a, _ := agent.New(llmClient, "MCP Agent", "An agent that uses tools from an MCP server.")
for _, tool := range tools {
_ = a.AddTool(tool)
}
res, _ := a.Run(ctx, "Give me a random quote.")
fmt.Println(res)
Server side (define and run a tool)
server := mcp.NewServer(&mcp.Implementation{Name: "random_quote", Version: "v1.0.0"}, nil)
mcp.AddTool(
server,
&mcp.Tool{Name: "get_random_quote", Description: "Fetches a random inspirational quote"},
getRandomQuoteHandler,
)
// Run over stdin/stdout until client disconnects
_ = server.Run(context.Background(), &mcp.StdioTransport{})
Filtering tools
If your MCP server exposes many tools, you can selectively expose them to an agent by passing a filter:
tools, err := mcpServer.AsTools(ctx, func(name string) bool {
// allowlist only a subset
return name == "get_random_quote" || strings.HasPrefix(name, "search_")
})
Notes & troubleshooting
- The example server calls
https://zenquotes.io/api/random(needs outbound HTTP). - Run the MCP client from the repo root, or update the server command path.
- Bring your own
llm.LLMbackend (see llm).