1
0
mirror of https://github.com/go-micro/go-micro.git synced 2026-06-15 19:35:13 +02:00
Files
go-micro/gateway/api/gateway.go
asim 3986738e2c stdio MCP transport and gateway refactor
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>
2026-02-11 13:38:27 +00:00

156 lines
3.9 KiB
Go

// Package api provides HTTP API gateway functionality for go-micro services.
//
// The API gateway translates HTTP requests into RPC calls and serves a web dashboard
// for browsing and calling services. It can be used in development (micro run) or
// production (micro server) with optional authentication.
package api
import (
"context"
"fmt"
"log"
"net/http"
"time"
"go-micro.dev/v5/gateway/mcp"
"go-micro.dev/v5/registry"
)
// Options configures the HTTP API gateway
type Options struct {
// Address to listen on (e.g., ":8080")
Address string
// AuthEnabled controls whether authentication is required
// If true, the HandlerRegistrar should include auth middleware
AuthEnabled bool
// Context for cancellation (if nil, uses background context)
Context context.Context
// Logger for gateway messages (if nil, uses log.Default())
Logger *log.Logger
// HandlerRegistrar is called to register HTTP handlers on the mux
// This allows different configurations (dev vs prod) to register different handlers
HandlerRegistrar func(mux *http.ServeMux) error
// MCPEnabled controls whether to start MCP gateway
MCPEnabled bool
// MCPAddress is the address for MCP gateway (e.g., ":3000")
MCPAddress string
// Registry for service discovery (if nil, uses registry.DefaultRegistry)
Registry registry.Registry
}
// Gateway represents a running HTTP API gateway server
type Gateway struct {
opts Options
server *http.Server
mux *http.ServeMux
}
// New creates a new gateway with the given options and starts it.
// Returns immediately after starting the server in a goroutine.
// Use Wait() or Run() to block until the server stops.
func New(opts Options) (*Gateway, error) {
// Set defaults
if opts.Address == "" {
opts.Address = ":8080"
}
if opts.Context == nil {
opts.Context = context.Background()
}
if opts.Logger == nil {
opts.Logger = log.Default()
}
if opts.Registry == nil {
opts.Registry = registry.DefaultRegistry
}
// Create a new mux for this gateway instance
mux := http.NewServeMux()
// Register handlers using the provided registrar
if opts.HandlerRegistrar != nil {
if err := opts.HandlerRegistrar(mux); err != nil {
return nil, fmt.Errorf("failed to register handlers: %w", err)
}
}
// Create HTTP server
server := &http.Server{
Addr: opts.Address,
Handler: mux,
}
gw := &Gateway{
opts: opts,
server: server,
mux: mux,
}
// Start MCP gateway if enabled
if opts.MCPEnabled && opts.MCPAddress != "" {
go func() {
if err := mcp.ListenAndServe(opts.MCPAddress, mcp.Options{
Registry: opts.Registry,
Context: opts.Context,
Logger: opts.Logger,
}); err != nil {
opts.Logger.Printf("[mcp] MCP gateway error: %v", err)
}
}()
opts.Logger.Printf("[mcp] MCP gateway enabled on %s", opts.MCPAddress)
}
// Start server in background
go func() {
opts.Logger.Printf("[gateway] Listening on %s (auth: %v)", opts.Address, opts.AuthEnabled)
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
opts.Logger.Printf("[gateway] Server error: %v", err)
}
}()
return gw, nil
}
// Run creates and starts a gateway, blocking until it stops.
// This is a convenience function equivalent to New() + Wait().
func Run(opts Options) error {
gw, err := New(opts)
if err != nil {
return err
}
return gw.Wait()
}
// Wait blocks until the server is shut down
func (g *Gateway) Wait() error {
<-g.opts.Context.Done()
return g.Stop()
}
// Stop gracefully shuts down the gateway
func (g *Gateway) Stop() error {
if g.server != nil {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
return g.server.Shutdown(ctx)
}
return nil
}
// Addr returns the address the gateway is listening on
func (g *Gateway) Addr() string {
return g.opts.Address
}
// Mux returns the underlying HTTP mux for this gateway
// This can be used to register additional handlers after creation
func (g *Gateway) Mux() *http.ServeMux {
return g.mux
}