decision_write
Writes data through a governed data product within a decision envelope. All write operations are logged and only committed when the decision is closed with "commit".
Overview
The decision_write method allows you to insert, update, or delete data through a data product within a decision context. Write operations are validated according to the data product's configuration and are only made permanent when you close the decision with action: "commit".
Request
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
decision_id | string | Yes | The decision ID (from decision_create) |
product | string | Yes | Data product name (e.g., "pg_orders_v1") |
purpose | string | Yes | Why you're writing the data (must be allowed by the data product) |
mutation | object | Yes | The mutation to perform (see Mutation Structure below) |
idempotency_key | string | No | Key for idempotent writes (prevents duplicate writes on retries) |
Mutation Structure
The mutation object must contain:
| Field | Type | Required | Description |
|---|---|---|---|
operation | string | Yes | Must be "insert", "update", or "delete" |
records | array | Yes* | Array of records to write (required for all operations) |
data | object | Yes* | Single record to write (alternative to records for insert operations) |
* For insert operations, you can use either data (single record) or records (array). For update and delete, use records.
Example Request - Insert
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "decision_write",
"arguments": {
"decision_id": "TMEM_abc123...",
"product": "pg_orders_v1",
"purpose": "order_creation",
"mutation": {
"operation": "insert",
"records": [
{
"customer_id": 1001,
"product_id": 5,
"quantity": 1,
"total_amount": 299.99
}
]
},
"idempotency_key": "order-1001-20260107-001"
}
}
}
Example Request - Update
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "decision_write",
"arguments": {
"decision_id": "TMEM_abc123...",
"product": "pg_orders_v1",
"purpose": "order_update",
"mutation": {
"operation": "update",
"records": [
{
"order_id": 12345,
"status": "shipped",
"shipped_at": "2026-01-07T14:00:00Z"
}
]
}
}
}
}
Example Request - Delete
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "decision_write",
"arguments": {
"decision_id": "TMEM_abc123...",
"product": "pg_orders_v1",
"purpose": "order_cancellation",
"mutation": {
"operation": "delete",
"records": [
{
"order_id": 12345
}
]
}
}
}
}
Response
Success Response
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "{\"event_id\": \"evt_...\", \"status\": \"executed\", \"mutation_summary\": {\"targets\": 1, \"fields_changed\": []}, \"created_records\": [...]}"
}
]
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
event_id | string | Unique identifier for this write event |
status | string | Status of the write operation (typically "executed") |
mutation_summary | object | Summary of the mutation |
mutation_summary.targets | number | Number of records affected |
mutation_summary.fields_changed | array | List of fields that were changed (for updates) |
created_records | array | Array of created records with generated IDs (only for insert operations when return_created is enabled) |
Example Response - Insert with Returned Records
{
"event_id": "evt_write_abc123",
"status": "executed",
"mutation_summary": {
"targets": 1,
"fields_changed": []
},
"created_records": [
{
"order_id": 12345,
"customer_id": 1001,
"product_id": 5,
"quantity": 1,
"total_amount": 299.99,
"created_at": "2026-01-15T10:30:00Z"
}
]
}
Note: The created_records field is only present when:
- The operation is
insert - The data product has
restrictions.insert_config.return_createdset totrue - The insert operation succeeds
Insert Operation Validation
For insert operations, the following validation rules apply:
1. Required Columns
All columns marked as required: true in the data product's insert_config.column_config must be provided in the mutation data.
Error if missing:
{
"error": {
"code": -32603,
"message": "Internal error",
"data": "Validation failed: required column 'customer_id' is missing"
}
}
2. Allowed Columns
Only columns marked as allowed: true (or not explicitly disallowed) in insert_config.column_config can be included. Columns not in the exposed schema are also rejected.
Error if disallowed:
{
"error": {
"code": -32603,
"message": "Internal error",
"data": "Validation failed: column 'internal_notes' is not allowed"
}
}
3. Primary Key Handling
For primary keys with auto-generated defaults (sequences, auto_increment, UUIDs):
- If
allow_custom_primary_key[item_id]isfalseor not set, custom values will be rejected - If
allow_custom_primary_key[item_id]istrue, custom values are allowed
Error if custom primary key not allowed:
{
"error": {
"code": -32603,
"message": "Internal error",
"data": "Validation failed: custom primary key value not allowed for 'order_id'"
}
}
4. Default Values
Columns can have default behaviors configured:
"user_provided"- User must provide the value"db_default"- Database default is used (column can be omitted)"tracemem_default"- Fixed default value is used (specified intracemem_default_value)"null"- Column is set to NULL (only for nullable columns)
Error Cases
Missing Required Parameters
Error Code: -32600 (Invalid Request)
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32600,
"message": "Invalid Request",
"data": "decision_id, product, purpose, and mutation are required"
}
}
Invalid Operation
Error Code: -32602 (Invalid params)
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32602,
"message": "Invalid params",
"data": "mutation.operation must be one of: insert, update, delete"
}
}
Validation Errors
Error Code: -32603 (Internal error)
Common validation errors:
- Missing required columns
- Disallowed columns in the request
- Primary key custom values not allowed
- Invalid default value configurations
- Invalid data types
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32603,
"message": "Internal error",
"data": "Validation failed: required column 'customer_id' is missing. Tip: Check that all required columns are provided and only allowed columns are included."
}
}
Policy Evaluation Required
Error Code: -32603 (Internal error)
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32603,
"message": "Internal error",
"data": "Policy evaluation required before write operation. Tip: Use the 'decision_evaluate' tool to evaluate the required policy(ies) before performing write operations."
}
}
Solution: Evaluate the required policy using decision_evaluate before performing the write.
Data Product Not Found
Error Code: -32603 (Internal error)
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32603,
"message": "Internal error",
"data": "Data product 'pg_orders_v1' not found or not accessible"
}
}
Permission Denied
HTTP Status: 403 Forbidden
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32603,
"message": "Internal error",
"data": "Permission denied: agent does not have write access to this data product"
}
}
Decision Not Found or Closed
Error Code: -32603 (Internal error)
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32603,
"message": "Internal error",
"data": "Decision not found or already closed"
}
}
Authentication Errors
HTTP Status: 401 Unauthorized
Occurs when:
- API key is missing
- API key is invalid
- API key has been revoked
Usage Examples
Insert Single Record
import requests
import json
def write_data(decision_id, product, purpose, mutation, idempotency_key=None, api_key=None):
response = requests.post('https://mcp.tracemem.com',
headers={'Authorization': f'Agent {api_key}'},
json={
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "decision_write",
"arguments": {
"decision_id": decision_id,
"product": product,
"purpose": purpose,
"mutation": mutation,
"idempotency_key": idempotency_key
}
}
})
result = response.json()
if "error" in result:
raise Exception(result["error"]["data"])
write_data = json.loads(result["result"]["content"][0]["text"])
return write_data
# Insert order
result = write_data(
decision_id="TMEM_abc123...",
product="pg_orders_v1",
purpose="order_creation",
mutation={
"operation": "insert",
"records": [{
"customer_id": 1001,
"product_id": 5,
"quantity": 1,
"total_amount": 299.99
}]
},
idempotency_key=f"order-1001-{int(time.time())}",
api_key="YOUR_API_KEY"
)
# Check if created records were returned
if "created_records" in result:
order_id = result["created_records"][0]["order_id"]
print(f"Order created with ID: {order_id}")
Insert Multiple Records
# Insert multiple order items
result = write_data(
decision_id=decision_id,
product="pg_order_items_v1",
purpose="order_creation",
mutation={
"operation": "insert",
"records": [
{"order_id": 12345, "product_id": 5, "quantity": 2, "price": 99.99},
{"order_id": 12345, "product_id": 8, "quantity": 1, "price": 149.99}
]
},
api_key=api_key
)
Update Record
# Update order status
result = write_data(
decision_id=decision_id,
product="pg_orders_v1",
purpose="order_fulfillment",
mutation={
"operation": "update",
"records": [{
"order_id": 12345,
"status": "shipped",
"shipped_at": "2026-01-07T14:00:00Z",
"tracking_number": "TRACK123"
}]
},
api_key=api_key
)
Delete Record
# Cancel order
result = write_data(
decision_id=decision_id,
product="pg_orders_v1",
purpose="order_cancellation",
mutation={
"operation": "delete",
"records": [{
"order_id": 12345
}]
},
api_key=api_key
)
Best Practices
-
Evaluate policies first: Use
decision_evaluateto check policies before writing data -
Use idempotency keys: Include
idempotency_keyfor writes that may be retried to prevent duplicates -
Check data product configuration: Use
product_getto understand required/allowed columns and validation rules -
Validate before writing: Ensure all required fields are present and data types are correct
-
Handle validation errors: Provide clear error messages to users when validation fails
-
Commit decisions: Remember that writes are only permanent when you close the decision with
action: "commit" -
Use appropriate purposes: Specify purposes that match your use case and are allowed by the data product
-
Batch operations: When inserting multiple records, use the
recordsarray rather than multiple separate calls
Important Notes
-
Writes are not immediate: Writes are staged and only committed when you close the decision with
action: "commit" -
Approval may be required: If a decision requires approval, writes are blocked until approval is granted
-
Rollback on abort: If you close a decision with
action: "abort", all writes within that decision are rolled back -
Validation is strict: All validation rules must be satisfied or the write will fail
-
Policy evaluation: Some data products require policy evaluation before writes are allowed
-
Created records: The
created_recordsfield is only returned for insert operations when the data product is configured to return them
Related Methods
decision_create- Create a decision (required before writing)decision_evaluate- Evaluate policies before writingdecision_close- Commit or abort the decision (makes writes permanent or rolls them back)product_get- Get data product details (check write permissions and validation rules)