embeddable

package
v0.0.14 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 23, 2025 License: MIT Imports: 19 Imported by: 1

README

Embeddable MCP Server

The embeddable package provides a simple way for Go applications to add MCP (Model Context Protocol) server capabilities with minimal code changes.

Features

  • Simple Integration: Add MCP server capabilities with just a few lines of code
  • Cobra Integration: Provides a standard mcp subcommand for existing cobra applications
  • Multiple Tool Registration Methods: Support for function-based, struct-based, and reflection-based tool registration
  • Session Management: Automatic session management with context-based access
  • Transport Flexibility: Support for both stdio and SSE transports
  • Schema Generation: Automatic JSON schema generation from Go structs and function signatures

Quick Start

Basic Usage
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/spf13/cobra"
    "github.com/go-go-golems/go-go-mcp/pkg/embeddable"
    "github.com/go-go-golems/go-go-mcp/pkg/protocol"
)

func main() {
    rootCmd := &cobra.Command{
        Use:   "myapp",
        Short: "My application",
    }

    // Add MCP server capability
    err := embeddable.AddMCPCommand(rootCmd,
        embeddable.WithName("MyApp MCP Server"),
        embeddable.WithVersion("1.0.0"),
        embeddable.WithServerDescription("Example MCP server"),
        embeddable.WithTool("greet", greetHandler,
            embeddable.WithDescription("Greet a person"),
            embeddable.WithStringArg("name", "Name of the person to greet", true),
        ),
    )
    if err != nil {
        log.Fatal(err)
    }

    if err := rootCmd.Execute(); err != nil {
        log.Fatal(err)
    }
}

func greetHandler(ctx context.Context, args map[string]interface{}) (*protocol.ToolResult, error) {
    name, ok := args["name"].(string)
    if !ok {
        return protocol.NewErrorToolResult(protocol.NewTextContent("name must be a string")), nil
    }

    return protocol.NewToolResult(
        protocol.WithText(fmt.Sprintf("Hello, %s!", name)),
    ), nil
}

Usage:

# Start the MCP server with stdio transport
myapp mcp start

# Start with SSE transport on port 3001
myapp mcp start --transport sse --port 3001

# List available tools
myapp mcp list-tools
Session Management

The embeddable API provides automatic session management through Go's context system:

func counterHandler(ctx context.Context, args map[string]interface{}) (*protocol.ToolResult, error) {
    // Session is automatically available via context
    sess, ok := session.GetSessionFromContext(ctx)
    if !ok {
        return protocol.NewErrorToolResult(protocol.NewTextContent("No session found")), nil
    }

    // Store and retrieve data from session
    sess.SetData("counter", 42)
    value, exists := sess.GetData("counter")
    
    return protocol.NewToolResult(
        protocol.WithText(fmt.Sprintf("Session: %s, Counter: %v", sess.ID, value)),
    ), nil
}
Struct-Based Tool Registration

Register tools directly from struct methods:

type DatabaseService struct {
    connectionString string
}

type QueryArgs struct {
    Query string `json:"query" description:"SQL query to execute"`
    Limit int    `json:"limit,omitempty" description:"Maximum number of rows to return"`
}

func (db *DatabaseService) ExecuteQuery(ctx context.Context, args QueryArgs) (*protocol.ToolResult, error) {
    return protocol.NewToolResult(
        protocol.WithText(fmt.Sprintf("Executed: %s", args.Query)),
    ), nil
}

func main() {
    // ... setup code ...
    
    config := embeddable.NewServerConfig()
    dbService := &DatabaseService{connectionString: "..."}
    
    err := embeddable.RegisterStructTool(config, "execute_query", dbService, "ExecuteQuery")
    if err != nil {
        log.Fatal(err)
    }
    
    // ... rest of setup ...
}

Enhanced Features (v2)

Inspired by mark3labs/mcp-go, we now provide enhanced APIs for even more convenient tool development:

