Go Agent Examples

This guide provides complete, runnable examples for building TraceMem agents in Go. Each example demonstrates a specific pattern for interacting with TraceMem's Agent MCP server.

Prerequisites

  • Go 1.21 or higher
  • Standard library only (no external dependencies required)
  • Access to a TraceMem Agent MCP server (default: https://mcp.tracemem.com)
  • A valid TraceMem API key

Connection Details

  • Endpoint: https://mcp.tracemem.com (or set via MCP_AGENT_URL environment variable)
  • Protocol: JSON-RPC 2.0 over HTTP
  • Authentication: Authorization: Agent <your-api-key> header

MCP Client Implementation

First, let's create a reusable MCP client that handles JSON-RPC 2.0 communication:

go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
)

// JsonRpcRequest represents a JSON-RPC 2.0 request
type JsonRpcRequest struct {
	JsonRpc string                 `json:"jsonrpc"`
	ID      int                    `json:"id"`
	Method  string                  `json:"method"`
	Params  map[string]interface{} `json:"params,omitempty"`
}

// JsonRpcResponse represents a JSON-RPC 2.0 response
type JsonRpcResponse struct {
	JsonRpc string                 `json:"jsonrpc"`
	ID      int                    `json:"id"`
	Result  map[string]interface{} `json:"result,omitempty"`
	Error   *JsonRpcError           `json:"error,omitempty"`
}

// JsonRpcError represents a JSON-RPC 2.0 error
type JsonRpcError struct {
	Code    int                    `json:"code"`
	Message string                 `json:"message"`
	Data    map[string]interface{} `json:"data,omitempty"`
}

// ToolContent represents MCP tool call result content
type ToolContent struct {
	Type string `json:"type"`
	Text string `json:"text,omitempty"`
}

// ToolCallResult represents MCP tool call result
type ToolCallResult struct {
	Content []ToolContent `json:"content"`
	IsError bool          `json:"isError,omitempty"`
}

// MCPClient handles communication with TraceMem Agent MCP Server
type MCPClient struct {
	baseURL     string
	apiKey      string
	httpClient  *http.Client
	requestID   int
	initialized bool
}

// NewMCPClient creates a new MCP client
func NewMCPClient(baseURL, apiKey string) *MCPClient {
	return &MCPClient{
		baseURL:    baseURL,
		apiKey:     apiKey,
		httpClient: &http.Client{},
		requestID:  0,
	}
}

// nextID returns the next request ID
func (c *MCPClient) nextID() int {
	c.requestID++
	return c.requestID
}

// call makes a JSON-RPC call to the MCP server
func (c *MCPClient) call(method string, params map[string]interface{}) (map[string]interface{}, error) {
	request := JsonRpcRequest{
		JsonRpc: "2.0",
		ID:      c.nextID(),
		Method:  method,
		Params:  params,
	}

	jsonData, err := json.Marshal(request)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	req, err := http.NewRequest("POST", c.baseURL, bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}

	req.Header.Set("Authorization", fmt.Sprintf("Agent %s", c.apiKey))
	req.Header.Set("Content-Type", "application/json")

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("HTTP error: %w", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("failed to read response: %w", err)
	}

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("HTTP error %d: %s", resp.StatusCode, string(body))
	}

	var jsonResp JsonRpcResponse
	if err := json.Unmarshal(body, &jsonResp); err != nil {
		return nil, fmt.Errorf("failed to unmarshal response: %w", err)
	}

	if jsonResp.Error != nil {
		errorMsg := fmt.Sprintf("MCP Error %d: %s", jsonResp.Error.Code, jsonResp.Error.Message)
		if jsonResp.Error.Data != nil {
			dataJSON, _ := json.Marshal(jsonResp.Error.Data)
			errorMsg += fmt.Sprintf(" - %s", string(dataJSON))
		}
		return nil, fmt.Errorf(errorMsg)
	}

	if jsonResp.Result == nil {
		return make(map[string]interface{}), nil
	}

	return jsonResp.Result, nil
}

