wire

package
v0.1.5 Latest Latest
Warning

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

Go to latest
Published: Feb 2, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package wire provides multi-protocol wire format adapters for tool communication.

It enables encoding and decoding of tool requests and responses across different protocols including MCP (Anthropic), A2A (Google), and ACP (IBM).

Ecosystem Position

wire sits at the protocol boundary, translating between internal representations and protocol-specific wire formats:

┌─────────────────────────────────────────────────────────────────┐
│                    Protocol Translation Flow                    │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   External Client          wire               Internal          │
│   ┌───────────┐         ┌─────────┐         ┌─────────┐        │
│   │ MCP/A2A/  │─────────│ Decode  │─────────│ Request │        │
│   │ ACP JSON  │         │         │         │ struct  │        │
│   └───────────┘         │ ┌─────┐ │         └─────────┘        │
│        ▲                │ │Wire │ │              │              │
│        │                │ │ Impl│ │              ▼              │
│        │                │ └─────┘ │         ┌─────────┐        │
│   ┌───────────┐         │         │         │ Execute │        │
│   │ MCP/A2A/  │◀────────│ Encode  │◀────────│  Tool   │        │
│   │ ACP JSON  │         │         │         │         │        │
│   └───────────┘         └─────────┘         └─────────┘        │
│                              │                                  │
│                         ┌────┴────┐                            │
│                         │Registry │                            │
│                         │ (lookup)│                            │
│                         └─────────┘                            │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Core Components

  • Wire: Interface for protocol-specific encoding/decoding
  • MCPWire: Model Context Protocol (Anthropic) - JSON-RPC 2.0 based
  • A2AWire: Agent-to-Agent Protocol (Google) - JSON-RPC with artifacts
  • ACPWire: Agent Communication Protocol (IBM) - JSON-RPC with agents
  • Registry: Thread-safe registry of wire format handlers
  • DefaultRegistry: Pre-configured registry with all standard formats

Quick Start

// Use default registry for standard protocols
reg := wire.DefaultRegistry()
w := reg.Get("mcp")

// Encode a request
req := &wire.Request{
    ID:     "1",
    Method: "tools/call",
    ToolID: "search",
    Arguments: map[string]any{"query": "golang"},
}
data, err := w.EncodeRequest(ctx, req)

// Decode a response
resp, err := w.DecodeResponse(ctx, responseData)

Available Formats

MCP (Model Context Protocol):

  • Version: 2025-11-25
  • Streaming: Yes
  • Batch requests: No
  • Progress notifications: Yes
  • Cancellation: Yes

A2A (Agent-to-Agent Protocol):

  • Version: 0.2.1
  • Streaming: Yes
  • Batch requests: No
  • Progress notifications: Yes
  • Cancellation: Yes

ACP (Agent Communication Protocol):

  • Version: 1.0.0
  • Streaming: No
  • Batch requests: Yes
  • Progress notifications: No
  • Cancellation: Yes

Thread Safety

All exported types are safe for concurrent use:

Error Handling

Sentinel errors (use errors.Is for checking):

Encode/Decode methods wrap underlying errors with context:

resp, err := w.DecodeResponse(ctx, data)
if err != nil {
    // err contains: "decode response: <underlying error>"
}

Integration with ApertureStack

wire integrates with other ApertureStack packages:

  • transport: Uses wire for protocol-specific message encoding
  • stream: Streaming responses use wire for event encoding
  • discover: Tool lists encoded via EncodeToolList/DecodeToolList
  • content: Response content types map to wire.Content

Index

Examples

Constants

View Source
const A2AVersion = "0.2.1"

A2AVersion is the A2A protocol version.

View Source
const ACPVersion = "1.0.0"

ACPVersion is the ACP protocol version.

View Source
const MCPVersion = "2025-11-25"

MCPVersion is the MCP specification version.

Variables

View Source
var (
	// ErrUnsupportedFormat is returned when an unknown wire format is requested.
	ErrUnsupportedFormat = errors.New("wire: unsupported format")

	// ErrEncodeFailure is returned when encoding fails.
	ErrEncodeFailure = errors.New("wire: encode failed")

	// ErrDecodeFailure is returned when decoding fails.
	ErrDecodeFailure = errors.New("wire: decode failed")
)

Sentinel errors for wire operations. All errors use the "wire: " prefix for consistent error identification.

Functions

This section is empty.

Types

type A2AWire

type A2AWire struct{}

A2AWire implements Wire for Google's Agent-to-Agent protocol.

func NewA2A

func NewA2A() *A2AWire

NewA2A creates a new A2A wire format handler.