Enhanced Tool Registration
embeddable.WithEnhancedTool("format_text", formatTextHandler,
    embeddable.WithEnhancedDescription("Format text with various options"),
    embeddable.WithReadOnlyHint(true),
    embeddable.WithIdempotentHint(true),
    embeddable.WithStringProperty("text",
        embeddable.PropertyDescription("Text to format"),
        embeddable.PropertyRequired(),
        embeddable.MinLength(1),
    ),
    embeddable.WithStringProperty("format",
        embeddable.PropertyDescription("Format type"),
        embeddable.StringEnum("uppercase", "lowercase", "title"),
        embeddable.DefaultString("lowercase"),
    ),
)
Enhanced Argument Access
func formatTextHandler(ctx context.Context, args embeddable.Arguments) (*protocol.ToolResult, error) {
    // Type-safe argument access with defaults and validation
    text, err := args.RequireString("text")
    if err != nil {
        return protocol.NewErrorToolResult(protocol.NewTextContent(err.Error())), nil
    }
    
    format := args.GetString("format", "lowercase")
    maxLength := args.GetInt("max_length", 100)
    enabled := args.GetBool("enabled", true)
    
    // Bind to struct
    var config MyConfig
    if err := args.BindArguments(&config); err != nil {
        return nil, err
    }
    
    // ... implementation
}
Tool Annotations

Add semantic hints about tool behavior:

embeddable.WithReadOnlyHint(true),        // Tool doesn't modify environment
embeddable.WithDestructiveHint(false),    // Tool won't cause destructive changes
embeddable.WithIdempotentHint(true),      // Repeated calls have no additional effect
embeddable.WithOpenWorldHint(false),      // Tool doesn't interact with external entities

API Reference

Server Configuration Options
Core Options
  • WithName(name string) - Set server name
  • WithVersion(version string) - Set server version
  • WithServerDescription(description string) - Set server description
Transport Options
  • WithDefaultTransport(transport string) - Set default transport ("stdio" or "sse")
  • WithDefaultPort(port int) - Set default port for SSE transport
Tool Registration Options
  • WithTool(name, handler, opts...) - Register a tool with handler function
  • WithEnhancedTool(name, handler, opts...) - Register with enhanced argument handling
  • WithToolRegistry(registry) - Use a custom tool registry
Advanced Options
  • WithSessionStore(store) - Use a custom session store
  • WithMiddleware(middleware...) - Add middleware functions
  • WithHooks(hooks) - Add lifecycle hooks
Tool Configuration Options
Basic Tool Options
  • WithDescription(desc string) - Set tool description
  • WithSchema(schema interface{}) - Set custom JSON schema
  • WithExample(name, description, args) - Add usage example
Enhanced Tool Options
  • WithEnhancedDescription(desc) - Set tool description
  • WithReadOnlyHint(bool) - Mark tool as read-only
  • WithDestructiveHint(bool) - Mark tool as potentially destructive
  • WithIdempotentHint(bool) - Mark tool as idempotent
  • WithOpenWorldHint(bool) - Mark tool as interacting with external world
Property Configuration (Enhanced Tools)
  • WithStringProperty(name, opts...) - Add string property with rich options
  • WithIntProperty(name, opts...) - Add integer property
  • WithNumberProperty(name, opts...) - Add number property
  • WithBooleanProperty(name, opts...) - Add boolean property
  • WithArrayProperty(name, opts...) - Add array property
  • WithObjectProperty(name, opts...) - Add object property
Property Options
  • PropertyDescription(desc) - Set property description
  • PropertyRequired() - Mark property as required
  • PropertyTitle(title) - Set display title
  • DefaultString(value), DefaultNumber(value), DefaultBool(value) - Set defaults
  • StringEnum(values...) - Restrict to enum values
  • MinLength(n), MaxLength(n) - String length constraints
  • Minimum(n), Maximum(n) - Number range constraints
  • StringPattern(regex) - Regex pattern validation
  • MinItems(n), MaxItems(n) - Array size constraints
  • UniqueItems(bool) - Array uniqueness constraint
