Skip to content

Tool Catalog API Reference

This document provides comprehensive documentation for all built-in tools in the Adaptive Sentience platform. Each tool includes detailed schemas, examples, and usage guidance.

Overview

Tools are the fundamental execution units in Adaptive Sentience. They are:

  • Deterministic: Same inputs produce same outputs (for most tools)
  • Schema-validated: Inputs automatically validated against JSON Schema
  • Capability-gated: Execution requires specific capability tokens
  • Versioned: Semantic versioning for backward compatibility
  • Tagged: Policy tags enable automatic policy enforcement

Tool Discovery

Tools can be discovered through multiple interfaces:

Via HTTP Gateway

curl http://127.0.0.1:8787/v1/catalog

Via MCP Server

curl -X POST http://127.0.0.1:8787/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}'

Via Python

from clients.unified_client import UnifiedToolClient

client = UnifiedToolClient()
toolhost = client.get_local_toolhost()
tools = toolhost.list_tools()

for tool in tools:
    print(f"{tool['name']} v{tool['version']}: {tool['description']}")

Tool Schema Format

Each tool has a standardized schema:

@dataclass
class ToolSchema:
    tool_id: str              # Stable identifier (e.g., "tool:pii_redact")
    name: str                 # Short name used by gateway/toolhost
    version: str              # Semantic version
    description: str          # Human-readable description
    input_schema: Dict        # JSON Schema for input validation
    output_schema: Dict       # JSON Schema for output structure
    required_capabilities: list[str]  # Capability tokens required
    policy_tags: list[str]    # Tags for policy enforcement
    deterministic: bool       # Whether tool is deterministic

Built-in Tools

1. unit_convert

Convert between units of measurement (length, temperature, mass).

Tool ID: tool:unit_convert

Version: 1.0.0

Deterministic: Yes

Required Capabilities: - tool:unit_convert

Policy Tags: - pure - No side effects - deterministic - Same inputs → same outputs - no_network - No network access required

Input Schema

{
  "type": "object",
  "properties": {
    "value": {
      "type": "number",
      "description": "Numeric value to convert"
    },
    "from_unit": {
      "type": "string",
      "description": "Source unit (e.g., 'km', 'mi', 'c', 'f', 'kg', 'lb')"
    },
    "to_unit": {
      "type": "string",
      "description": "Target unit (e.g., 'km', 'mi', 'c', 'f', 'kg', 'lb')"
    }
  },
  "required": ["value", "from_unit", "to_unit"],
  "additionalProperties": false
}

Supported Units

Length: - m, meter, meters → Meters - ft, foot, feet → Feet - km, kilometer, kilometers → Kilometers - mi, mile, miles → Miles

Temperature: - c, celsius → Celsius - f, fahrenheit → Fahrenheit

Mass: - kg, kilogram, kilograms → Kilograms - lb, lbs, pound, pounds → Pounds

Output Schema

{
  "type": "object",
  "properties": {
    "value": {
      "type": "number",
      "description": "Converted value"
    },
    "from_unit": {
      "type": "string",
      "description": "Original unit"
    },
    "to_unit": {
      "type": "string",
      "description": "Target unit"
    }
  },
  "required": ["value", "from_unit", "to_unit"]
}

Examples

Example 1: Miles to Kilometers

curl -X POST http://127.0.0.1:8787/v1/tool_call \
  -H "Content-Type: application/json" \
  -d '{
    "target": {"kind": "local"},
    "tool_name": "unit_convert",
    "tool_args": {
      "value": 10,
      "from_unit": "miles",
      "to_unit": "km"
    }
  }'

Response:

{
  "ok": true,
  "result": {
    "value": 16.0934,
    "from_unit": "miles",
    "to_unit": "km"
  }
}

Example 2: Celsius to Fahrenheit

from clients.unified_client import UnifiedToolClient

client = UnifiedToolClient()
result = client.call_tool_local("unit_convert", {
    "value": 100,
    "from_unit": "celsius",
    "to_unit": "fahrenheit"
})