Example
package main

import (
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	w := wire.NewA2A()

	fmt.Println("Name:", w.Name())
	fmt.Println("Version:", w.Version())
}
Output:
Name: a2a
Version: 0.2.1

func (*A2AWire) Capabilities

func (w *A2AWire) Capabilities() *Capabilities

Capabilities returns A2A protocol capabilities.

Example
package main

import (
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	w := wire.NewA2A()
	caps := w.Capabilities()

	fmt.Println("Streaming:", caps.Streaming)
	fmt.Println("BatchRequests:", caps.BatchRequests)
	fmt.Println("Progress:", caps.Progress)
	fmt.Println("Cancellation:", caps.Cancellation)
}
Output:
Streaming: true
BatchRequests: false
Progress: true
Cancellation: true

func (*A2AWire) DecodeRequest

func (w *A2AWire) DecodeRequest(ctx context.Context, data []byte) (*Request, error)

DecodeRequest decodes A2A format to a Request.

func (*A2AWire) DecodeResponse

func (w *A2AWire) DecodeResponse(ctx context.Context, data []byte) (*Response, error)

DecodeResponse decodes A2A format to a Response.

func (*A2AWire) DecodeToolList

func (w *A2AWire) DecodeToolList(ctx context.Context, data []byte) ([]Tool, error)

DecodeToolList decodes A2A format to a tool list.

func (*A2AWire) EncodeRequest

func (w *A2AWire) EncodeRequest(ctx context.Context, req *Request) ([]byte, error)

EncodeRequest encodes a Request to A2A format.

func (*A2AWire) EncodeResponse

func (w *A2AWire) EncodeResponse(ctx context.Context, resp *Response) ([]byte, error)

EncodeResponse encodes a Response to A2A format.

func (*A2AWire) EncodeToolList

func (w *A2AWire) EncodeToolList(ctx context.Context, tools []Tool) ([]byte, error)

EncodeToolList encodes a tool list to A2A format.

func (*A2AWire) Name

func (w *A2AWire) Name() string

Name returns "a2a".

func (*A2AWire) Version

func (w *A2AWire) Version() string

Version returns the A2A spec version.

type ACPWire

type ACPWire struct{}

ACPWire implements Wire for IBM's Agent Communication Protocol.

func NewACP

func NewACP() *ACPWire

NewACP creates a new ACP wire format handler.

Example
package main

import (
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	w := wire.NewACP()

	fmt.Println("Name:", w.Name())
	fmt.Println("Version:", w.Version())
}
Output:
Name: acp
Version: 1.0.0

func (*ACPWire) Capabilities

func (w *ACPWire) Capabilities() *Capabilities

Capabilities returns ACP protocol capabilities.

Example
package main

import (
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	w := wire.NewACP()
	caps := w.Capabilities()

	fmt.Println("Streaming:", caps.Streaming)
	fmt.Println("BatchRequests:", caps.BatchRequests)
	fmt.Println("Progress:", caps.Progress)
	fmt.Println("Cancellation:", caps.Cancellation)
}
Output:
Streaming: false
BatchRequests: true
Progress: false
Cancellation: true

func (*ACPWire) DecodeRequest

func (w *ACPWire) DecodeRequest(ctx context.Context, data []byte) (*Request, error)

DecodeRequest decodes ACP format to a Request.

func (*ACPWire) DecodeResponse

func (w *ACPWire) DecodeResponse(ctx context.Context, data []byte) (*Response, error)

DecodeResponse decodes ACP format to a Response.

func (*ACPWire) DecodeToolList

func (w *ACPWire) DecodeToolList(ctx context.Context, data []byte) ([]Tool, error)

DecodeToolList decodes ACP format to a tool list.

func (*ACPWire) EncodeRequest

func (w *ACPWire) EncodeRequest(ctx context.Context, req *Request) ([]byte, error)

EncodeRequest encodes a Request to ACP format.

func (*ACPWire) EncodeResponse

func (w *ACPWire) EncodeResponse(ctx context.Context, resp *Response) ([]byte, error)

EncodeResponse encodes a Response to ACP format.

func (*ACPWire) EncodeToolList

func (w *ACPWire) EncodeToolList(ctx context.Context, tools []Tool) ([]byte, error)

EncodeToolList encodes a tool list to ACP format.

func (*ACPWire) Name

func (w *ACPWire) Name() string

Name returns "acp".

func (*ACPWire) Version

func (w *ACPWire) Version() string

Version returns the ACP spec version.

type Capabilities