Convenience Schema Builders (Legacy)
  • WithStringArg(name, description, required) - Add string parameter
  • WithIntArg(name, description, required) - Add integer parameter
  • WithBoolArg(name, description, required) - Add boolean parameter
  • WithFileArg(name, description, required) - Add file parameter
Command Structure

The generated mcp command provides:

myapp mcp
├── start              # Start the MCP server
│   ├── --transport    # Transport type (stdio, sse)
│   ├── --port         # Port for SSE transport
│   └── --config       # Configuration file path
├── list-tools         # List available tools
└── test-tool          # Test a specific tool

Advanced Features

Middleware Support

Add middleware to process tool calls:

func loggingMiddleware(next embeddable.ToolHandler) embeddable.ToolHandler {
    return func(ctx context.Context, args map[string]interface{}) (*protocol.ToolResult, error) {
        log.Printf("Calling tool with args: %v", args)
        result, err := next(ctx, args)
        log.Printf("Tool result: %v, error: %v", result, err)
        return result, err
    }
}

// Usage
embeddable.AddMCPCommand(rootCmd,
    embeddable.WithMiddleware(loggingMiddleware),
    // ... other options
)
Reflection-Based Registration

Register functions directly using reflection:

func addNumbers(ctx context.Context, args AddArgs) (*protocol.ToolResult, error) {
    // Implementation
}

// Register the function
err := embeddable.RegisterFunctionTool(config, "add", addNumbers)
Custom Tool Registry

Use a custom tool registry for advanced scenarios:

registry := tool_registry.NewRegistry()
// ... register tools manually ...

err := embeddable.AddMCPCommand(rootCmd,
    embeddable.WithToolRegistry(registry),
    // ... other options
)

Examples

See the examples/ directory for complete working examples:

  • examples/basic/ - Basic tool registration and usage
  • examples/session/ - Session management demonstration
  • examples/struct/ - Struct-based tool registration
  • examples/enhanced/ - Enhanced API with rich argument handling and property configuration

Migration from Manual Setup

The embeddable API is designed to work alongside existing go-go-mcp implementations:

  1. Gradual Adoption: Can coexist with manual server implementations
  2. Tool Reuse: Existing tools can be easily wrapped for the embeddable API
  3. Configuration Compatibility: Supports existing configuration patterns
  4. Feature Parity: All core go-go-mcp features available

Error Handling

The embeddable API provides consistent error handling:

func myHandler(ctx context.Context, args map[string]interface{}) (*protocol.ToolResult, error) {
    if someCondition {
        // Return error result (shown to user)
        return protocol.NewErrorToolResult(
            protocol.NewTextContent("Something went wrong"),
        ), nil
    }
    
    // Return system error (logged, generic error shown to user)
    return nil, fmt.Errorf("system error: %w", err)
}

Best Practices

  1. Tool Naming: Use clear, descriptive names for tools
  2. Schema Design: Provide comprehensive schemas with descriptions
  3. Error Messages: Use user-friendly error messages
  4. Session Management: Use sessions for stateful operations
  5. Validation: Validate inputs before processing
  6. Documentation: Add examples to help users understand tool usage

Contributing

The embeddable package is part of the go-go-mcp project. See the main project README for contribution guidelines.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddMCPCommand

func AddMCPCommand(rootCmd *cobra.Command, opts ...ServerOption) error

AddMCPCommand adds a standard 'mcp' subcommand to an existing cobra application

func GetCommandFlags added in v0.0.11

func GetCommandFlags(ctx context.Context) (map[string]interface{}, bool)

GetCommandFlags retrieves command flags from context

func NewMCPCommand

func NewMCPCommand(opts ...ServerOption) *cobra.Command

NewMCPCommand creates a new 'mcp' command with the given options

