Documentation
¶
Overview ¶
Package adapter provides protocol-agnostic tool format conversion. It enables bidirectional transformation between MCP, OpenAI, and Anthropic tool definitions through a canonical intermediate representation.
This is a pure data-transform library with no I/O, network, or runtime execution.
Overview ¶
The adapter package uses a hub-and-spoke architecture where all conversions pass through a canonical intermediate format (CanonicalTool). This allows N adapters to support N² conversions with only N implementations.
Basic Usage ¶
Use the default registry with all built-in adapters:
registry := adapter.DefaultRegistry()
// Convert an MCP tool to OpenAI format
result, err := registry.Convert(mcpTool, "mcp", "openai")
if err != nil {
log.Fatal(err)
}
// Check for feature loss warnings
for _, w := range result.Warnings {
log.Printf("Warning: %s", w)
}
openaiTool := result.Tool.(*adapter.OpenAITool)
Supported Formats ¶
The package includes adapters for three tool formats:
- MCP (Model Context Protocol) - Full JSON Schema 2020-12 support
- OpenAI - Function calling format with strict mode support
- Anthropic - Tool use format with anyOf support
Feature Loss Warnings ¶
Different formats support different JSON Schema features. When converting from a format with more features to one with fewer, the adapter emits warnings indicating which features were lost:
result, _ := registry.Convert(tool, "mcp", "openai")
if len(result.Warnings) > 0 {
fmt.Println("The following features are not supported by OpenAI:")
for _, w := range result.Warnings {
fmt.Printf(" - %s at %s\n", w.Feature, w.Path)
}
}
Feature Support Matrix ¶
Feature MCP OpenAI Anthropic ───────────────────────────────────────── $ref/$defs Yes No No anyOf Yes No Yes oneOf Yes No No allOf Yes No No not Yes No No pattern Yes Yes Yes format Yes No Yes enum/const Yes Yes Yes min/max Yes Yes Yes
Custom Adapters ¶
Implement the Adapter interface to add support for new formats:
type Adapter interface {
Name() string
ToCanonical(raw any) (*CanonicalTool, error)
FromCanonical(ct *CanonicalTool) (any, error)
SupportsFeature(feature SchemaFeature) bool
}
Register custom adapters with the registry:
registry := adapter.NewRegistry() registry.Register(adapter.NewMCPAdapter()) registry.Register(myCustomAdapter)
Type Definitions ¶
The package defines local types for OpenAI and Anthropic formats to avoid SDK coupling:
- OpenAITool / OpenAIFunction - OpenAI function calling format
- AnthropicTool - Anthropic tool use format
These types can be serialized directly to JSON for API requests.
Thread Safety ¶
The AdapterRegistry is thread-safe for concurrent reads after initial registration. Register all adapters during initialization before concurrent use.
Index ¶
- type Adapter
- type AdapterRegistry
- func (r *AdapterRegistry) Convert(tool any, fromFormat, toFormat string) (*ConversionResult, error)
- func (r *AdapterRegistry) Get(name string) (Adapter, error)
- func (r *AdapterRegistry) List() []string
- func (r *AdapterRegistry) Register(a Adapter) error
- func (r *AdapterRegistry) Unregister(name string) error
- type AnthropicAdapter
- type AnthropicCacheControl
- type AnthropicTool
- type CanonicalTool
- type ConversionError
- type ConversionResult
- type FeatureLossWarning
- type JSONSchema
- type MCPAdapter
- type OpenAIAdapter
- type OpenAIFunction
- type OpenAITool
- type SchemaFeature
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Adapter ¶
type Adapter interface {
// Name returns the adapter's identifier (e.g., "mcp", "openai", "anthropic")
Name() string
// ToCanonical converts a protocol-specific tool to canonical format.
// The raw parameter type depends on the adapter (e.g., mcp.Tool, OpenAIFunction).
ToCanonical(raw any) (*CanonicalTool, error)
// FromCanonical converts a canonical tool to the protocol-specific format.
// The returned type depends on the adapter.
FromCanonical(tool *CanonicalTool) (any, error)
// SupportsFeature returns whether this adapter supports a schema feature.
// Features not supported will generate warnings during conversion.
SupportsFeature(feature SchemaFeature) bool
}
Adapter defines the contract for protocol-specific tool adapters. Each adapter handles bidirectional conversion between a specific tool format (MCP, OpenAI, Anthropic) and the canonical representation.
Contract:
- Thread-safety: implementations must be safe for concurrent use unless documented otherwise.
- Ownership: must not mutate caller-owned inputs; return new objects on conversion.
- Errors: ToCanonical/FromCanonical must return typed errors (e.g., *ConversionError) for invalid input.
- Determinism: same input yields structurally equivalent canonical output.
type AdapterRegistry ¶
type AdapterRegistry struct {
// contains filtered or unexported fields
}
AdapterRegistry is a thread-safe registry of protocol adapters.
func DefaultRegistry ¶ added in v0.2.0
func DefaultRegistry() *AdapterRegistry
DefaultRegistry returns a registry pre-configured with all built-in adapters. The registry includes MCP, OpenAI, and Anthropic adapters.
Example ¶
package main
import (
"fmt"
"github.com/jonwraymond/toolfoundation/adapter"
)
func main() {
registry := adapter.DefaultRegistry()
// List available adapters
adapters := registry.List()
fmt.Printf("Adapter count: %d\n", len(adapters))
}
Output: Adapter count: 3
func NewRegistry ¶
func NewRegistry() *AdapterRegistry
NewRegistry creates a new empty adapter registry.
Example ¶
package main
import (
"fmt"
"github.com/jonwraymond/toolfoundation/adapter"
)
func main() {
// Create a custom registry with only specific adapters
registry := adapter.NewRegistry()
// Register only the adapters you need
_ = registry.Register(adapter.NewMCPAdapter())
_ = registry.Register(adapter.NewOpenAIAdapter())
fmt.Printf("Custom registry has %d adapters\n", len(registry.List()))
}
Output: Custom registry has 2 adapters
func (*AdapterRegistry) Convert ¶
func (r *AdapterRegistry) Convert(tool any, fromFormat, toFormat string) (*ConversionResult, error)
Convert transforms a tool from one format to another. It uses the source adapter's ToCanonical and the target adapter's FromCanonical. Returns warnings if schema features are lost during conversion.
Example ¶
package main
import (
"fmt"
"log"
"github.com/modelcontextprotocol/go-sdk/mcp"
"github.com/jonwraymond/toolfoundation/adapter"
"github.com/jonwraymond/toolfoundation/model"
)
func main() {
// Create a tool
tool := &model.Tool{
Tool: mcp.Tool{
Name: "get_weather",
Description: "Get current weather for a location",
InputSchema: map[string]any{
"type": "object",
"properties": map[string]any{
"location": map[string]any{
"type": "string",
"description": "City name",
},
},
"required": []string{"location"},
},
},
}
// Convert MCP to OpenAI format
registry := adapter.DefaultRegistry()
result, err := registry.Convert(tool, "mcp", "openai")
if err != nil {
log.Fatal(err)
}
openaiTool := result.Tool.(*adapter.OpenAITool)
fmt.Println("Type:", openaiTool.Type)
fmt.Println("Function name:", openaiTool.Function.Name)
}
Output: Type: function Function name: get_weather
Example (WithWarnings) ¶
package main
import (
"fmt"
"github.com/modelcontextprotocol/go-sdk/mcp"
"github.com/jonwraymond/toolfoundation/adapter"
"github.com/jonwraymond/toolfoundation/model"
)
func main() {
// Create a tool with features not supported by all adapters
tool := &model.Tool{
Tool: mcp.Tool{
Name: "search",
Description: "Search with flexible input",
InputSchema: map[string]any{
"type": "object",
"properties": map[string]any{
"query": map[string]any{
// anyOf is not supported by OpenAI
"anyOf": []any{
map[string]any{"type": "string"},
map[string]any{"type": "array", "items": map[string]any{"type": "string"}},
},
},
},
},
},
}
registry := adapter.DefaultRegistry()
result, _ := registry.Convert(tool, "mcp", "openai")
if len(result.Warnings) > 0 {
fmt.Println("Feature loss detected")
for _, w := range result.Warnings {
fmt.Printf(" - %s\n", w.Feature)
}
}
}
Output: Feature loss detected - anyOf
func (*AdapterRegistry) Get ¶
func (r *AdapterRegistry) Get(name string) (Adapter, error)
Get retrieves an adapter by name. Returns an error if the adapter is not found.
func (*AdapterRegistry) List ¶
func (r *AdapterRegistry) List() []string
List returns the names of all registered adapters.
func (*AdapterRegistry) Register ¶
func (r *AdapterRegistry) Register(a Adapter) error
Register adds an adapter to the registry. Returns an error if an adapter with the same name is already registered.
func (*AdapterRegistry) Unregister ¶
func (r *AdapterRegistry) Unregister(name string) error
Unregister removes an adapter from the registry. Returns an error if the adapter is not found.
type AnthropicAdapter ¶ added in v0.2.0
type AnthropicAdapter struct{}
AnthropicAdapter converts between Anthropic tool format and CanonicalTool.
func NewAnthropicAdapter ¶ added in v0.2.0
func NewAnthropicAdapter() *AnthropicAdapter
NewAnthropicAdapter creates a new Anthropic adapter.
func (*AnthropicAdapter) FromCanonical ¶ added in v0.2.0
func (a *AnthropicAdapter) FromCanonical(ct *CanonicalTool) (any, error)
FromCanonical converts a canonical tool to Anthropic format. Returns *AnthropicTool.
func (*AnthropicAdapter) Name ¶ added in v0.2.0
func (a *AnthropicAdapter) Name() string
Name returns the adapter's identifier.
func (*AnthropicAdapter) SupportsFeature ¶ added in v0.2.0
func (a *AnthropicAdapter) SupportsFeature(feature SchemaFeature) bool
SupportsFeature returns whether this adapter supports a schema feature.
func (*AnthropicAdapter) ToCanonical ¶ added in v0.2.0
func (a *AnthropicAdapter) ToCanonical(raw any) (*CanonicalTool, error)
ToCanonical converts an Anthropic tool to the canonical format. Accepts *AnthropicTool or AnthropicTool.
type AnthropicCacheControl ¶ added in v0.2.0
type AnthropicCacheControl struct {
Type string `json:"type"` // "ephemeral"
}
AnthropicCacheControl for prompt caching.
type AnthropicTool ¶ added in v0.2.0
type AnthropicTool struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
InputSchema map[string]any `json:"input_schema"`
CacheControl *AnthropicCacheControl `json:"cache_control,omitempty"`
}
AnthropicTool represents the Anthropic tool format. Based on Anthropic API spec - defined locally to avoid SDK coupling.
Example ¶
package main
import (
"encoding/json"
"fmt"
"github.com/jonwraymond/toolfoundation/adapter"
)
func main() {
anthropicTool := &adapter.AnthropicTool{
Name: "search_docs",
Description: "Search documentation",
InputSchema: map[string]any{
"type": "object",
"properties": map[string]any{
"query": map[string]any{"type": "string"},
},
"required": []string{"query"},
},
}
// Serialize to JSON for API request
data, _ := json.MarshalIndent(anthropicTool, "", " ")
fmt.Println(string(data))
}
Output: { "name": "search_docs", "description": "Search documentation", "input_schema": { "properties": { "query": { "type": "string" } }, "required": [ "query" ], "type": "object" } }
type CanonicalTool ¶
type CanonicalTool struct {
// Namespace groups related tools (e.g., "github", "slack")
Namespace string
// Name is the tool's identifier (required)
Name string
// Version is the semantic version of the tool
Version string
// Description explains what the tool does
Description string
// Category classifies the tool's purpose
Category string
// Tags are keywords for discovery
Tags []string
// InputSchema defines the tool's input parameters (required)
InputSchema *JSONSchema
// OutputSchema defines the tool's output format
OutputSchema *JSONSchema
// Timeout is the maximum execution time
Timeout time.Duration
// SourceFormat is the original format (e.g., "mcp", "openai", "anthropic")
SourceFormat string
// SourceMeta contains format-specific metadata for round-trip conversion
SourceMeta map[string]any
// RequiredScopes are authorization scopes needed to use the tool
RequiredScopes []string
}
CanonicalTool is the protocol-agnostic representation of a tool definition. It serves as the intermediate format for converting between MCP, OpenAI, and Anthropic tool formats.
func (*CanonicalTool) ID ¶
func (t *CanonicalTool) ID() string
ID returns the tool's fully qualified identifier. If Namespace is set, returns "namespace:name", otherwise just "name".
func (*CanonicalTool) Validate ¶
func (t *CanonicalTool) Validate() error
Validate checks that the tool has all required fields. Returns an error if Name or InputSchema is missing.
type ConversionError ¶
type ConversionError struct {
// Adapter is the name of the adapter that encountered the error
Adapter string
// Direction is "to_canonical" or "from_canonical"
Direction string
// Cause is the underlying error
Cause error
}
ConversionError represents an error during tool format conversion.
func (*ConversionError) Error ¶
func (e *ConversionError) Error() string
Error returns a formatted error message including adapter, direction, and cause.
func (*ConversionError) Unwrap ¶
func (e *ConversionError) Unwrap() error
Unwrap returns the underlying cause for use with errors.Is and errors.As.
type ConversionResult ¶
type ConversionResult struct {
// Tool is the converted tool in the target format
Tool any
// Warnings lists features that may have been lost during conversion
Warnings []FeatureLossWarning
}
ConversionResult contains the result of a format conversion.
type FeatureLossWarning ¶
type FeatureLossWarning struct {
// Feature is the schema feature that will be lost
Feature SchemaFeature
// FromAdapter is the source adapter name
FromAdapter string
// ToAdapter is the target adapter name
ToAdapter string
}
FeatureLossWarning indicates that a schema feature will be lost during conversion. This is a warning, not an error - the conversion proceeds but with reduced fidelity.
func (FeatureLossWarning) String ¶
func (w FeatureLossWarning) String() string
String returns a human-readable warning message.
type JSONSchema ¶
type JSONSchema struct {
// Type is the JSON type (object, array, string, number, integer, boolean, null)
Type string
// Properties maps property names to their schemas (for object types)
Properties map[string]*JSONSchema
// Required lists property names that must be present
Required []string
// Items is the schema for array elements
Items *JSONSchema
// Description explains the schema
Description string
// Enum restricts values to a fixed set
Enum []any
// Const restricts to a single value
Const any
// Default is the default value
Default any
// Minimum is the minimum numeric value
Minimum *float64
// Maximum is the maximum numeric value
Maximum *float64
// MinLength is the minimum string length
MinLength *int
// MaxLength is the maximum string length
MaxLength *int
// Pattern is a regex pattern for string validation
Pattern string
// Format is a semantic format (e.g., "email", "uri", "date-time")
Format string
// Ref is a JSON Pointer reference to another schema ($ref)
Ref string
// Defs contains schema definitions ($defs)
Defs map[string]*JSONSchema
// AdditionalProperties controls whether extra properties are allowed
AdditionalProperties *bool
// AnyOf allows any of the listed schemas
AnyOf []*JSONSchema
// OneOf requires exactly one of the listed schemas
OneOf []*JSONSchema
// AllOf requires all of the listed schemas
AllOf []*JSONSchema
// Not disallows the specified schema
Not *JSONSchema
}
JSONSchema represents a JSON Schema definition. It is a superset supporting features from MCP, OpenAI, and Anthropic formats.
func (*JSONSchema) DeepCopy ¶
func (s *JSONSchema) DeepCopy() *JSONSchema
DeepCopy creates a deep copy of the JSONSchema. Returns nil if the receiver is nil.
func (*JSONSchema) ToMap ¶
func (s *JSONSchema) ToMap() map[string]any
ToMap converts the JSONSchema to a map[string]any representation. Zero-valued fields are omitted from the output.
type MCPAdapter ¶ added in v0.2.0
type MCPAdapter struct{}
MCPAdapter converts between model.Tool and CanonicalTool. MCP supports all JSON Schema 2020-12 features.
func NewMCPAdapter ¶ added in v0.2.0
func NewMCPAdapter() *MCPAdapter
NewMCPAdapter creates a new MCP adapter.
func (*MCPAdapter) FromCanonical ¶ added in v0.2.0
func (a *MCPAdapter) FromCanonical(ct *CanonicalTool) (any, error)
FromCanonical converts a canonical tool to model.Tool.
func (*MCPAdapter) Name ¶ added in v0.2.0
func (a *MCPAdapter) Name() string
Name returns the adapter's identifier.
func (*MCPAdapter) SupportsFeature ¶ added in v0.2.0
func (a *MCPAdapter) SupportsFeature(feature SchemaFeature) bool
SupportsFeature returns whether this adapter supports a schema feature. MCP supports all JSON Schema 2020-12 features.
Example ¶
package main
import (
"fmt"
"github.com/jonwraymond/toolfoundation/adapter"
)
func main() {
mcp := adapter.NewMCPAdapter()
openai := adapter.NewOpenAIAdapter()
// MCP supports all JSON Schema features
fmt.Println("MCP supports $ref:", mcp.SupportsFeature(adapter.FeatureRef))
fmt.Println("MCP supports anyOf:", mcp.SupportsFeature(adapter.FeatureAnyOf))
// OpenAI has limited support
fmt.Println("OpenAI supports $ref:", openai.SupportsFeature(adapter.FeatureRef))
fmt.Println("OpenAI supports anyOf:", openai.SupportsFeature(adapter.FeatureAnyOf))
}
Output: MCP supports $ref: true MCP supports anyOf: true OpenAI supports $ref: false OpenAI supports anyOf: false
func (*MCPAdapter) ToCanonical ¶ added in v0.2.0
func (a *MCPAdapter) ToCanonical(raw any) (*CanonicalTool, error)
ToCanonical converts an MCP tool to the canonical format. Accepts *model.Tool, model.Tool, *mcp.Tool, or mcp.Tool.
type OpenAIAdapter ¶ added in v0.2.0
type OpenAIAdapter struct{}
OpenAIAdapter converts between OpenAI function format and CanonicalTool.
func NewOpenAIAdapter ¶ added in v0.2.0
func NewOpenAIAdapter() *OpenAIAdapter
NewOpenAIAdapter creates a new OpenAI adapter.
func (*OpenAIAdapter) FromCanonical ¶ added in v0.2.0
func (a *OpenAIAdapter) FromCanonical(ct *CanonicalTool) (any, error)
FromCanonical converts a canonical tool to OpenAI format. Returns *OpenAITool.
func (*OpenAIAdapter) Name ¶ added in v0.2.0
func (a *OpenAIAdapter) Name() string
Name returns the adapter's identifier.
func (*OpenAIAdapter) SupportsFeature ¶ added in v0.2.0
func (a *OpenAIAdapter) SupportsFeature(feature SchemaFeature) bool
SupportsFeature returns whether this adapter supports a schema feature.
func (*OpenAIAdapter) ToCanonical ¶ added in v0.2.0
func (a *OpenAIAdapter) ToCanonical(raw any) (*CanonicalTool, error)
ToCanonical converts an OpenAI tool to the canonical format. Accepts *OpenAITool, OpenAITool, *OpenAIFunction, or OpenAIFunction.
type OpenAIFunction ¶ added in v0.2.0
type OpenAIFunction struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Parameters map[string]any `json:"parameters"`
Strict *bool `json:"strict,omitempty"`
}
OpenAIFunction represents the OpenAI function calling format. Based on OpenAI API spec - defined locally to avoid SDK coupling.
type OpenAITool ¶ added in v0.2.0
type OpenAITool struct {
Type string `json:"type"` // always "function"
Function OpenAIFunction `json:"function"`
}
OpenAITool wraps a function for the tools array format.
Example ¶
package main
import (
"encoding/json"
"fmt"
"github.com/jonwraymond/toolfoundation/adapter"
)
func main() {
openaiTool := &adapter.OpenAITool{
Type: "function",
Function: adapter.OpenAIFunction{
Name: "calculate",
Description: "Perform a calculation",
Parameters: map[string]any{
"type": "object",
"properties": map[string]any{
"expression": map[string]any{"type": "string"},
},
"required": []string{"expression"},
},
},
}
// Serialize to JSON for API request
data, _ := json.MarshalIndent(openaiTool, "", " ")
fmt.Println(string(data))
}
Output: { "type": "function", "function": { "name": "calculate", "description": "Perform a calculation", "parameters": { "properties": { "expression": { "type": "string" } }, "required": [ "expression" ], "type": "object" } } }
type SchemaFeature ¶
type SchemaFeature int
SchemaFeature represents a JSON Schema feature that may or may not be supported by a particular protocol adapter.
const ( // FeatureRef is the $ref keyword for schema references FeatureRef SchemaFeature = iota // FeatureDefs is the $defs keyword for schema definitions FeatureDefs // FeatureAnyOf allows any of the listed schemas FeatureAnyOf // FeatureOneOf requires exactly one of the listed schemas FeatureOneOf // FeatureAllOf requires all of the listed schemas FeatureAllOf // FeatureNot disallows the specified schema FeatureNot // FeaturePattern is regex pattern validation FeaturePattern // FeatureFormat is semantic format validation FeatureFormat // FeatureAdditionalProperties controls extra property handling FeatureAdditionalProperties // FeatureMinimum is minimum numeric value FeatureMinimum // FeatureMaximum is maximum numeric value FeatureMaximum // FeatureMinLength is minimum string length FeatureMinLength // FeatureMaxLength is maximum string length FeatureMaxLength // FeatureEnum restricts to a set of values FeatureEnum // FeatureConst restricts to a single value FeatureConst // FeatureDefault provides a default value FeatureDefault )
func AllFeatures ¶
func AllFeatures() []SchemaFeature
AllFeatures returns all known schema features in a stable order.
func (SchemaFeature) String ¶
func (f SchemaFeature) String() string
String returns the JSON Schema keyword name for this feature.