type Capabilities struct {
	// Streaming indicates support for streaming responses.
	Streaming bool

	// BatchRequests indicates support for batched requests.
	BatchRequests bool

	// Progress indicates support for progress notifications.
	Progress bool

	// Cancellation indicates support for request cancellation.
	Cancellation bool
}

Capabilities describes protocol features.

type Content

type Content struct {
	// Type identifies the content type.
	Type ContentType

	// Text is the text content (for ContentTypeText).
	Text string

	// MIMEType is the MIME type (for images and resources).
	MIMEType string

	// Data is binary data (for images).
	Data []byte

	// URI is the resource URI (for ContentTypeResource).
	URI string
}

Content represents a piece of response content.

type ContentType

type ContentType string

ContentType identifies the type of content in a response.

const (
	// ContentTypeText is plain text content.
	ContentTypeText ContentType = "text"

	// ContentTypeImage is image data.
	ContentTypeImage ContentType = "image"

	// ContentTypeResource is a resource reference.
	ContentTypeResource ContentType = "resource"
)

type Error

type Error struct {
	// Code is the error code (JSON-RPC style).
	Code int

	// Message is a human-readable error message.
	Message string

	// Data contains additional error details.
	Data any
}

Error represents a wire protocol error.

func (*Error) Error

func (e *Error) Error() string

Error implements the error interface.

Example
package main

import (
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	err := &wire.Error{
		Code:    -32600,
		Message: "Invalid Request",
	}

	fmt.Println(err.Error())
}
Output:
Invalid Request (code: -32600)
Example (WithData)
package main

import (
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	err := &wire.Error{
		Code:    -32602,
		Message: "Invalid params",
		Data:    "missing required field: query",
	}

	fmt.Println(err.Error())
}
Output:
Invalid params (code: -32602, data: missing required field: query)

type MCPWire

type MCPWire struct{}

MCPWire implements Wire for the Model Context Protocol.

func NewMCP

func NewMCP() *MCPWire

NewMCP creates a new MCP wire format handler.

Example
package main

import (
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	w := wire.NewMCP()

	fmt.Println("Name:", w.Name())
	fmt.Println("Version:", w.Version())
}
Output:
Name: mcp
Version: 2025-11-25

func (*MCPWire) Capabilities

func (w *MCPWire) Capabilities() *Capabilities

Capabilities returns MCP protocol capabilities.

Example
package main

import (
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	w := wire.NewMCP()
	caps := w.Capabilities()

	fmt.Println("Streaming:", caps.Streaming)
	fmt.Println("BatchRequests:", caps.BatchRequests)
	fmt.Println("Progress:", caps.Progress)
	fmt.Println("Cancellation:", caps.Cancellation)
}
Output:
Streaming: true
BatchRequests: false
Progress: true
Cancellation: true

func (*MCPWire) DecodeRequest

func (w *MCPWire) DecodeRequest(ctx context.Context, data []byte) (*Request, error)

DecodeRequest decodes MCP JSON-RPC format to a Request.

Example
package main

import (
	"context"
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	w := wire.NewMCP()
	ctx := context.Background()

	// JSON-RPC 2.0 request
	data := []byte(`{
		"jsonrpc": "2.0",
		"id": "req-1",
		"method": "tools/call",
		"params": {
			"name": "search",
			"arguments": {"query": "test"}
		}
	}`)

	req, err := w.DecodeRequest(ctx, data)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	fmt.Println("ID:", req.ID)
	fmt.Println("Method:", req.Method)
	fmt.Println("ToolID:", req.ToolID)
	fmt.Println("Query:", req.Arguments["query"])
}
Output:
ID: req-1
Method: tools/call
ToolID: search
Query: test

func (*MCPWire) DecodeResponse

func (w *MCPWire) DecodeResponse(ctx context.Context, data []byte) (*Response, error)

DecodeResponse decodes MCP JSON-RPC format to a Response.

Example
package main

import (
	"context"
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	w := wire.NewMCP()
	ctx := context.Background()

	// JSON-RPC 2.0 response
	data := []byte(`{
		"jsonrpc": "2.0",
		"id": "req-1",
		"result": {
			"content": [
				{"type": "text", "text": "Search results found"}
			]
		}
	}`)

	resp, err := w.DecodeResponse(ctx, data)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	fmt.Println("ID:", resp.ID)
	fmt.Println("IsError:", resp.IsError)
	fmt.Println("Content count:", len(resp.Content))
	fmt.Println("Text:", resp.Content[0].Text)
}
Output:
ID: req-1
IsError: false
Content count: 1
Text: Search results found
Example (Error)
package main