print(f"100°C = {result['value']}°F")  # 100°C = 212.0°F

Example 3: Pounds to Kilograms

result = client.call_tool_local("unit_convert", {
    "value": 150,
    "from_unit": "pounds",
    "to_unit": "kg"
})

print(f"150 lbs = {result['value']} kg")  # 150 lbs = 68.0388 kg

Example 4: Feet to Meters

result = client.call_tool_local("unit_convert", {
    "value": 100,
    "from_unit": "feet",
    "to_unit": "meters"
})

print(f"100 ft = {result['value']} m")  # 100 ft = 30.48 m

Error Handling

try:
    result = client.call_tool_local("unit_convert", {
        "value": 10,
        "from_unit": "invalid_unit",
        "to_unit": "km"
    })
except ValueError as e:
    print(f"Error: {e}")  # Error: Unsupported unit: invalid_unit

2. pii_redact

Redact personally identifiable information (PII) from text using regex patterns.

WARNING: This is a heuristic demo implementation, NOT production-grade PII detection. For production use, employ specialized PII detection services with ML-based entity recognition.

Tool ID: tool:pii_redact

Version: 1.0.0

Deterministic: Yes

Required Capabilities: - tool:pii_redact

Policy Tags: - pii - Handles PII data - privacy - Privacy-sensitive operation - pure - No side effects - no_network - No network access required

Input Schema

{
  "type": "object",
  "properties": {
    "text": {
      "type": "string",
      "description": "Text to redact PII from"
    },
    "redact_emails": {
      "type": "boolean",
      "description": "Whether to redact email addresses",
      "default": true
    },
    "redact_phones": {
      "type": "boolean",
      "description": "Whether to redact phone numbers",
      "default": true
    },
    "replacement": {
      "type": "string",
      "description": "Replacement text for redacted content",
      "default": "[REDACTED]"
    }
  },
  "required": ["text"],
  "additionalProperties": false
}

Detection Patterns

Email Pattern: - Regex: \b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b - Matches: user@example.com, admin.user@company.co.uk

Phone Patterns (US-centric): - 123-456-7890 - 123.456.7890 - 123 456 7890 - (123) 456-7890 - (123)456-7890 - 1234567890

Output Schema

{
  "type": "object",
  "properties": {
    "redacted_text": {
      "type": "string",
      "description": "Text with PII redacted"
    },
    "redactions": {
      "type": "array",
      "description": "List of redactions performed",
      "items": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": ["email", "phone"]
          },
          "count": {
            "type": "integer"
          }
        },
        "required": ["type", "count"]
      }
    }
  },
  "required": ["redacted_text", "redactions"]
}

Examples

Example 1: Redact Email

curl -X POST http://127.0.0.1:8787/v1/tool_call \
  -H "Content-Type: application/json" \
  -d '{
    "target": {"kind": "local"},
    "tool_name": "pii_redact",
    "tool_args": {
      "text": "Contact support at admin@company.com for assistance"
    }
  }'

Response:

{
  "ok": true,
  "result": {
    "redacted_text": "Contact support at [REDACTED] for assistance",
    "redactions": [
      {
        "type": "email",
        "count": 1
      }
    ]
  }
}

Example 2: Redact Phone Number

result = client.call_tool_local("pii_redact", {
    "text": "Call me at 555-123-4567 or (555) 987-6543"
})

print(result["redacted_text"])
# Output: "Call me at [REDACTED] or [REDACTED]"
print(result["redactions"])
# Output: [{"type": "phone", "count": 2}]

Example 3: Custom Replacement

result = client.call_tool_local("pii_redact", {
    "text": "Email: john@example.com, Phone: 555-1234",
    "replacement": "***HIDDEN***"
})

print(result["redacted_text"])
# Output: "Email: ***HIDDEN***, Phone: ***HIDDEN***"

Example 4: Selective Redaction