// Initialize initializes the MCP session
func (c *MCPClient) Initialize() (map[string]interface{}, error) {
	params := map[string]interface{}{
		"protocolVersion": "2024-11-05",
		"capabilities":     map[string]interface{}{},
		"clientInfo": map[string]interface{}{
			"name":    "tracemem-test-agent",
			"version": "1.0.0",
		},
	}

	result, err := c.call("initialize", params)
	if err != nil {
		return nil, err
	}

	c.initialized = true
	return result, nil
}

// ListTools lists available tools
func (c *MCPClient) ListTools() (map[string]interface{}, error) {
	return c.call("tools/list", nil)
}

// CallTool calls a tool
func (c *MCPClient) CallTool(name string, arguments map[string]interface{}) (map[string]interface{}, error) {
	if !c.initialized {
		if _, err := c.Initialize(); err != nil {
			return nil, err
		}
	}

	params := map[string]interface{}{
		"name":      name,
		"arguments": arguments,
	}

	result, err := c.call("tools/call", params)
	if err != nil {
		return nil, err
	}

	// Check if the tool result indicates an error
	if isError, ok := result["isError"].(bool); ok && isError {
		errorMessage := "Tool call failed"
		if content, ok := result["content"].([]interface{}); ok && len(content) > 0 {
			if contentMap, ok := content[0].(map[string]interface{}); ok {
				if text, ok := contentMap["text"].(string); ok {
					errorMessage = text
				}
			}
		}
		return nil, fmt.Errorf(errorMessage)
	}

	// Parse content from tool result
	if content, ok := result["content"].([]interface{}); ok && len(content) > 0 {
		if contentMap, ok := content[0].(map[string]interface{}); ok {
			if text, ok := contentMap["text"].(string); ok {
				var parsed map[string]interface{}
				if err := json.Unmarshal([]byte(text), &parsed); err == nil {
					return parsed, nil
				}
				return map[string]interface{}{"raw_text": text}, nil
			}
		}
	}

	return result, nil
}

// IsInitialized checks if the client is initialized
func (c *MCPClient) IsInitialized() bool {
	return c.initialized
}

Example 1: Read Agent

This example demonstrates reading customer data from a data product.

go
package main

import (
	"encoding/json"
	"fmt"
	"os"
	"strconv"
)