import (
	"context"
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	w := wire.NewMCP()
	ctx := context.Background()

	// JSON-RPC 2.0 error response
	data := []byte(`{
		"jsonrpc": "2.0",
		"id": "req-1",
		"error": {
			"code": -32600,
			"message": "Invalid Request"
		}
	}`)

	resp, err := w.DecodeResponse(ctx, data)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	fmt.Println("ID:", resp.ID)
	fmt.Println("IsError:", resp.IsError)
	fmt.Println("Error code:", resp.Error.Code)
	fmt.Println("Error message:", resp.Error.Message)
}
Output:
ID: req-1
IsError: true
Error code: -32600
Error message: Invalid Request

func (*MCPWire) DecodeToolList

func (w *MCPWire) DecodeToolList(ctx context.Context, data []byte) ([]Tool, error)

DecodeToolList decodes MCP format to a tool list.

Example
package main

import (
	"context"
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	w := wire.NewMCP()
	ctx := context.Background()

	data := []byte(`{
		"tools": [
			{
				"name": "search",
				"description": "Search the web",
				"inputSchema": {"type": "object"}
			}
		]
	}`)

	tools, err := w.DecodeToolList(ctx, data)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	fmt.Println("Tool count:", len(tools))
	fmt.Println("Tool name:", tools[0].Name)
	fmt.Println("Tool description:", tools[0].Description)
}
Output:
Tool count: 1
Tool name: search
Tool description: Search the web

func (*MCPWire) EncodeRequest

func (w *MCPWire) EncodeRequest(ctx context.Context, req *Request) ([]byte, error)

EncodeRequest encodes a Request to MCP JSON-RPC format.

Example
package main

import (
	"context"
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	w := wire.NewMCP()
	ctx := context.Background()

	req := &wire.Request{
		ID:     "req-1",
		Method: "tools/call",
		ToolID: "search",
		Arguments: map[string]any{
			"query": "golang tutorials",
		},
	}

	data, err := w.EncodeRequest(ctx, req)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	// Output is JSON-RPC 2.0 format
	fmt.Println("Encoded successfully:", len(data) > 0)
}
Output:
Encoded successfully: true

func (*MCPWire) EncodeResponse

func (w *MCPWire) EncodeResponse(ctx context.Context, resp *Response) ([]byte, error)

EncodeResponse encodes a Response to MCP JSON-RPC format.

Example
package main

import (
	"context"
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	w := wire.NewMCP()
	ctx := context.Background()

	resp := &wire.Response{
		ID: "req-1",
		Content: []wire.Content{
			{Type: wire.ContentTypeText, Text: "Hello, world!"},
		},
	}

	data, err := w.EncodeResponse(ctx, resp)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	fmt.Println("Encoded successfully:", len(data) > 0)
}
Output:
Encoded successfully: true

func (*MCPWire) EncodeToolList

func (w *MCPWire) EncodeToolList(ctx context.Context, tools []Tool) ([]byte, error)

EncodeToolList encodes a tool list to MCP format.

Example
package main

import (
	"context"
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	w := wire.NewMCP()
	ctx := context.Background()

	tools := []wire.Tool{
		{
			Name:        "search",
			Description: "Search the web",
			InputSchema: map[string]any{
				"type": "object",
				"properties": map[string]any{
					"query": map[string]any{"type": "string"},
				},
			},
		},
	}

	data, err := w.EncodeToolList(ctx, tools)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	fmt.Println("Encoded successfully:", len(data) > 0)
}
Output:
Encoded successfully: true

func (*MCPWire) Name

func (w *MCPWire) Name() string

Name returns "mcp".

func (*MCPWire) Version

func (w *MCPWire) Version() string

Version returns the MCP spec version.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry manages wire format handlers.

Contract:

  • Concurrency: All methods are safe for concurrent use via sync.RWMutex.
  • Registration: Register replaces existing handlers with the same name.
  • Lookup: Get returns nil for unknown format names (no error).
  • Ownership: Wire implementations are shared; do not modify after registration.

func DefaultRegistry

func DefaultRegistry() *Registry

DefaultRegistry returns the default wire format registry.

Example
package main

import (
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	reg := wire.DefaultRegistry()

	// Default registry has mcp, a2a, and acp pre-registered
	mcp := reg.Get("mcp")
	a2a := reg.Get("a2a")
	acp := reg.Get("acp")

	fmt.Println("Has mcp:", mcp != nil)
	fmt.Println("Has a2a:", a2a != nil)
	fmt.Println("Has acp:", acp != nil)
}
Output:
Has mcp: true
Has a2a: true
Has acp: true