# Only redact emails, keep phone numbers
result = client.call_tool_local("pii_redact", {
    "text": "Contact: admin@example.com or 555-123-4567",
    "redact_emails": True,
    "redact_phones": False
})

print(result["redacted_text"])
# Output: "Contact: [REDACTED] or 555-123-4567"

Example 5: Multiple PII Types

result = client.call_tool_local("pii_redact", {
    "text": """
    Customer report:
    Name: John Doe
    Email: john.doe@customer.com
    Phone: (555) 123-4567
    Alt Email: j.doe@gmail.com
    Mobile: 555.987.6543
    """
})

print(result["redacted_text"])
# Emails and phones are redacted
print(result["redactions"])
# [{"type": "email", "count": 2}, {"type": "phone", "count": 2}]

3. jsonschema_validate

Validate data against a JSON Schema with detailed error messages.

Tool ID: tool:jsonschema_validate

Version: 1.0.0

Deterministic: Yes

Required Capabilities: - tool:jsonschema_validate

Policy Tags: - validation - Data validation operation - pure - No side effects - deterministic - Same inputs → same outputs - no_network - No network access required

Input Schema

{
  "type": "object",
  "properties": {
    "schema": {
      "type": "object",
      "description": "JSON Schema to validate against"
    },
    "data": {
      "description": "Data to validate (any type)"
    }
  },
  "required": ["schema", "data"],
  "additionalProperties": false
}

Output Schema

{
  "type": "object",
  "properties": {
    "valid": {
      "type": "boolean",
      "description": "Whether data is valid"
    },
    "errors": {
      "type": "array",
      "description": "Validation error messages",
      "items": {
        "type": "string"
      }
    }
  },
  "required": ["valid", "errors"]
}

Examples

Example 1: Valid User Schema

result = client.call_tool_local("jsonschema_validate", {
    "schema": {
        "type": "object",
        "properties": {
            "name": {"type": "string"},
            "age": {"type": "number", "minimum": 0},
            "email": {"type": "string", "format": "email"}
        },
        "required": ["name", "age"]
    },
    "data": {
        "name": "Alice",
        "age": 30,
        "email": "alice@example.com"
    }
})

print(f"Valid: {result['valid']}")  # True
print(f"Errors: {result['errors']}")  # []

Example 2: Invalid Data (Missing Required Field)

result = client.call_tool_local("jsonschema_validate", {
    "schema": {
        "type": "object",
        "properties": {
            "name": {"type": "string"},
            "email": {"type": "string"}
        },
        "required": ["name", "email"]
    },
    "data": {
        "name": "Bob"
        # Missing email
    }
})

print(f"Valid: {result['valid']}")  # False
print(f"Errors: {result['errors']}")
# ["'email' is a required property"]

Example 3: Type Validation

result = client.call_tool_local("jsonschema_validate", {
    "schema": {
        "type": "object",
        "properties": {
            "count": {"type": "integer"},
            "price": {"type": "number"}
        }
    },
    "data": {
        "count": "not_a_number",
        "price": 29.99
    }
})

print(f"Valid: {result['valid']}")  # False
print(f"Errors: {result['errors']}")
# ["'not_a_number' is not of type 'integer'"]

Example 4: Array Validation

result = client.call_tool_local("jsonschema_validate", {
    "schema": {
        "type": "array",
        "items": {
            "type": "object",
            "properties": {
                "id": {"type": "integer"},
                "name": {"type": "string"}
            },
            "required": ["id", "name"]
        },
        "minItems": 1
    },
    "data": [
        {"id": 1, "name": "Item 1"},
        {"id": 2, "name": "Item 2"}
    ]
})

print(f"Valid: {result['valid']}")  # True

Example 5: Enum Validation

result = client.call_tool_local("jsonschema_validate", {
    "schema": {
        "type": "object",
        "properties": {
            "status": {
                "type": "string",
                "enum": ["pending", "active", "completed"]
            }
        },
        "required": ["status"]
    },
    "data": {
        "status": "invalid_status"
    }
})