func runReadTest() error {
	// Get configuration from environment
	mcpURL := getEnv("MCP_AGENT_URL", "https://mcp.tracemem.com")
	apiKey := os.Getenv("TRACEMEM_API_KEY")
	instance := os.Getenv("TRACEMEM_INSTANCE")
	actor := getEnv("TRACEMEM_ACTOR", "test-read-agent")
	customerID := getEnv("CUSTOMER_ID", "1003")

	if apiKey == "" {
		return fmt.Errorf("ERROR: TRACEMEM_API_KEY environment variable is required")
	}

	fmt.Println(strings.Repeat("=", 60))
	fmt.Println("TraceMem MCP - Read Test Agent")
	fmt.Println(strings.Repeat("=", 60))
	fmt.Println()
	fmt.Printf("Connecting to Agent MCP at: %s\n", mcpURL)
	if instance != "" {
		fmt.Printf("Instance: %s\n", instance)
	}
	fmt.Printf("Actor: %s\n", actor)
	fmt.Printf("Customer ID: %s\n", customerID)
	fmt.Println()

	client := NewMCPClient(mcpURL, apiKey)
	var decisionID string

	defer func() {
		if decisionID != "" {
			// Try to close decision on error
			if r := recover(); r != nil {
				fmt.Println("Attempting to abort decision...")
				_, err := client.CallTool("decision_close", map[string]interface{}{
					"decision_id": decisionID,
					"action":       "abort",
					"reason":       fmt.Sprintf("Error occurred: %v", r),
				})
				if err != nil {
					fmt.Printf("Failed to abort decision: %v\n", err)
				} else {
					fmt.Println("✓ Decision aborted")
				}
			}
		}
	}()

	// Initialize MCP session
	fmt.Println("Initializing MCP session...")
	initResult, err := client.Initialize()
	if err != nil {
		return fmt.Errorf("failed to initialize: %w", err)
	}

	serverInfo, _ := initResult["serverInfo"].(map[string]interface{})
	serverName := "TraceMem Agent MCP"
	if name, ok := serverInfo["name"].(string); ok {
		serverName = name
	}
	fmt.Printf("✓ Connected to %s\n", serverName)
	fmt.Println()

	// Step 1: Create decision envelope
	fmt.Println("Step 1: Creating decision envelope...")
	decision, err := client.CallTool("decision_create", map[string]interface{}{
		"intent":         "test.read.customer",
		"automation_mode": "autonomous",
		"instance":        instance,
		"actor":           actor,
		"metadata": map[string]interface{}{
			"customer_id": customerID,
			"test_type":   "read",
		},
	})
	if err != nil {
		return fmt.Errorf("failed to create decision: %w", err)
	}

	decisionID, _ = decision["decision_id"].(string)
	if decisionID == "" {
		decisionID, _ = decision["id"].(string)
	}
	if decisionID == "" {
		return fmt.Errorf("failed to get decision_id from decision_create response")
	}
	fmt.Printf("✓ Decision envelope created: %s\n", decisionID)
	fmt.Println()

	// Step 2: Read customer data
	fmt.Println("Step 2: Reading customer data...")
	customerIDInt, _ := strconv.Atoi(customerID)
	readResult, err := client.CallTool("decision_read", map[string]interface{}{
		"decision_id": decisionID,
		"product":      "planetscale_read_customer_v1",
		"purpose":      "web_order",
		"query": map[string]interface{}{
			"id": customerIDInt,
		},
	})
	if err != nil {
		return fmt.Errorf("failed to read customer data: %w", err)
	}

	fmt.Println("✓ Customer data retrieved")
	if eventID, ok := readResult["event_id"].(string); ok {
		fmt.Printf("  Event ID: %s\n", eventID)
	}
	if dataRef, ok := readResult["data_ref"].(string); ok {
		fmt.Printf("  Data Reference: %s\n", dataRef)
	}
	if records, ok := readResult["records"].([]interface{}); ok && len(records) > 0 {
		fmt.Printf("  Records found: %d\n", len(records))
		fmt.Println("  Customer data:")
		recordJSON, _ := json.MarshalIndent(records[0], "", "  ")
		fmt.Println(string(recordJSON))
	} else {
		fmt.Println("  No records found")
	}
	fmt.Println()

	// Step 3: Close decision (commit)
	fmt.Println("Step 3: Committing decision...")
	closeResult, err := client.CallTool("decision_close", map[string]interface{}{
		"decision_id": decisionID,
		"action":       "commit",
	})
	if err != nil {
		return fmt.Errorf("failed to close decision: %w", err)
	}

	fmt.Println("✓ Decision committed")
	if status, ok := closeResult["status"].(string); ok {
		fmt.Printf("  Status: %s\n", status)
	}
	fmt.Println()

	// Summary
	fmt.Println(strings.Repeat("=", 60))
	fmt.Println("Summary")
	fmt.Println(strings.Repeat("=", 60))
	fmt.Printf("Decision ID: %s\n", decisionID)
	fmt.Println("Result: ✓ Read operation completed successfully")
	fmt.Println()

	return nil
}

func getEnv(key, defaultValue string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return defaultValue
}

func main() {
	if err := runReadTest(); err != nil {
		fmt.Fprintf(os.Stderr, "✗ Error: %v\n", err)
		os.Exit(1)
	}
}

Environment Variables

  • TRACEMEM_API_KEY (required): Your TraceMem agent API key
  • MCP_AGENT_URL (optional): MCP server URL (default: https://mcp.tracemem.com)
  • TRACEMEM_INSTANCE (optional): Instance identifier
  • TRACEMEM_ACTOR (optional): Actor identifier (default: test-read-agent)
  • CUSTOMER_ID (optional): Customer ID to read (default: 1003)

Running the Example

bash
export TRACEMEM_API_KEY="your-api-key"
export CUSTOMER_ID="1"
go run test_read_agent.go

Example 2: Insert Agent (with Policy)

This example demonstrates inserting an order with policy evaluation.

go
package main

import (
	"encoding/json"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func runInsertTest() error {
	// Get configuration from environment
	mcpURL := getEnv("MCP_AGENT_URL", "https://mcp.tracemem.com")
	apiKey := os.Getenv("TRACEMEM_API_KEY")
	instance := os.Getenv("TRACEMEM_INSTANCE")
	actor := getEnv("TRACEMEM_ACTOR", "test-insert-agent")

	// Test data - can be overridden via environment variables
	customerID, _ := strconv.Atoi(getEnv("CUSTOMER_ID", "1001"))
	productID, _ := strconv.Atoi(getEnv("PRODUCT_ID", "2"))
	quantity, _ := strconv.Atoi(getEnv("QUANTITY", "1"))
	totalAmount, _ := strconv.ParseFloat(getEnv("TOTAL_AMOUNT", "99.99"), 64)
	orderStatus := getEnv("ORDER_STATUS", "pending")
	proposedDiscount, _ := strconv.ParseFloat(getEnv("PROPOSED_DISCOUNT", "0"), 64)

	if apiKey == "" {
		return fmt.Errorf("ERROR: TRACEMEM_API_KEY environment variable is required")
	}

	fmt.Println(strings.Repeat("=", 60))
	fmt.Println("TraceMem MCP - Insert Test Agent")
	fmt.Println(strings.Repeat("=", 60))
	fmt.Println()
	fmt.Printf("Connecting to Agent MCP at: %s\n", mcpURL)
	if instance != "" {
		fmt.Printf("Instance: %s\n", instance)
	}
	fmt.Printf("Actor: %s\n", actor)
	fmt.Println("Order Data:")
	fmt.Printf("  Customer ID: %d\n", customerID)
	fmt.Printf("  Product ID: %d\n", productID)
	fmt.Printf("  Quantity: %d\n", quantity)
	fmt.Printf("  Total Amount: %.2f\n", totalAmount)
	fmt.Printf("  Order Status: %s\n", orderStatus)
	fmt.Printf("  Proposed Discount: %.2f\n", proposedDiscount)
	fmt.Println()

	client := NewMCPClient(mcpURL, apiKey)
	var decisionID string

	defer func() {
		if decisionID != "" {
			if r := recover(); r != nil {
				fmt.Println("Attempting to abort decision...")
				_, err := client.CallTool("decision_close", map[string]interface{}{
					"decision_id": decisionID,
					"action":       "abort",
					"reason":       fmt.Sprintf("Error occurred: %v", r),
				})
				if err != nil {
					fmt.Printf("Failed to abort decision: %v\n", err)
				} else {
					fmt.Println("✓ Decision aborted")
				}
			}
		}
	}()

	// Initialize MCP session
	fmt.Println("Initializing MCP session...")
	initResult, err := client.Initialize()
	if err != nil {
		return fmt.Errorf("failed to initialize: %w", err)
	}

	serverInfo, _ := initResult["serverInfo"].(map[string]interface{})
	serverName := "TraceMem Agent MCP"
	if name, ok := serverInfo["name"].(string); ok {
		serverName = name
	}
	fmt.Printf("✓ Connected to %s\n", serverName)
	fmt.Println()

	// Step 1: Create decision envelope
	fmt.Println("Step 1: Creating decision envelope...")
	decision, err := client.CallTool("decision_create", map[string]interface{}{
		"intent":         "test.insert.order",
		"automation_mode": "autonomous",
		"instance":        instance,
		"actor":           actor,
		"metadata": map[string]interface{}{
			"customer_id": strconv.Itoa(customerID),
			"product_id":  strconv.Itoa(productID),
			"test_type":   "insert",
		},
	})
	if err != nil {
		return fmt.Errorf("failed to create decision: %w", err)
	}

	decisionID, _ = decision["decision_id"].(string)
	if decisionID == "" {
		decisionID, _ = decision["id"].(string)
	}
	if decisionID == "" {
		return fmt.Errorf("failed to get decision_id from decision_create response")
	}
	fmt.Printf("✓ Decision envelope created: %s\n", decisionID)
	fmt.Println()

	// Step 2: Evaluate policy
	fmt.Println("Step 2: Evaluating discount_cap_v1 policy...")
	policyResult, err := client.CallTool("decision_evaluate", map[string]interface{}{
		"decision_id": decisionID,
		"policy_id":    "discount_cap_v1",
		"inputs": map[string]interface{}{
			"proposed_discount": proposedDiscount,
		},
	})
	if err != nil {
		return fmt.Errorf("failed to evaluate policy: %w", err)
	}

	outcome, _ := policyResult["outcome"].(string)
	if outcome == "" {
		outcome = "unknown"
	}
	fmt.Println("✓ Policy evaluation completed")
	fmt.Printf("  Policy ID: discount_cap_v1\n")
	fmt.Printf("  Proposed Discount: %.2f\n", proposedDiscount)
	fmt.Printf("  Outcome: %s\n", outcome)
	if rationale, ok := policyResult["rationale"].(map[string]interface{}); ok {
		if msg, ok := rationale["message"].(string); ok {
			fmt.Printf("  Rationale: %s\n", msg)
		} else {
			rationaleJSON, _ := json.Marshal(rationale)
			fmt.Printf("  Rationale: %s\n", string(rationaleJSON))
		}
	} else if rationale, ok := policyResult["rationale"].(string); ok {
		fmt.Printf("  Rationale: %s\n", rationale)
	}
	if eventID, ok := policyResult["event_id"].(string); ok {
		fmt.Printf("  Event ID: %s\n", eventID)
	}
	fmt.Println()

	// Handle policy outcomes
	if outcome == "deny" {
		rationaleMsg := "No rationale provided"
		if rationale, ok := policyResult["rationale"].(map[string]interface{}); ok {
			if msg, ok := rationale["message"].(string); ok {
				rationaleMsg = msg
			}
		}
		return fmt.Errorf("policy evaluation denied the operation. Rationale: %s", rationaleMsg)
	} else if outcome == "requires_exception" {
		fmt.Println("⚠ Policy requires exception/approval, but continuing with test...")
		fmt.Println()
	} else if outcome != "allow" {
		fmt.Printf("⚠ Unexpected policy outcome: %s, continuing with test...\n", outcome)
		fmt.Println()
	}

	// Step 3: Insert order
	fmt.Println("Step 3: Inserting order...")
	writeResult, err := client.CallTool("decision_write", map[string]interface{}{
		"decision_id": decisionID,
		"product":      "planetscale_insert_order_v1",
		"purpose":      "web_order",
		"mutation": map[string]interface{}{
			"operation": "insert",
			"records": []map[string]interface{}{
				{
					"customer_id":  customerID,
					"product_id":   productID,
					"quantity":     quantity,
					"total_amount": totalAmount,
					"order_status": orderStatus,
				},
			},
		},
	})
	if err != nil {
		return fmt.Errorf("failed to write: %w", err)
	}

	fmt.Println("✓ Order inserted")
	if eventID, ok := writeResult["event_id"].(string); ok {
		fmt.Printf("  Event ID: %s\n", eventID)
	}
	if status, ok := writeResult["status"].(string); ok {
		fmt.Printf("  Status: %s\n", status)
	}
	if createdRecords, ok := writeResult["created_records"].([]interface{}); ok && len(createdRecords) > 0 {
		fmt.Printf("  Created %d record(s):\n", len(createdRecords))
		for i, record := range createdRecords {
			fmt.Printf("  Record %d:\n", i+1)
			recordJSON, _ := json.MarshalIndent(record, "", "  ")
			fmt.Println(string(recordJSON))
		}
	}
	if mutationSummary, ok := writeResult["mutation_summary"].(map[string]interface{}); ok {
		mutationJSON, _ := json.Marshal(mutationSummary)
		fmt.Printf("  Mutation Summary: %s\n", string(mutationJSON))
	}
	fmt.Println()

	// Step 4: Close decision (commit)
	fmt.Println("Step 4: Committing decision...")
	closeResult, err := client.CallTool("decision_close", map[string]interface{}{
		"decision_id": decisionID,
		"action":       "commit",
	})
	if err != nil {
		return fmt.Errorf("failed to close decision: %w", err)
	}

	fmt.Println("✓ Decision committed")
	if status, ok := closeResult["status"].(string); ok {
		fmt.Printf("  Status: %s\n", status)
	}
	fmt.Println()

	// Summary
	fmt.Println(strings.Repeat("=", 60))
	fmt.Println("Summary")
	fmt.Println(strings.Repeat("=", 60))
	fmt.Printf("Decision ID: %s\n", decisionID)
	fmt.Println("Result: ✓ Insert operation completed successfully")
	if createdRecords, ok := writeResult["created_records"].([]interface{}); ok && len(createdRecords) > 0 {
		if firstRecord, ok := createdRecords[0].(map[string]interface{}); ok {
			if orderID, ok := firstRecord["order_id"].(float64); ok {
				fmt.Printf("Created Order ID: %.0f\n", orderID)
			}
		}
	}
	fmt.Println()

	return nil
}

func getEnv(key, defaultValue string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return defaultValue
}

func main() {
	if err := runInsertTest(); err != nil {
		fmt.Fprintf(os.Stderr, "✗ Error: %v\n", err)
		os.Exit(1)
	}
}

Environment Variables

  • TRACEMEM_API_KEY (required): Your TraceMem agent API key
  • MCP_AGENT_URL (optional): MCP server URL (default: https://mcp.tracemem.com)
  • TRACEMEM_INSTANCE (optional): Instance identifier
  • TRACEMEM_ACTOR (optional): Actor identifier (default: test-insert-agent)
  • CUSTOMER_ID (optional): Customer ID for order (default: 1001)
  • PRODUCT_ID (optional): Product ID for order (default: 2)
  • QUANTITY (optional): Order quantity (default: 1)
  • TOTAL_AMOUNT (optional): Order total amount (default: 99.99)
  • ORDER_STATUS (optional): Order status (default: pending)
  • PROPOSED_DISCOUNT (optional): Proposed discount for policy evaluation (default: 0)

Example 3: Insert Agent (without Policy)

This example demonstrates inserting an order without policy evaluation. The code structure is similar to Example 2, but without the policy evaluation step. The key difference is using planetscale_insert_order_no_policy_v1 as the product and skipping the decision_evaluate call.

Example 4: Update Agent

This example demonstrates updating product stock.

go
package main

import (
	"encoding/json"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func runUpdateTest() error {
	// Get configuration from environment
	mcpURL := getEnv("MCP_AGENT_URL", "https://mcp.tracemem.com")
	apiKey := os.Getenv("TRACEMEM_API_KEY")
	instance := os.Getenv("TRACEMEM_INSTANCE")
	actor := getEnv("TRACEMEM_ACTOR", "test-update-agent")

	// Test data
	productID, _ := strconv.Atoi(getEnv("PRODUCT_ID", "4"))
	stockQuantity, _ := strconv.Atoi(getEnv("STOCK_QUANTITY", "90"))

	if apiKey == "" {
		return fmt.Errorf("ERROR: TRACEMEM_API_KEY environment variable is required")
	}

	fmt.Println(strings.Repeat("=", 60))
	fmt.Println("TraceMem MCP - Update Test Agent")
	fmt.Println(strings.Repeat("=", 60))
	fmt.Println()
	fmt.Printf("Connecting to Agent MCP at: %s\n", mcpURL)
	if instance != "" {
		fmt.Printf("Instance: %s\n", instance)
	}
	fmt.Printf("Actor: %s\n", actor)
	fmt.Println("Update Data:")
	fmt.Printf("  Product ID: %d\n", productID)
	fmt.Printf("  Stock Quantity: %d\n", stockQuantity)
	fmt.Println()

	client := NewMCPClient(mcpURL, apiKey)
	var decisionID string

	defer func() {
		if decisionID != "" {
			if r := recover(); r != nil {
				fmt.Println("Attempting to abort decision...")
				_, err := client.CallTool("decision_close", map[string]interface{}{
					"decision_id": decisionID,
					"action":       "abort",
					"reason":       fmt.Sprintf("Error occurred: %v", r),
				})
				if err != nil {
					fmt.Printf("Failed to abort decision: %v\n", err)
				} else {
					fmt.Println("✓ Decision aborted")
				}
			}
		}
	}()

	// Initialize and create decision (similar pattern as above)
	// ... (implementation follows same pattern as read/insert examples)

	// Step 2: Update product stock
	fmt.Println("Step 2: Updating product stock...")
	writeResult, err := client.CallTool("decision_write", map[string]interface{}{
		"decision_id": decisionID,
		"product":      "planetscale_update_product_stock_v1",
		"purpose":      "web_order",
		"mutation": map[string]interface{}{
			"operation": "update",
			"records": []map[string]interface{}{
				{
					"product_id":    productID,  // Key field for identification
					"stock_quantity": stockQuantity,  // Field to update
				},
			},
		},
	})
	if err != nil {
		return fmt.Errorf("failed to update: %w", err)
	}

	fmt.Println("✓ Product stock updated")
	// ... (output handling similar to insert example)

	return nil
}

func getEnv(key, defaultValue string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return defaultValue
}

func main() {
	if err := runUpdateTest(); err != nil {
		fmt.Fprintf(os.Stderr, "✗ Error: %v\n", err)
		os.Exit(1)
	}
}

Environment Variables

  • TRACEMEM_API_KEY (required): Your TraceMem agent API key
  • MCP_AGENT_URL (optional): MCP server URL (default: https://mcp.tracemem.com)
  • TRACEMEM_INSTANCE (optional): Instance identifier
  • TRACEMEM_ACTOR (optional): Actor identifier (default: test-update-agent)
  • PRODUCT_ID (optional): Product ID to update (default: 4)
  • STOCK_QUANTITY (optional): New stock quantity (default: 90)

Example 5: Delete Agent

This example demonstrates deleting a target record.

go
package main

import (
	"encoding/json"
	"fmt"
	"os"
	"regexp"
	"strings"
)

func runDeleteTest() error {
	// Get configuration from environment
	mcpURL := getEnv("MCP_AGENT_URL", "https://mcp.tracemem.com")
	apiKey := os.Getenv("TRACEMEM_API_KEY")
	instance := os.Getenv("TRACEMEM_INSTANCE")
	actor := getEnv("TRACEMEM_ACTOR", "test-delete-agent")
	targetID := getEnv("TARGET_ID", "0cf1e19e-00ed-4a4c-8d82-ee70f590fad8")

	if apiKey == "" {
		return fmt.Errorf("ERROR: TRACEMEM_API_KEY environment variable is required")
	}

	if targetID == "" {
		return fmt.Errorf("ERROR: TARGET_ID environment variable is required (must be a UUID)")
	}

	// Basic UUID format validation
	uuidRegex := regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`)
	if !uuidRegex.MatchString(targetID) {
		return fmt.Errorf("ERROR: TARGET_ID must be a valid UUID format. Received: %s", targetID)
	}

	fmt.Println(strings.Repeat("=", 60))
	fmt.Println("TraceMem MCP - Delete Test Agent")
	fmt.Println(strings.Repeat("=", 60))
	fmt.Println()
	fmt.Printf("Connecting to Agent MCP at: %s\n", mcpURL)
	if instance != "" {
		fmt.Printf("Instance: %s\n", instance)
	}
	fmt.Printf("Actor: %s\n", actor)
	fmt.Println("Delete Data:")
	fmt.Printf("  Target ID: %s\n", targetID)
	fmt.Println()
	fmt.Println("⚠ WARNING: This will delete a record from the database!")
	fmt.Println()

	client := NewMCPClient(mcpURL, apiKey)
	var decisionID string

	defer func() {
		if decisionID != "" {
			if r := recover(); r != nil {
				fmt.Println("Attempting to abort decision...")
				_, err := client.CallTool("decision_close", map[string]interface{}{
					"decision_id": decisionID,
					"action":       "abort",
					"reason":       fmt.Sprintf("Error occurred: %v", r),
				})
				if err != nil {
					fmt.Printf("Failed to abort decision: %v\n", err)
				} else {
					fmt.Println("✓ Decision aborted")
				}
			}
		}
	}()

	// Initialize and create decision (similar pattern as above)
	// ... (implementation follows same pattern)

	// Step 2: Delete target record
	fmt.Println("Step 2: Deleting target record...")
	writeResult, err := client.CallTool("decision_write", map[string]interface{}{
		"decision_id": decisionID,
		"product":      "planetscale_delete_target_v1",
		"purpose":      "delete_target",
		"mutation": map[string]interface{}{
			"operation": "delete",
			"records": []map[string]interface{}{
				{
					"id": targetID,  // Key field for deletion
				},
			},
		},
	})
	if err != nil {
		return fmt.Errorf("failed to delete: %w", err)
	}

	fmt.Println("✓ Target record deleted")
	// ... (output handling)

	return nil
}

func getEnv(key, defaultValue string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return defaultValue
}

func main() {
	if err := runDeleteTest(); err != nil {
		fmt.Fprintf(os.Stderr, "✗ Error: %v\n", err)
		os.Exit(1)
	}
}

Environment Variables

  • TRACEMEM_API_KEY (required): Your TraceMem agent API key
  • MCP_AGENT_URL (optional): MCP server URL (default: https://mcp.tracemem.com)
  • TRACEMEM_INSTANCE (optional): Instance identifier
  • TRACEMEM_ACTOR (optional): Actor identifier (default: test-delete-agent)
  • TARGET_ID (required): UUID of target record to delete

Common Patterns

Error Handling Best Practices

Always ensure decision envelopes are properly closed, even on errors:

go
decisionID := ""
defer func() {
    if decisionID != "" {
        if r := recover(); r != nil {
            fmt.Println("Attempting to abort decision...")
            _, err := client.CallTool("decision_close", map[string]interface{}{
                "decision_id": decisionID,
                "action":       "abort",
                "reason":       fmt.Sprintf("Error occurred: %v", r),
            })
            if err != nil {
                fmt.Printf("Failed to abort decision: %v\n", err)
            }
        }
    }
}()

// Create decision and perform operations
decision, err := client.CallTool("decision_create", {...})
if err != nil {
    return err
}
decisionID = decision["decision_id"].(string)

// Perform operations...

// Commit on success
_, err = client.CallTool("decision_close", map[string]interface{}{
    "decision_id": decisionID,
    "action":       "commit",
})
if err != nil {
    return err
}

Decision Envelope Lifecycle

Every agent operation should follow this pattern:

  1. Initialize MCP Session: Connect to the Agent MCP server
  2. Create Decision Envelope: Open a decision with appropriate intent
  3. Perform Operations: Read, write, evaluate policies, etc.
  4. Close Decision: Commit on success, abort on error

Environment Variable Configuration

All examples use environment variables for configuration:

bash
# Required
export TRACEMEM_API_KEY="your-api-key"

# Optional
export MCP_AGENT_URL="https://mcp.tracemem.com"
export TRACEMEM_INSTANCE="my-instance"
export TRACEMEM_ACTOR="my-agent"

Testing Tips

  1. Start with Read Operations: Test read operations first to verify connectivity
  2. Use Test Data: Use non-production data products for testing
  3. Check Decision Traces: Review decision traces in the TraceMem dashboard
  4. Handle Errors Gracefully: Always implement proper error handling and decision cleanup

TraceMem is trace-native infrastructure for AI agents