func RegisterFunctionTool

func RegisterFunctionTool(config *ServerConfig, name string, fn interface{}) error

RegisterFunctionTool creates a tool from a function using reflection

func RegisterSimpleTools

func RegisterSimpleTools(config *ServerConfig, tools map[string]ToolHandler) error

RegisterSimpleTools provides a very easy way to register multiple tools

func RegisterStructTool

func RegisterStructTool(config *ServerConfig, name string, obj interface{}, methodName string) error

RegisterStructTool automatically creates a tool from a struct and method

Types

type Arguments

type Arguments map[string]interface{}

Arguments provides convenient methods for accessing tool arguments with type conversion and validation, inspired by mark3labs/mcp-go

func NewArguments

func NewArguments(args map[string]interface{}) Arguments

NewArguments creates an Arguments instance from a map

func (Arguments) BindArguments

func (a Arguments) BindArguments(target interface{}) error

BindArguments unmarshals the arguments into the provided struct

func (Arguments) GetBool

func (a Arguments) GetBool(key string, defaultValue bool) bool

Boolean argument access with flexible type conversion

func (Arguments) GetFloat

func (a Arguments) GetFloat(key string, defaultValue float64) float64

Float argument access with flexible type conversion

func (Arguments) GetInt

func (a Arguments) GetInt(key string, defaultValue int) int

Integer argument access with flexible type conversion

func (Arguments) GetIntSlice

func (a Arguments) GetIntSlice(key string, defaultValue []int) []int

Int slice argument access

func (Arguments) GetString

func (a Arguments) GetString(key string, defaultValue string) string

String argument access

func (Arguments) GetStringSlice

func (a Arguments) GetStringSlice(key string, defaultValue []string) []string

String slice argument access

func (Arguments) Has

func (a Arguments) Has(key string) bool

Has checks if an argument exists

func (Arguments) Keys

func (a Arguments) Keys() []string

Keys returns all argument keys

func (Arguments) Raw

func (a Arguments) Raw() map[string]interface{}

Raw returns the underlying map for direct access

func (Arguments) RequireBool

func (a Arguments) RequireBool(key string) (bool, error)

func (Arguments) RequireFloat

func (a Arguments) RequireFloat(key string) (float64, error)

func (Arguments) RequireInt

func (a Arguments) RequireInt(key string) (int, error)

func (Arguments) RequireIntSlice

func (a Arguments) RequireIntSlice(key string) ([]int, error)

func (Arguments) RequireString

func (a Arguments) RequireString(key string) (string, error)

func (Arguments) RequireStringSlice

func (a Arguments) RequireStringSlice(key string) ([]string, error)

type Backend added in v0.0.14

type Backend interface {
	Start(ctx context.Context) error
}

Backend represents a runnable server backend that starts the selected transport using an mcp-go MCPServer.

func NewBackend added in v0.0.14

func NewBackend(cfg *ServerConfig) (Backend, error)

NewBackend constructs an mcp-go based backend from the provided ServerConfig. It builds an MCP server, registers tools via existing configuration, and returns a transport-specific backend that can Start(ctx).

type CommandCustomizer added in v0.0.11

type CommandCustomizer func(*cobra.Command) error

CommandCustomizer is a function that can customize a cobra.Command

type ContextKey added in v0.0.11

type ContextKey string

ContextKey is used for storing values in context

const (
	// CommandFlagsKey is the context key for storing command flags
	CommandFlagsKey ContextKey = "command_flags"
)

type EnhancedToolConfig

type EnhancedToolConfig struct {
	Description string
	Schema      map[string]interface{}
	Annotations ToolAnnotations
	Examples    []ToolExample
}

EnhancedToolConfig holds configuration for enhanced tools

type EnhancedToolHandler

type EnhancedToolHandler func(ctx context.Context, args Arguments) (*protocol.ToolResult, error)