print(f"Valid: {result['valid']}")  # False
print(f"Errors: {result['errors']}")
# ["'invalid_status' is not one of ['pending', 'active', 'completed']"]

Example 6: Complex Nested Schema

curl -X POST http://127.0.0.1:8787/v1/tool_call \
  -H "Content-Type: application/json" \
  -d '{
    "target": {"kind": "local"},
    "tool_name": "jsonschema_validate",
    "tool_args": {
      "schema": {
        "type": "object",
        "properties": {
          "user": {
            "type": "object",
            "properties": {
              "name": {"type": "string"},
              "contacts": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "type": {"type": "string", "enum": ["email", "phone"]},
                    "value": {"type": "string"}
                  },
                  "required": ["type", "value"]
                }
              }
            },
            "required": ["name"]
          }
        },
        "required": ["user"]
      },
      "data": {
        "user": {
          "name": "Alice",
          "contacts": [
            {"type": "email", "value": "alice@example.com"},
            {"type": "phone", "value": "555-1234"}
          ]
        }
      }
    }
  }'

4. doc_summarize

Create extractive summary of text using frequency-based sentence scoring.

Note: This is a simple heuristic approach. For production use, employ specialized NLP/LLM-based summarization services.

Tool ID: tool:doc_summarize

Version: 1.0.0

Deterministic: Yes

Required Capabilities: - tool:doc_summarize

Policy Tags: - nlp - Natural language processing - pure - No side effects - no_network - No network access required

Input Schema

{
  "type": "object",
  "properties": {
    "text": {
      "type": "string",
      "description": "Text to summarize"
    },
    "max_sentences": {
      "type": "integer",
      "description": "Maximum number of sentences in summary",
      "default": 3,
      "minimum": 1
    }
  },
  "required": ["text"],
  "additionalProperties": false
}

Output Schema

{
  "type": "object",
  "properties": {
    "summary": {
      "type": "string",
      "description": "Extractive summary"
    },
    "original_sentences": {
      "type": "integer",
      "description": "Number of sentences in original text"
    },
    "summary_sentences": {
      "type": "integer",
      "description": "Number of sentences in summary"
    },
    "method": {
      "type": "string",
      "description": "Summarization method used"
    }
  },
  "required": ["summary", "original_sentences", "summary_sentences", "method"]
}

Summarization Algorithm

  1. Sentence Splitting: Split text into sentences using .!? delimiters
  2. Word Tokenization: Extract words using regex \b\w+\b
  3. Stop Word Removal: Filter common words (the, a, an, and, etc.)
  4. Frequency Counting: Count word frequencies in the document
  5. Sentence Scoring: Score sentences by sum of word frequencies
  6. Top-K Selection: Select top K sentences by score
  7. Re-ordering: Restore original sentence order

Examples

Example 1: Summarize Article

text = """
Artificial intelligence is transforming how businesses operate.
Machine learning algorithms can analyze vast amounts of data quickly.
Companies are using AI to improve customer service and operations.
However, ethical considerations around AI deployment remain important.
Privacy concerns and algorithmic bias need to be addressed.
The future of AI depends on responsible development practices.
Regulations are being developed to ensure AI safety.
"""

result = client.call_tool_local("doc_summarize", {
    "text": text,
    "max_sentences": 3
})

print(result["summary"])
# Output: Top 3 most important sentences based on word frequency
print(f"Original: {result['original_sentences']} sentences")
print(f"Summary: {result['summary_sentences']} sentences")

Example 2: Short Summary

curl -X POST http://127.0.0.1:8787/v1/tool_call \
  -H "Content-Type: application/json" \
  -d '{
    "target": {"kind": "local"},
    "tool_name": "doc_summarize",
    "tool_args": {
      "text": "The quick brown fox jumps over the lazy dog. This is a test sentence. Another sentence for testing.",
      "max_sentences": 2
    }
  }'

Response:

{
  "ok": true,
  "result": {
    "summary": "The quick brown fox jumps over the lazy dog. This is a test sentence.",
    "original_sentences": 3,
    "summary_sentences": 2,
    "method": "extractive-frequency"
  }
}