func NewRegistry

func NewRegistry() *Registry

NewRegistry creates a new empty registry.

Example
package main

import (
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	reg := wire.NewRegistry()

	// Register a custom wire format
	reg.Register("mcp", wire.NewMCP())

	// List registered formats
	names := reg.List()
	fmt.Println("Registered:", len(names) > 0)
}
Output:
Registered: true

func (*Registry) Get

func (r *Registry) Get(name string) Wire

Get returns the wire handler for the given format name, or nil if not found.

Example
package main

import (
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	reg := wire.NewRegistry()
	reg.Register("mcp", wire.NewMCP())

	// Get existing format
	w := reg.Get("mcp")
	fmt.Println("Found mcp:", w != nil)
	fmt.Println("Name:", w.Name())

	// Get non-existent format
	missing := reg.Get("unknown")
	fmt.Println("Found unknown:", missing != nil)
}
Output:
Found mcp: true
Name: mcp
Found unknown: false

func (*Registry) List

func (r *Registry) List() []string

List returns the names of all registered wire formats.

Example
package main

import (
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	reg := wire.NewRegistry()
	reg.Register("mcp", wire.NewMCP())
	reg.Register("a2a", wire.NewA2A())

	names := reg.List()
	fmt.Println("Count:", len(names))
}
Output:
Count: 2

func (*Registry) Register

func (r *Registry) Register(name string, wire Wire)

Register adds a wire format handler to the registry. If a handler with the same name exists, it is replaced.

Example
package main

import (
	"fmt"

	"github.com/jonwraymond/toolprotocol/wire"
)

func main() {
	reg := wire.NewRegistry()

	// Register formats
	reg.Register("mcp", wire.NewMCP())
	reg.Register("a2a", wire.NewA2A())
	reg.Register("acp", wire.NewACP())

	fmt.Println("Registered count:", len(reg.List()))
}
Output:
Registered count: 3

type Request

type Request struct {
	// ID is the request identifier.
	ID string

	// Method is the RPC method (e.g., "tools/call", "tools/list").
	Method string

	// ToolID is the tool to invoke.
	ToolID string

	// Arguments are the tool input parameters.
	Arguments map[string]any

	// Meta contains protocol-specific metadata.
	Meta map[string]any
}

Request represents a tool invocation request.

type Response

type Response struct {
	// ID is the request identifier this responds to.
	ID string

	// Content is the response payload.
	Content []Content

	// IsError indicates if this is an error response.
	IsError bool

	// Error contains error details when IsError is true.
	Error *Error

	// Meta contains protocol-specific metadata.
	Meta map[string]any
}

Response represents a tool invocation response.

type Tool

type Tool struct {
	// Name is the tool identifier.
	Name string

	// Description explains what the tool does.
	Description string

	// InputSchema is the JSON Schema for tool arguments.
	InputSchema map[string]any
}

Tool describes a tool's interface.

type Wire

type Wire interface {
	// Name returns the protocol name (e.g., "mcp", "a2a", "acp").
	Name() string

	// Version returns the protocol version.
	Version() string

	// EncodeRequest encodes a request to wire format.
	EncodeRequest(ctx context.Context, req *Request) ([]byte, error)

	// DecodeRequest decodes a request from wire format.
	DecodeRequest(ctx context.Context, data []byte) (*Request, error)

	// EncodeResponse encodes a response to wire format.
	EncodeResponse(ctx context.Context, resp *Response) ([]byte, error)

	// DecodeResponse decodes a response from wire format.
	DecodeResponse(ctx context.Context, data []byte) (*Response, error)

	// EncodeToolList encodes a list of tools to wire format.
	EncodeToolList(ctx context.Context, tools []Tool) ([]byte, error)

	// DecodeToolList decodes a list of tools from wire format.
	DecodeToolList(ctx context.Context, data []byte) ([]Tool, error)

	// Capabilities returns the protocol capabilities.
	Capabilities() *Capabilities
}

Wire encodes/decodes protocol-specific wire formats.

Contract:

  • Concurrency: All implementations are safe for concurrent use. MCPWire, A2AWire, and ACPWire are stateless and thread-safe.
  • Context: Encode/Decode methods accept context for future extensibility. Current implementations do not perform I/O and ignore context.
  • Errors: Returns wrapped errors with context (e.g., "decode request: ..."). Use errors.Is/errors.As for error inspection.
  • Ownership: Input data is not modified. Output []byte is owned by caller.
  • Nil safety: Passing nil *Request or *Response to Encode methods will panic.

Jump to

Keyboard shortcuts

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