EnhancedToolHandler is an enhanced function signature for tool handlers It provides an Arguments wrapper with convenient accessor methods

type EnhancedToolOption

type EnhancedToolOption func(*EnhancedToolConfig) error

EnhancedToolOption configures enhanced tools

func WithAnnotations

func WithAnnotations(annotations ToolAnnotations) EnhancedToolOption

func WithArrayProperty

func WithArrayProperty(name string, opts ...PropertyOption) EnhancedToolOption

func WithBooleanProperty

func WithBooleanProperty(name string, opts ...PropertyOption) EnhancedToolOption

func WithDestructiveHint

func WithDestructiveHint(destructive bool) EnhancedToolOption

func WithEnhancedDescription

func WithEnhancedDescription(desc string) EnhancedToolOption

Enhanced tool configuration options

func WithIdempotentHint

func WithIdempotentHint(idempotent bool) EnhancedToolOption

func WithIntProperty

func WithIntProperty(name string, opts ...PropertyOption) EnhancedToolOption

func WithNumberProperty

func WithNumberProperty(name string, opts ...PropertyOption) EnhancedToolOption

func WithObjectProperty

func WithObjectProperty(name string, opts ...PropertyOption) EnhancedToolOption

func WithOpenWorldHint

func WithOpenWorldHint(openWorld bool) EnhancedToolOption

func WithReadOnlyHint

func WithReadOnlyHint(readOnly bool) EnhancedToolOption

func WithStringProperty

func WithStringProperty(name string, opts ...PropertyOption) EnhancedToolOption

Enhanced property configuration

type Hooks

type Hooks struct {
	OnServerStart  func(ctx context.Context) error
	BeforeToolCall func(ctx context.Context, toolName string, args map[string]interface{}) error
	AfterToolCall  func(ctx context.Context, toolName string, result *protocol.ToolResult, err error)
}

Hooks allows customization of server behavior

type JSONSchema added in v0.0.12

type JSONSchema struct {
	Type        string                    `json:"type"`
	Properties  map[string]PropertySchema `json:"properties"`
	Required    []string                  `json:"required"`
	Description string                    `json:"description"`
}

JSONSchema represents a JSON Schema structure

type PropertyOption

type PropertyOption func(map[string]interface{})

PropertyOption configures a property in a tool's input schema

func ArrayItems

func ArrayItems(itemSchema map[string]interface{}) PropertyOption

Array property options

func DefaultBool

func DefaultBool(value bool) PropertyOption

Boolean property options

func DefaultNumber

func DefaultNumber(value float64) PropertyOption

Number property options

func DefaultString

func DefaultString(value string) PropertyOption

String property options

func MaxItems

func MaxItems(maxItems int) PropertyOption

func MaxLength

func MaxLength(maxLen int) PropertyOption

func Maximum

func Maximum(maxVal float64) PropertyOption

func MinItems

func MinItems(minItems int) PropertyOption

func MinLength

func MinLength(minLen int) PropertyOption

func Minimum

func Minimum(minVal float64) PropertyOption

func MultipleOf

func MultipleOf(value float64) PropertyOption

func PropertyDescription

func PropertyDescription(desc string) PropertyOption

Property configuration options

func PropertyRequired

func PropertyRequired() PropertyOption

func PropertyTitle

func PropertyTitle(title string) PropertyOption

func StringEnum

func StringEnum(values ...string) PropertyOption

func StringPattern

func StringPattern(pattern string) PropertyOption

func UniqueItems

func UniqueItems(unique bool) PropertyOption

type PropertySchema added in v0.0.12

type PropertySchema struct {
	Type        string      `json:"type"`
	Description string      `json:"description"`
	Enum        []string    `json:"enum"`
	Default     interface{} `json:"default"`
}

PropertySchema represents a property in JSON Schema

type ServerConfig

type ServerConfig struct {
	Name        string
	Version     string
	Description string
	// contains filtered or unexported fields
}

