reconcile: carry MCP<->ZAP bridge onto refactored main

WIP main was an orphaned old base; remote main is the canonical refactor and
already contains the WIP intent, advanced further: PQ handshake (bigger
handshake/), the full transport/ suite WITH C kernels (dpdk_pmd/gpudirect_rdma/
uma_cuda) and QUIC (quic-go in go.mod), plus larger node.go/zap.go. All 15
modified source files + go.mod/go.sum in the WIP were the older base and are
superseded (accept remote). LLM.md/MIGRATION.md: remote canonical, no unique
local notes to fold. The 416 mdns/rust/target/* build artifacts the WIP had
committed are dropped (compiled output, never committed).

Genuinely-new, ported: mcp/ package (MCP<->ZAP bridge for fast tool calling),
absent from remote. Builds clean against the refactored zap API (go build
./... OK).

Full WIP preserved on branch wip/local + tag backup/pre-reconcile-main.
This commit is contained in:
hanzo-dev
2026-06-20 18:37:21 +00:00
parent 2ba428c21b
commit 32407342ec
2 changed files with 689 additions and 0 deletions
+466
View File
@@ -0,0 +1,466 @@
// Copyright (C) 2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
// Package mcp provides a bridge between MCP (Model Context Protocol) servers
// and ZAP for high-performance tool calling.
//
// This bridge auto-discovers MCP servers and exposes their capabilities via ZAP,
// providing 10-30x performance improvement over native MCP JSON-RPC.
package mcp
import (
"bufio"
"context"
"encoding/json"
"fmt"
"io"
"os"
"os/exec"
"sync"
"github.com/luxfi/zap"
)
// Message types for MCP-ZAP bridge
const (
MsgTypeToolList uint16 = 100 // List available tools
MsgTypeToolCall uint16 = 101 // Call a tool
MsgTypeToolResult uint16 = 102 // Tool result
// Field offsets
FieldToolCount = 0 // uint32 - number of tools
FieldToolID = 0 // uint32 - tool ID
FieldToolName = 4 // 64 bytes - tool name
FieldArgsLen = 68 // uint32 - arguments JSON length
FieldArgs = 72 // bytes - arguments JSON
FieldResultLen = 0 // uint32 - result length
FieldResultData = 4 // bytes - result data
)
// Tool represents an MCP tool capability
type Tool struct {
ID uint32 `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
InputSchema map[string]interface{} `json:"inputSchema"`
}
// MCPServer represents a connection to an MCP server
type MCPServer struct {
Name string
Command string
Args []string
Tools []Tool
cmd *exec.Cmd
stdin io.WriteCloser
stdout *bufio.Reader
mu sync.Mutex
reqID int
}
// Bridge manages multiple MCP servers and exposes them via ZAP
type Bridge struct {
node *zap.Node
servers map[string]*MCPServer
tools map[uint32]*Tool // toolID -> tool
toolMCP map[uint32]*MCPServer // toolID -> server
mu sync.RWMutex
nextID uint32
}
// NewBridge creates a new MCP-ZAP bridge
func NewBridge(node *zap.Node) *Bridge {
b := &Bridge{
node: node,
servers: make(map[string]*MCPServer),
tools: make(map[uint32]*Tool),
toolMCP: make(map[uint32]*MCPServer),
nextID: 1,
}
// Register handlers
node.Handle(MsgTypeToolList, b.handleToolList)
node.Handle(MsgTypeToolCall, b.handleToolCall)
return b
}
// AddServer adds and starts an MCP server
func (b *Bridge) AddServer(name, command string, args ...string) error {
server := &MCPServer{
Name: name,
Command: command,
Args: args,
}
// Start the MCP server process
if err := server.Start(); err != nil {
return fmt.Errorf("failed to start MCP server %s: %w", name, err)
}
// Discover tools
tools, err := server.ListTools()
if err != nil {
server.Stop()
return fmt.Errorf("failed to list tools from %s: %w", name, err)
}
b.mu.Lock()
defer b.mu.Unlock()
// Assign IDs and register tools
for i := range tools {
tools[i].ID = b.nextID
b.nextID++
b.tools[tools[i].ID] = &tools[i]
b.toolMCP[tools[i].ID] = server
}
server.Tools = tools
b.servers[name] = server
return nil
}
// AddServerConfig adds a server from a config
func (b *Bridge) AddServerConfig(cfg ServerConfig) error {
return b.AddServer(cfg.Name, cfg.Command, cfg.Args...)
}
// ServerConfig configures an MCP server
type ServerConfig struct {
Name string `json:"name"`
Command string `json:"command"`
Args []string `json:"args"`
Env []string `json:"env,omitempty"`
}
// GetTools returns all registered tools
func (b *Bridge) GetTools() []Tool {
b.mu.RLock()
defer b.mu.RUnlock()
tools := make([]Tool, 0, len(b.tools))
for _, t := range b.tools {
tools = append(tools, *t)
}
return tools
}
// CallTool calls a tool by ID
func (b *Bridge) CallTool(ctx context.Context, toolID uint32, args map[string]interface{}) (interface{}, error) {
b.mu.RLock()
tool, ok := b.tools[toolID]
server := b.toolMCP[toolID]
b.mu.RUnlock()
if !ok {
return nil, fmt.Errorf("tool not found: %d", toolID)
}
return server.CallTool(tool.Name, args)
}
// CallToolByName calls a tool by name
func (b *Bridge) CallToolByName(ctx context.Context, name string, args map[string]interface{}) (interface{}, error) {
b.mu.RLock()
var tool *Tool
var server *MCPServer
for _, t := range b.tools {
if t.Name == name {
tool = t
server = b.toolMCP[t.ID]
break
}
}
b.mu.RUnlock()
if tool == nil {
return nil, fmt.Errorf("tool not found: %s", name)
}
return server.CallTool(name, args)
}
// handleToolList returns all available tools
func (b *Bridge) handleToolList(ctx context.Context, from string, msg *zap.Message) (*zap.Message, error) {
tools := b.GetTools()
// Build response with tool list
builder := zap.NewBuilder(1024)
obj := builder.StartObject(512)
obj.SetUint32(FieldToolCount, uint32(len(tools)))
// Encode tools as JSON in the message (for simplicity)
toolsJSON, _ := json.Marshal(tools)
for i, c := range toolsJSON {
if i >= 500 {
break
}
obj.SetUint8(4+i, c)
}
obj.FinishAsRoot()
resp, _ := zap.Parse(builder.FinishWithFlags(MsgTypeToolList << 8))
return resp, nil
}
// handleToolCall handles a tool call request
func (b *Bridge) handleToolCall(ctx context.Context, from string, msg *zap.Message) (*zap.Message, error) {
root := msg.Root()
toolID := root.Uint32(FieldToolID)
// Extract tool name
var toolName string
nameBytes := make([]byte, 64)
for i := 0; i < 64; i++ {
c := root.Uint8(FieldToolName + i)
if c == 0 {
toolName = string(nameBytes[:i])
break
}
nameBytes[i] = c
}
// Extract args JSON
argsLen := root.Uint32(FieldArgsLen)
argsBytes := make([]byte, argsLen)
for i := uint32(0); i < argsLen; i++ {
argsBytes[i] = root.Uint8(int(FieldArgs + int(i)))
}
var args map[string]interface{}
json.Unmarshal(argsBytes, &args)
// Call the tool
var result interface{}
var err error
if toolID > 0 {
result, err = b.CallTool(ctx, toolID, args)
} else {
result, err = b.CallToolByName(ctx, toolName, args)
}
// Build response
builder := zap.NewBuilder(4096)
obj := builder.StartObject(4000)
if err != nil {
errStr := err.Error()
obj.SetUint32(FieldResultLen, uint32(len(errStr)))
for i, c := range []byte(errStr) {
obj.SetUint8(FieldResultData+i, c)
}
} else {
resultJSON, _ := json.Marshal(result)
obj.SetUint32(FieldResultLen, uint32(len(resultJSON)))
for i, c := range resultJSON {
if i >= 3900 {
break
}
obj.SetUint8(FieldResultData+i, c)
}
}
obj.FinishAsRoot()
resp, _ := zap.Parse(builder.FinishWithFlags(MsgTypeToolResult << 8))
return resp, nil
}
// Stop stops all MCP servers
func (b *Bridge) Stop() {
b.mu.Lock()
defer b.mu.Unlock()
for _, server := range b.servers {
server.Stop()
}
}
// ============================================================================
// MCP Server Process Management
// ============================================================================
// Start starts the MCP server process
func (s *MCPServer) Start() error {
s.mu.Lock()
defer s.mu.Unlock()
s.cmd = exec.Command(s.Command, s.Args...)
s.cmd.Stderr = os.Stderr
var err error
s.stdin, err = s.cmd.StdinPipe()
if err != nil {
return err
}
stdout, err := s.cmd.StdoutPipe()
if err != nil {
return err
}
s.stdout = bufio.NewReader(stdout)
if err := s.cmd.Start(); err != nil {
return err
}
// Initialize MCP connection
return s.initialize()
}
// Stop stops the MCP server process
func (s *MCPServer) Stop() {
s.mu.Lock()
defer s.mu.Unlock()
if s.stdin != nil {
s.stdin.Close()
}
if s.cmd != nil && s.cmd.Process != nil {
s.cmd.Process.Kill()
}
}
// initialize performs MCP handshake
func (s *MCPServer) initialize() error {
// Send initialize request
req := map[string]interface{}{
"jsonrpc": "2.0",
"id": s.nextReqID(),
"method": "initialize",
"params": map[string]interface{}{
"protocolVersion": "2024-11-05",
"capabilities": map[string]interface{}{},
"clientInfo": map[string]interface{}{
"name": "zap-mcp-bridge",
"version": "1.0.0",
},
},
}
if _, err := s.call(req); err != nil {
return err
}
// Send initialized notification
notif := map[string]interface{}{
"jsonrpc": "2.0",
"method": "notifications/initialized",
}
return s.send(notif)
}
// ListTools discovers available tools from the MCP server
func (s *MCPServer) ListTools() ([]Tool, error) {
req := map[string]interface{}{
"jsonrpc": "2.0",
"id": s.nextReqID(),
"method": "tools/list",
}
resp, err := s.call(req)
if err != nil {
return nil, err
}
result, ok := resp["result"].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("invalid response")
}
toolsRaw, ok := result["tools"].([]interface{})
if !ok {
return nil, fmt.Errorf("no tools in response")
}
tools := make([]Tool, len(toolsRaw))
for i, t := range toolsRaw {
tm := t.(map[string]interface{})
tools[i] = Tool{
Name: tm["name"].(string),
Description: getString(tm, "description"),
}
if schema, ok := tm["inputSchema"].(map[string]interface{}); ok {
tools[i].InputSchema = schema
}
}
return tools, nil
}
// CallTool calls a tool on the MCP server
func (s *MCPServer) CallTool(name string, args map[string]interface{}) (interface{}, error) {
req := map[string]interface{}{
"jsonrpc": "2.0",
"id": s.nextReqID(),
"method": "tools/call",
"params": map[string]interface{}{
"name": name,
"arguments": args,
},
}
resp, err := s.call(req)
if err != nil {
return nil, err
}
if errObj, ok := resp["error"].(map[string]interface{}); ok {
return nil, fmt.Errorf("MCP error: %v", errObj["message"])
}
return resp["result"], nil
}
func (s *MCPServer) call(req map[string]interface{}) (map[string]interface{}, error) {
s.mu.Lock()
defer s.mu.Unlock()
if err := s.sendLocked(req); err != nil {
return nil, err
}
return s.readLocked()
}
func (s *MCPServer) send(msg map[string]interface{}) error {
s.mu.Lock()
defer s.mu.Unlock()
return s.sendLocked(msg)
}
func (s *MCPServer) sendLocked(msg map[string]interface{}) error {
data, err := json.Marshal(msg)
if err != nil {
return err
}
_, err = fmt.Fprintf(s.stdin, "%s\n", data)
return err
}
func (s *MCPServer) readLocked() (map[string]interface{}, error) {
line, err := s.stdout.ReadString('\n')
if err != nil {
return nil, err
}
var resp map[string]interface{}
if err := json.Unmarshal([]byte(line), &resp); err != nil {
return nil, err
}
return resp, nil
}
func (s *MCPServer) nextReqID() int {
s.reqID++
return s.reqID
}
func getString(m map[string]interface{}, key string) string {
if v, ok := m[key].(string); ok {
return v
}
return ""
}
+223
View File
@@ -0,0 +1,223 @@
// Copyright (C) 2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package mcp
import (
"encoding/binary"
"encoding/json"
"testing"
"github.com/luxfi/zap"
)
// buildToolCallMessage builds a valid ZAP message representing an MCP tool call.
// The message has: toolID (uint32 at 0), toolName (64 bytes at 4), argsLen (uint32 at 68), args (bytes at 72).
func buildToolCallMessage(toolID uint32, toolName string, args map[string]interface{}) []byte {
b := zap.NewBuilder(4096)
// We need enough space: 72 (fixed fields before args) + argsJSON length
argsJSON, _ := json.Marshal(args)
objSize := FieldArgs + len(argsJSON)
// Align to 8
objSize = (objSize + 7) &^ 7
ob := b.StartObject(objSize)
ob.SetUint32(FieldToolID, toolID)
// Write tool name as fixed 64-byte field
nameBytes := []byte(toolName)
for i := 0; i < 64 && i < len(nameBytes); i++ {
ob.SetUint8(FieldToolName+i, nameBytes[i])
}
// Write args length and args bytes
ob.SetUint32(FieldArgsLen, uint32(len(argsJSON)))
for i, c := range argsJSON {
ob.SetUint8(FieldArgs+i, c)
}
ob.FinishAsRoot()
return b.Finish()
}
// buildToolResultMessage builds a valid ZAP message representing an MCP tool result.
// The message has: resultLen (uint32 at 0), resultData (bytes at 4).
func buildToolResultMessage(result interface{}) []byte {
b := zap.NewBuilder(4096)
resultJSON, _ := json.Marshal(result)
objSize := FieldResultData + len(resultJSON)
objSize = (objSize + 7) &^ 7
ob := b.StartObject(objSize)
ob.SetUint32(FieldResultLen, uint32(len(resultJSON)))
for i, c := range resultJSON {
ob.SetUint8(FieldResultData+i, c)
}
ob.FinishAsRoot()
return b.Finish()
}
// FuzzMCPBridgeToolCall parses arbitrary bytes as a ZAP-encoded MCP tool call
// message. Extracts toolID, toolName, and args JSON exactly as handleToolCall
// does. Must never panic.
func FuzzMCPBridgeToolCall(f *testing.F) {
// Seed 1: valid tool call
f.Add(buildToolCallMessage(1, "read_file", map[string]interface{}{
"path": "/tmp/test.txt",
}))
// Seed 2: tool call by name only (ID=0)
f.Add(buildToolCallMessage(0, "search", map[string]interface{}{
"query": "hello world",
"limit": 10,
}))
// Seed 3: empty args
f.Add(buildToolCallMessage(42, "list_tools", map[string]interface{}{}))
// Seed 4: long tool name (truncated to 64 bytes by builder)
f.Add(buildToolCallMessage(99, "this_is_a_very_long_tool_name_that_exceeds_the_64_byte_fixed_field_limit_in_the_protocol", map[string]interface{}{
"a": "b",
}))
// Seed 5: empty bytes
f.Add([]byte{})
// Seed 6: just a header
header := make([]byte, zap.HeaderSize)
copy(header[0:4], zap.Magic)
binary.LittleEndian.PutUint16(header[4:6], zap.Version)
binary.LittleEndian.PutUint32(header[12:16], zap.HeaderSize)
f.Add(header)
// Seed 7: nested JSON args with special characters
f.Add(buildToolCallMessage(5, "exec", map[string]interface{}{
"cmd": "echo 'hello\"world'",
"args": []string{"--flag", "-v"},
"env": map[string]interface{}{"PATH": "/usr/bin"},
"empty": nil,
}))
f.Fuzz(func(t *testing.T, data []byte) {
msg, err := zap.Parse(data)
if err != nil {
return // invalid ZAP message, that's fine
}
root := msg.Root()
// Extract tool ID -- same as handleToolCall
toolID := root.Uint32(FieldToolID)
_ = toolID
// Extract tool name from fixed 64-byte field
nameBytes := make([]byte, 64)
var toolName string
for i := 0; i < 64; i++ {
c := root.Uint8(FieldToolName + i)
if c == 0 {
toolName = string(nameBytes[:i])
break
}
nameBytes[i] = c
}
if toolName == "" && nameBytes[0] != 0 {
toolName = string(nameBytes)
}
_ = toolName
// Extract args JSON
argsLen := root.Uint32(FieldArgsLen)
// Cap to prevent OOM -- real handler would also need this
if argsLen > 1<<20 {
argsLen = 1 << 20
}
argsBytes := make([]byte, argsLen)
for i := uint32(0); i < argsLen; i++ {
argsBytes[i] = root.Uint8(int(FieldArgs + int(i)))
}
// Attempt JSON parse -- errors are fine, panics are not
var args map[string]interface{}
_ = json.Unmarshal(argsBytes, &args)
})
}
// FuzzMCPBridgeToolResult parses arbitrary bytes as a ZAP-encoded MCP tool
// result message. Extracts resultLen and resultData exactly as the bridge
// protocol defines. Must never panic.
func FuzzMCPBridgeToolResult(f *testing.F) {
// Seed 1: simple string result
f.Add(buildToolResultMessage("file contents here"))
// Seed 2: structured result
f.Add(buildToolResultMessage(map[string]interface{}{
"content": []map[string]interface{}{
{"type": "text", "text": "result data"},
},
"isError": false,
}))
// Seed 3: error result
f.Add(buildToolResultMessage(map[string]interface{}{
"error": "tool execution failed",
}))
// Seed 4: empty result
f.Add(buildToolResultMessage(nil))
// Seed 5: large result
bigData := make([]byte, 4000)
for i := range bigData {
bigData[i] = byte(i % 256)
}
f.Add(buildToolResultMessage(string(bigData)))
// Seed 6: empty bytes
f.Add([]byte{})
// Seed 7: just a header
header := make([]byte, zap.HeaderSize)
copy(header[0:4], zap.Magic)
binary.LittleEndian.PutUint16(header[4:6], zap.Version)
binary.LittleEndian.PutUint32(header[12:16], zap.HeaderSize)
f.Add(header)
f.Fuzz(func(t *testing.T, data []byte) {
msg, err := zap.Parse(data)
if err != nil {
return
}
root := msg.Root()
// Extract result length
resultLen := root.Uint32(FieldResultLen)
// Cap to prevent OOM
if resultLen > 1<<20 {
resultLen = 1 << 20
}
// Extract result data byte-by-byte, same as handleToolCall response pattern
resultBytes := make([]byte, resultLen)
for i := uint32(0); i < resultLen; i++ {
resultBytes[i] = root.Uint8(int(FieldResultData + int(i)))
}
// Attempt JSON parse
var result interface{}
_ = json.Unmarshal(resultBytes, &result)
// Also try as string
_ = string(resultBytes)
// Verify the message flags accessor doesn't panic
_ = msg.Flags()
})
}