Documentation

MCP

Current MCP routes, scopes, execution envelopes, and runtime controls.

Copy-paste API examples
curl JavaScript Python Elixir
curl
curl https://api.texttree.ai/api/v1/messages \
  -H "Authorization: Bearer $TEXTREE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phone_number":"+15551234567","body":"Hello"}'

MCP

Textree exposes a narrow MCP surface for controlled tool discovery and execution.

Base routes

  • GET /mcp/health
  • GET /mcp/tools
  • POST /mcp/tools/:name

Local Phoenix development runs at http://localhost:4001.

Authentication and scopes

Authenticated MCP requests use Textree-issued bearer tokens. Humans, wallet users, and AI agents all present the same Authorization: Bearer <token> header after authenticating through Textree.

The current route-level scopes are:

  • GET /mcp/tools requires mcp:read
  • POST /mcp/tools/:name requires mcp:execute

Tool entries can also declare a more specific required scope in the server registry. If that happens, Textree records a blocked execution audit and returns 403 insufficient_scope.

List tools

GET /mcp/tools

curl https://api.texttree.ai/mcp/tools \
  -H "Authorization: Bearer $TEXTREE_ACCESS_TOKEN"

Success returns a registry-backed tool list:

{
  "tools": [
    {
      "name": "contacts.lookup",
      "description": "Look up a contact record for agent context.",
      "required_scope": "mcp:execute",
      "timeout_ms": 1000
    },
    {
      "name": "messages.preview",
      "description": "Preview an outbound SMS payload before execution.",
      "required_scope": "mcp:execute",
      "timeout_ms": 1000
    }
  ]
}

The current alpha registry is configured server-side. There is no public admin surface to mutate the registry at runtime.

Execute a tool

POST /mcp/tools/:name

Request body

{
  "params": {
    "body": "hello"
  }
}

curl

curl https://api.texttree.ai/mcp/tools/messages.preview \
  -H "Authorization: Bearer $TEXTREE_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "params": {
      "phone_number": "+15551234567",
      "body": "Can you confirm your appointment?"
    }
  }'

JavaScript

const response = await fetch("https://api.texttree.ai/mcp/tools/messages.preview", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.TEXTREE_ACCESS_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    params: {
      phone_number: "+15551234567",
      body: "Can you confirm your appointment?",
    },
  }),
});

const { execution } = await response.json();

Success response

{
  "execution": {
    "id": "513f6a41-2c33-4c15-b4e2-10da14ab806f",
    "tool": "messages.preview",
    "outcome": "succeeded",
    "params_summary": {
      "body": "hello"
    },
    "result_summary": {
      "accepted": true,
      "params": {
        "body": "hello"
      },
      "tool": "messages.preview"
    },
    "error_message": null,
    "duration_ms": 3,
    "inserted_at": "2026-04-26T21:02:15Z"
  }
}

Error responses

  • 403 with {"error":"tool_not_allowed"} when the tool is outside the configured allowlist
  • 403 with {"error":"insufficient_scope","required_scope":"..."} when the key lacks the route-level or tool-level scope
  • 429 with {"error":"quota_exceeded"} when the per-key quota window is exhausted
  • 504 with {"error":"execution_timed_out"} when the execution exceeds the configured timeout
  • 422 with {"error":"execution_failed"} when the executor returns an error

All of these execution paths return an execution envelope when Textree was able to create an audit record.

Runtime controls

The current alpha MCP runtime is intentionally strict:

  • execution is gated by Textree bearer-token scopes
  • tools must exist in the server registry
  • tools must also be present in the allowlist boundary
  • executions are persisted with actor, key, tool, params summary, outcome, and timestamp
  • per-key quotas are enforced over a rolling window
  • per-tool or global timeouts stop long-running work

Agent integration pattern

Use MCP tools for bounded context and previews, not ungoverned sends. An AI agent should:

  1. call contacts.lookup to gather recipient context
  2. call messages.preview to validate the proposed SMS
  3. hand off to your application for final send approval when required
  4. send through the normal /api/v1/messages endpoint so suppression, compliance, and spend gates run

This keeps agent workflows behind the same production controls as human and API sends.

Give an AI agent a phone number

For the May 17 launch path, an agent phone-number setup uses existing Textree identity, token, number, API, MCP, and log surfaces:

  1. Create an agent-scoped Textree bearer token with mcp:read, mcp:execute, and messages:write.
  2. Buy or connect a sender number in /app/numbers, or use the Numbers API with numbers:write.
  3. Use MCP for bounded context and previews.
  4. Send SMS through /api/v1/messages using the V1 phone_number field.
  5. Receive replies through signed inbound webhooks and review them in message, conversation, and provider-event logs.
  6. Use operator handoff when automation should pause or a human needs to review the conversation.

Current alpha constraints

  • MCP tooling is still config-backed rather than tenant-configurable
  • the default executor is intentionally simple and not a full dynamic tool runtime
  • there is no public audit-log viewer outside the Phoenix operator surfaces and repo database