micro--go-micro
3986738e2c
Implement Q2 2026 roadmap items for AI-native microservices: MCP stdio transport: - JSON-RPC 2.0 over stdio for Claude Code integration - Methods: initialize, tools/list, tools/call - Auto-detection: stdio (no address) vs HTTP/SSE (with address) micro mcp command: - 'micro mcp serve' - start MCP server (stdio or HTTP) - 'micro mcp list' - list available tools - 'micro mcp test' - test a tool (placeholder) - Enables Claude Code users to add microservices as tools Gateway refactor: - Created gateway/api package (reusable, 150 lines) - Moved gateway logic from cmd/micro/server/gateway.go - HandlerRegistrar pattern for flexibility - cmd/micro/server/gateway.go now compatibility wrapper (72 lines) - 50% code reduction, better separation of concerns - Library users can now use gateway in custom apps Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
257 行
5.9 KiB
Go
257 行
5.9 KiB
Go
// Package mcp provides the 'micro mcp' command for MCP server management
|
|
package mcp
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
|
|
"github.com/urfave/cli/v2"
|
|
"go-micro.dev/v5/cmd"
|
|
"go-micro.dev/v5/gateway/mcp"
|
|
"go-micro.dev/v5/registry"
|
|
)
|
|
|
|
func init() {
|
|
cmd.Register(&cli.Command{
|
|
Name: "mcp",
|
|
Usage: "MCP server management",
|
|
Description: `Manage MCP (Model Context Protocol) server for AI agent integration.
|
|
|
|
Examples:
|
|
# Start MCP server (stdio for Claude Code)
|
|
micro mcp serve
|
|
|
|
# Start MCP server with HTTP/SSE
|
|
micro mcp serve --address :3000
|
|
|
|
# List available tools
|
|
micro mcp list
|
|
|
|
# Test a tool
|
|
micro mcp test users.Users.Get
|
|
|
|
The 'micro mcp' command exposes your microservices as AI-accessible tools via the
|
|
Model Context Protocol (MCP). This enables Claude Code, ChatGPT, and other AI agents
|
|
to discover and call your services automatically.
|
|
|
|
For Claude Code integration, add to your config:
|
|
{
|
|
"mcpServers": {
|
|
"my-services": {
|
|
"command": "micro",
|
|
"args": ["mcp", "serve"]
|
|
}
|
|
}
|
|
}`,
|
|
Subcommands: []*cli.Command{
|
|
{
|
|
Name: "serve",
|
|
Usage: "Start MCP server",
|
|
Description: `Start an MCP server to expose microservices as AI tools.
|
|
|
|
By default, uses stdio transport (for Claude Code and local AI tools).
|
|
Use --address for HTTP/SSE transport (for web-based agents).
|
|
|
|
Examples:
|
|
# Stdio transport (for Claude Code)
|
|
micro mcp serve
|
|
|
|
# HTTP/SSE transport
|
|
micro mcp serve --address :3000
|
|
|
|
# Custom registry
|
|
micro mcp serve --registry consul --registry_address consul:8500`,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "address",
|
|
Usage: "HTTP address to listen on (e.g., :3000). If not set, uses stdio.",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "registry",
|
|
Usage: "Registry for service discovery (mdns, consul, etcd)",
|
|
Value: "mdns",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "registry_address",
|
|
Usage: "Registry address (e.g., consul:8500)",
|
|
},
|
|
},
|
|
Action: serveAction,
|
|
},
|
|
{
|
|
Name: "list",
|
|
Usage: "List available tools",
|
|
Description: `List all tools available via MCP.
|
|
|
|
Each service endpoint is exposed as a tool that AI agents can call.
|
|
|
|
Example:
|
|
micro mcp list`,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "registry",
|
|
Usage: "Registry for service discovery (mdns, consul, etcd)",
|
|
Value: "mdns",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "registry_address",
|
|
Usage: "Registry address",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "json",
|
|
Usage: "Output as JSON",
|
|
},
|
|
},
|
|
Action: listAction,
|
|
},
|
|
{
|
|
Name: "test",
|
|
Usage: "Test a tool",
|
|
Description: `Test calling a specific tool.
|
|
|
|
Example:
|
|
micro mcp test users.Users.Get '{"id": "123"}'`,
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "registry",
|
|
Usage: "Registry for service discovery",
|
|
Value: "mdns",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "registry_address",
|
|
Usage: "Registry address",
|
|
},
|
|
},
|
|
Action: testAction,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
// serveAction starts the MCP server
|
|
func serveAction(ctx *cli.Context) error {
|
|
// Get registry
|
|
reg := registry.DefaultRegistry
|
|
if regName := ctx.String("registry"); regName != "" {
|
|
// TODO: Support other registries (consul, etcd)
|
|
if regName != "mdns" {
|
|
return fmt.Errorf("registry %s not yet supported, use mdns", regName)
|
|
}
|
|
}
|
|
|
|
// Create MCP server options
|
|
opts := mcp.Options{
|
|
Registry: reg,
|
|
Address: ctx.String("address"),
|
|
Context: context.Background(),
|
|
Logger: log.Default(),
|
|
}
|
|
|
|
// Handle shutdown gracefully
|
|
ctx2, cancel := context.WithCancel(opts.Context)
|
|
opts.Context = ctx2
|
|
defer cancel()
|
|
|
|
sigChan := make(chan os.Signal, 1)
|
|
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
|
go func() {
|
|
<-sigChan
|
|
cancel()
|
|
}()
|
|
|
|
// Start MCP server
|
|
return mcp.Serve(opts)
|
|
}
|
|
|
|
// listAction lists available tools
|
|
func listAction(ctx *cli.Context) error {
|
|
// Get registry
|
|
reg := registry.DefaultRegistry
|
|
|
|
// Create temporary MCP server to discover tools
|
|
opts := mcp.Options{
|
|
Registry: reg,
|
|
Context: context.Background(),
|
|
Logger: log.New(os.Stderr, "", 0), // Log to stderr so stdout is clean
|
|
}
|
|
|
|
// Discover services
|
|
services, err := opts.Registry.ListServices()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to list services: %w", err)
|
|
}
|
|
|
|
if ctx.Bool("json") {
|
|
// JSON output
|
|
var tools []map[string]interface{}
|
|
for _, svc := range services {
|
|
fullSvcs, err := opts.Registry.GetService(svc.Name)
|
|
if err != nil || len(fullSvcs) == 0 {
|
|
continue
|
|
}
|
|
|
|
for _, ep := range fullSvcs[0].Endpoints {
|
|
tools = append(tools, map[string]interface{}{
|
|
"name": fmt.Sprintf("%s.%s", svc.Name, ep.Name),
|
|
"service": svc.Name,
|
|
"endpoint": ep.Name,
|
|
"description": fmt.Sprintf("Call %s on %s service", ep.Name, svc.Name),
|
|
})
|
|
}
|
|
}
|
|
|
|
enc := json.NewEncoder(os.Stdout)
|
|
enc.SetIndent("", " ")
|
|
return enc.Encode(map[string]interface{}{
|
|
"tools": tools,
|
|
"count": len(tools),
|
|
})
|
|
}
|
|
|
|
// Human-readable output
|
|
fmt.Printf("Available MCP Tools:\n\n")
|
|
toolCount := 0
|
|
for _, svc := range services {
|
|
fullSvcs, err := opts.Registry.GetService(svc.Name)
|
|
if err != nil || len(fullSvcs) == 0 {
|
|
continue
|
|
}
|
|
|
|
fmt.Printf("Service: %s\n", svc.Name)
|
|
for _, ep := range fullSvcs[0].Endpoints {
|
|
toolName := fmt.Sprintf("%s.%s", svc.Name, ep.Name)
|
|
fmt.Printf(" • %s\n", toolName)
|
|
toolCount++
|
|
}
|
|
fmt.Println()
|
|
}
|
|
|
|
fmt.Printf("Total: %d tools\n", toolCount)
|
|
return nil
|
|
}
|
|
|
|
// testAction tests a specific tool
|
|
func testAction(ctx *cli.Context) error {
|
|
if ctx.Args().Len() < 1 {
|
|
return fmt.Errorf("usage: micro mcp test <tool-name> [input-json]")
|
|
}
|
|
|
|
toolName := ctx.Args().First()
|
|
inputJSON := "{}"
|
|
if ctx.Args().Len() > 1 {
|
|
inputJSON = ctx.Args().Get(1)
|
|
}
|
|
|
|
fmt.Printf("Testing tool: %s\n", toolName)
|
|
fmt.Printf("Input: %s\n", inputJSON)
|
|
fmt.Println("\nResult:")
|
|
fmt.Println("(Not yet implemented - coming soon)")
|
|
|
|
return nil
|
|
}
|