Example 3: Single Sentence Summary

result = client.call_tool_local("doc_summarize", {
    "text": """
    Climate change is one of the biggest challenges facing humanity.
    Rising temperatures are causing extreme weather events.
    Scientists agree that immediate action is needed.
    Renewable energy adoption is increasing globally.
    However, more investment is required to meet climate goals.
    """,
    "max_sentences": 1
})

print(result["summary"])
# Returns the single most important sentence

Example 4: Already Short Text

result = client.call_tool_local("doc_summarize", {
    "text": "This is a short text.",
    "max_sentences": 5
})

print(result["summary"])
# Output: "This is a short text."
print(result["original_sentences"])  # 1
print(result["summary_sentences"])   # 1

Tool Versioning

Tools use semantic versioning (MAJOR.MINOR.PATCH):

  • MAJOR: Breaking changes to input/output schemas
  • MINOR: New features (backward compatible)
  • PATCH: Bug fixes (backward compatible)

Example version history:

tool:pii_redact
  1.0.0 - Initial release
  1.1.0 - Added SSN redaction (new feature)
  1.1.1 - Fixed phone number regex (bug fix)
  2.0.0 - Changed output format (breaking change)

Querying Available Tools

Via HTTP Gateway

# Get local catalog
curl http://127.0.0.1:8787/v1/catalog

# Get mesh catalog with enrichment
curl "http://127.0.0.1:8787/v1/catalog?enrich=true"

Via MCP

import requests

response = requests.post(
    "http://127.0.0.1:8787/mcp",
    json={
        "jsonrpc": "2.0",
        "id": 1,
        "method": "tools/list",
        "params": {}
    }
)

tools = response.json()["result"]["tools"]
for tool in tools:
    print(f"{tool['name']}: {tool['description']}")

Via Python Client

from clients.unified_client import UnifiedToolClient

client = UnifiedToolClient()
toolhost = client.get_local_toolhost()
tools = toolhost.list_tools()

# Filter by capability
pii_tools = [t for t in tools if "pii" in t.get("policy_tags", [])]

# Filter by determinism
deterministic_tools = [t for t in tools if t.get("deterministic", False)]

# Get specific tool
for tool in tools:
    if tool["name"] == "unit_convert":
        print(f"Version: {tool['version']}")
        print(f"Capability: {tool['required_capability']}")

Tool Execution Patterns

Pattern 1: Local Execution

Execute tool on gateway's local toolhost:

from clients.unified_client import UnifiedToolClient

client = UnifiedToolClient()
result = client.call_tool_local("pii_redact", {
    "text": "Contact admin@example.com"
})

Pattern 2: Remote Execution

Execute tool on specific remote node:

result = client.call_tool_remote(
    http_url="http://192.168.1.100:8000",
    tool_name="unit_convert",
    tool_args={
        "value": 10,
        "from_unit": "miles",
        "to_unit": "km"
    }
)

Pattern 3: Auto-Routing

Let gateway choose best available node:

curl -X POST http://127.0.0.1:8787/v1/tool_call \
  -H "Content-Type: application/json" \
  -d '{
    "target": {"kind": "auto"},
    "tool_name": "doc_summarize",
    "tool_args": {
      "text": "Long document here...",
      "max_sentences": 3
    }
  }'

Pattern 4: Workflow Chaining

Chain multiple tools together:

# Step 1: Redact PII
redacted = client.call_tool_local("pii_redact", {
    "text": "Contact john@example.com for info about the 10 mile race"
})

# Step 2: Summarize redacted text
summary = client.call_tool_local("doc_summarize", {
    "text": redacted["redacted_text"],
    "max_sentences": 1
})

# Step 3: Convert units mentioned
conversion = client.call_tool_local("unit_convert", {
    "value": 10,
    "from_unit": "miles",
    "to_unit": "km"
})

print(f"Summary: {summary['summary']}")
print(f"10 miles = {conversion['value']} km")