ServerConfig holds the configuration for the embeddable server

func NewServerConfig

func NewServerConfig() *ServerConfig

NewServerConfig creates a new server configuration with defaults

func (*ServerConfig) GetToolProvider

func (c *ServerConfig) GetToolProvider() pkg.ToolProvider

GetToolProvider returns the tool provider for the server config

type ServerOption

type ServerOption func(*ServerConfig) error

ServerOption configures the embeddable MCP server

func WithCommandCustomizer added in v0.0.11

func WithCommandCustomizer(customizer CommandCustomizer) ServerOption

func WithConfigEnabled

func WithConfigEnabled(enabled bool) ServerOption

func WithConfigFile

func WithConfigFile(file string) ServerOption

func WithDefaultPort

func WithDefaultPort(port int) ServerOption

func WithDefaultTransport

func WithDefaultTransport(transport string) ServerOption

Transport options

func WithEnhancedTool

func WithEnhancedTool(name string, handler EnhancedToolHandler, opts ...EnhancedToolOption) ServerOption

Enhanced tool registration with mark3labs/mcp-go inspired API

func WithHooks

func WithHooks(hooks *Hooks) ServerOption

func WithInternalServers

func WithInternalServers(servers ...string) ServerOption

func WithMiddleware

func WithMiddleware(middleware ...ToolMiddleware) ServerOption

func WithName

func WithName(name string) ServerOption

Core options

func WithServerDescription

func WithServerDescription(description string) ServerOption

func WithSessionStore

func WithSessionStore(store session.SessionStore) ServerOption

Advanced options

func WithTool

func WithTool(name string, handler ToolHandler, opts ...ToolOption) ServerOption

Tool registration options

func WithToolRegistry

func WithToolRegistry(registry *tool_registry.Registry) ServerOption

func WithVersion

func WithVersion(version string) ServerOption

type ToolAnnotations

type ToolAnnotations struct {
	Title           string `json:"title,omitempty"`
	ReadOnlyHint    *bool  `json:"readOnlyHint,omitempty"`
	DestructiveHint *bool  `json:"destructiveHint,omitempty"`
	IdempotentHint  *bool  `json:"idempotentHint,omitempty"`
	OpenWorldHint   *bool  `json:"openWorldHint,omitempty"`
}

ToolAnnotations provides metadata about tool behavior

type ToolConfig

type ToolConfig struct {
	Description string
	Schema      interface{} // Can be a struct, JSON schema string, or json.RawMessage
	Examples    []ToolExample
}

ToolConfig holds configuration for a tool

type ToolExample

type ToolExample struct {
	Name        string                 `json:"name"`
	Description string                 `json:"description"`
	Arguments   map[string]interface{} `json:"arguments"`
}

ToolExample represents an example usage of a tool

type ToolHandler

type ToolHandler func(ctx context.Context, args map[string]interface{}) (*protocol.ToolResult, error)

ToolHandler is a simplified function signature for tool handlers Session information is available via session.GetSessionFromContext(ctx)

type ToolMiddleware

type ToolMiddleware func(next ToolHandler) ToolHandler

ToolMiddleware is a function that wraps a ToolHandler

type ToolOption

type ToolOption func(*ToolConfig) error

ToolOption configures individual tools

func WithBoolArg

func WithBoolArg(name, description string, required bool) ToolOption

func WithDescription

func WithDescription(desc string) ToolOption

Tool configuration options

func WithExample

func WithExample(name, description string, args map[string]interface{}) ToolOption

func WithFileArg

func WithFileArg(name, description string, required bool) ToolOption

func WithIntArg

func WithIntArg(name, description string, required bool) ToolOption

func WithSchema

func WithSchema(schema interface{}) ToolOption

func WithStringArg

func WithStringArg(name, description string, required bool) ToolOption

Convenience functions for common tool patterns

Directories

Path Synopsis
examples
basic command
enhanced command
session command
struct command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL