Quickstart

Get your first decision trace stored in TraceMem in 5 minutes. This guide covers the minimum workflow to create an immutable audit trail of an agent decision.

What You'll Build

A simple agent that reads data through TraceMem and creates a decision trace—the foundation for explainable, auditable AI decisions.

Prerequisites

  • TraceMem account (sign up)
  • Access to a PostgreSQL-based database (e.g., PlanetScale or Supabase)

Example Database Schema

For this guide, we'll use a simple customers table. Create it in your PostgreSQL database:

sql
CREATE TABLE customers (
    customer_id SERIAL PRIMARY KEY,
    email VARCHAR(255) NOT NULL,
    name VARCHAR(255) NOT NULL,
    tier VARCHAR(50) DEFAULT 'standard',
    created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Insert sample data
INSERT INTO customers (email, name, tier) VALUES
    ('alice@example.com', 'Alice Smith', 'premium'),
    ('bob@example.com', 'Bob Jones', 'standard'),
    ('charlie@example.com', 'Charlie Brown', 'enterprise');

Step 1: Connect Your Data (2 minutes)

Create a Connector

  1. Go to Setup → Connectors in the dashboard
  2. Click Create Connector
  3. Select Database and your system type
  4. Enter a connection string:

PostgreSQL:

text
postgresql://username:password@host:5432/database?sslmode=require
  1. Click Create and verify connection status is connected

Create a Data Product

  1. Go to Config → Data Products
  2. Click Create Data Product
  3. Select Source:
    • Select Read operation
    • Choose your connector
    • Select the customers table (or your table)
  4. Choose columns:
    • Select the customer_id as required
  5. Fill in:
    • Product Name: customer_data (or your choice)
    • Description: "Customer information for agent access"
    • Set Allowed Purposes: add purpose: order_processing
  6. Review and Create data product
  7. Publish the data product

Step 2: Get Your API Key (1 minute)

  1. Go to Settings → Agents
  2. Click Create Agent
  3. Enter agent name: my-first-agent
  4. Click Create Credential
  5. Copy and save the API key (shown only once)

Step 3: Make Your First Decision (2 minutes)

Choose your language and run the example:

Python

python
import requests
import json

class MCPClient:
    def __init__(self, api_key):
        self.base_url = "https://mcp.tracemem.com"
        self.api_key = api_key
        self.session = requests.Session()
        self.session.headers.update({
            "Authorization": f"Agent {api_key}",
            "Content-Type": "application/json"
        })
        self.request_id = 0
    
    def _call(self, method, params=None):
        request = {
            "jsonrpc": "2.0",
            "id": self.request_id := self.request_id + 1,
            "method": method,
            "params": params or {}
        }
        response = self.session.post(self.base_url, json=request)
        response.raise_for_status()
        result = response.json()
        if "error" in result:
            raise Exception(f"Error: {result['error']}")
        return result.get("result", {})
    
    def call_tool(self, name, arguments):
        result = self._call("tools/call", {
            "name": name,
            "arguments": arguments
        })
        if "content" in result and len(result["content"]) > 0:
            return json.loads(result["content"][0].get("text", "{}"))
        return result

# Initialize
client = MCPClient("your-api-key-here")
client._call("initialize", {
    "protocolVersion": "2024-11-05",
    "capabilities": {},
    "clientInfo": {"name": "my-first-agent", "version": "1.0.0"}
})

# 1. Create decision envelope
decision = client.call_tool("decision_create", {
    "intent": "customer.lookup",
    "automation_mode": "autonomous"
})
decision_id = decision["decision_id"]
print(f"Created decision: {decision_id}")

# 2. Read data through Data Product
customer = client.call_tool("decision_read", {
    "decision_id": decision_id,
    "product": "customer_data",  # Your data product ID
    "purpose": "order_processing",
    "query": {"customer_id": 1}  # Query by customer_id
})
print(f"Read customer: {customer.get('records', [])}")

# 3. Close decision (commits the trace)
result = client.call_tool("decision_close", {
    "decision_id": decision_id,
    "action": "commit"
})
print(f"Decision closed: {result.get('status')}")

TypeScript

typescript
import fetch from 'node-fetch'; // or use native fetch in Node 18+

class MCPClient {
  private baseUrl: string;
  private apiKey: string;
  private requestId: number = 0;

  constructor(apiKey: string) {
    this.baseUrl = "https://mcp.tracemem.com";
    this.apiKey = apiKey;
  }

  private async call(method: string, params?: any): Promise<any> {
    const request = {
      jsonrpc: "2.0",
      id: ++this.requestId,
      method,
      params: params || {}
    };

    const response = await fetch(this.baseUrl, {
      method: 'POST',
      headers: {
        'Authorization': `Agent ${this.apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(request)
    });

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }

    const result = await response.json();
    if (result.error) {
      throw new Error(`Error: ${JSON.stringify(result.error)}`);
    }
    return result.result || {};
  }

  async callTool(name: string, arguments_: any): Promise<any> {
    const result = await this.call("tools/call", {
      name,
      arguments: arguments_
    });
    
    if (result.content && result.content.length > 0) {
      return JSON.parse(result.content[0].text || "{}");
    }
    return result;
  }
}

// Initialize and run
async function main() {
  const client = new MCPClient("your-api-key-here");
  
  await client.call("initialize", {
    protocolVersion: "2024-11-05",
    capabilities: {},
    clientInfo: { name: "my-first-agent", version: "1.0.0" }
  });

  // 1. Create decision envelope
  const decision = await client.callTool("decision_create", {
    intent: "customer.lookup",
    automation_mode: "autonomous"
  });
  const decisionId = decision.decision_id;
  console.log(`Created decision: ${decisionId}`);

  // 2. Read data through Data Product
  const customer = await client.callTool("decision_read", {
    decision_id: decisionId,
    product: "customer_data",  // Your data product ID
    purpose: "order_processing",
    query: { customer_id: 1 }  // Query by customer_id
  });
  console.log(`Read customer:`, customer.records || []);

  // 3. Close decision (commits the trace)
  const result = await client.callTool("decision_close", {
    decision_id: decisionId,
    action: "commit"
  });
  console.log(`Decision closed: ${result.status}`);
}

main().catch(console.error);

Install dependencies:

  • Python: pip install requests
  • TypeScript: npm install node-fetch @types/node-fetch (or use native fetch in Node 18+)

Run either script. You've created your first decision trace!

Step 4: View Your Trace

  1. Go to Traces in the dashboard
  2. Find your decision by decision_id or intent customer.lookup
  3. Click to view the complete trace:
    • Decision envelope (intent, status, timestamps)
    • Events (read operation with purpose)
    • Decision-time snapshot (data product version)
    • Outcome summary

What Just Happened?

You created an immutable decision trace that records:

  • What decision was made: customer.lookup
  • What data was accessed: Customer data via customer_data product
  • Why it was accessed: Purpose order_processing
  • When it happened: Exact timestamps
  • What version applied: Data product hash in snapshot

This trace will remain queryable and auditable forever, even if your data product changes.

TraceMem is trace-native infrastructure for AI agents