Policy Enforcement

Tools can be filtered by policy tags:

Privacy-Safe Tools

privacy_safe = [
    t for t in tools
    if "privacy" in t.get("policy_tags", [])
    or "pii" in t.get("policy_tags", [])
]

Deterministic Tools Only

deterministic = [
    t for t in tools
    if t.get("deterministic", False)
]

Network-Free Tools

offline_tools = [
    t for t in tools
    if "no_network" in t.get("policy_tags", [])
]

Custom Tool Development

To create a custom tool, follow this template:

# edge_node/tools/my_tool.py

from typing import Dict, Any


def my_tool(args: Dict[str, Any]) -> Dict[str, Any]:
    """
    Tool description.

    Args:
        args: {
            "param1": type,
            "param2": type
        }

    Returns:
        {
            "result_field": type
        }
    """
    # Validate inputs
    param1 = args.get("param1")
    if param1 is None:
        raise ValueError("Missing required field: param1")

    # Execute logic
    result = process(param1)

    # Return structured output
    return {
        "result_field": result
    }

Register in catalog:

# catalog/tool_schemas.py

TOOL_SCHEMAS["my_tool"] = ToolSchema(
    tool_id="tool:my_tool",
    name="my_tool",
    version="1.0.0",
    description="My custom tool",
    input_schema={
        "type": "object",
        "properties": {
            "param1": {"type": "string"}
        },
        "required": ["param1"]
    },
    output_schema={
        "type": "object",
        "properties": {
            "result_field": {"type": "string"}
        }
    },
    required_capabilities=["tool:my_tool"],
    policy_tags=["custom"],
    deterministic=True
)

Testing Tools

Unit Testing

import pytest
from edge_node.tools.pii_redact import pii_redact


def test_email_redaction():
    result = pii_redact({
        "text": "Contact admin@example.com"
    })
    assert "[REDACTED]" in result["redacted_text"]
    assert result["redactions"][0]["type"] == "email"
    assert result["redactions"][0]["count"] == 1


def test_phone_redaction():
    result = pii_redact({
        "text": "Call 555-123-4567"
    })
    assert "[REDACTED]" in result["redacted_text"]
    assert result["redactions"][0]["type"] == "phone"

Integration Testing

from clients.unified_client import UnifiedToolClient


def test_tool_execution():
    client = UnifiedToolClient()

    result = client.call_tool_local("unit_convert", {
        "value": 10,
        "from_unit": "miles",
        "to_unit": "km"
    })

    assert result["value"] == pytest.approx(16.0934, rel=1e-3)
    assert result["from_unit"] == "miles"
    assert result["to_unit"] == "km"

Performance Considerations

Tool Execution Latency

Typical latencies (local execution):

Tool Avg Latency Notes
unit_convert 1-5ms Pure computation
pii_redact 5-15ms Regex matching
jsonschema_validate 10-30ms Schema traversal
doc_summarize 20-100ms Depends on text length

Optimization Tips

  1. Cache tool schemas: Avoid repeated schema lookups
  2. Batch operations: Group multiple tool calls when possible
  3. Use local execution: Remote calls add network latency (50-200ms)
  4. Pre-validate inputs: Client-side validation reduces errors

Troubleshooting

Common Issues

Problem: "Unknown tool" error

Solution: Check tool name spelling and availability

tools = client.get_local_toolhost().list_tools()
print([t["name"] for t in tools])

Problem: "Invalid input" error

Solution: Validate against tool schema

from catalog.tool_schemas import get_tool_schema

schema = get_tool_schema("unit_convert")
print(schema.input_schema)

Problem: Tool execution timeout

Solution: Increase timeout or check node connectivity

curl http://192.168.1.100:8000/health

Changelog

  • v1.0.0 (2026-01-24): Initial tool catalog
  • unit_convert: Length, temperature, mass conversions
  • pii_redact: Email and phone number redaction
  • jsonschema_validate: JSON Schema validation
  • doc_summarize: Extractive text summarization