Skip to content

MCP servers ​

10 endpoints. Every path below is relative to the API base URL and already includes the /api/v1 prefix — see conventions for authentication, pagination, errors and idempotency.

Endpoint
GET/mcp-serversLists the organization's MCP servers, newest first, optionally only the active ones
POST/mcp-serversRegisters an MCP server, encrypting its secrets and refusing a URL the SSRF guard blocks
GET/mcp-servers/{mcpServer}Returns one MCP server with its cached tool catalogue loaded
PUT/mcp-servers/{mcpServer}Updates an MCP server's transport, auth and tool policy, re-checking any new URL against the SSRF guard
DELETE/mcp-servers/{mcpServer}Removes an MCP server registration from the organization
POST/mcp-servers/{mcpServer}/discoverHandshakes with the MCP server, lists its tools, reconciles the cache and re-projects the tool rows
POST/mcp-servers/{mcpServer}/testHandshakes with the MCP server to check reachability and records the resulting health status
GET/mcp-servers/{mcpServer}/toolsReturns the full cached tool catalogue discovered from this MCP server with each tool's risk and enabled state
POST/mcp-servers/{mcpServer}/tools/{toolName}/enabledFlips one tool's allow/deny state on the server policy and re-projects the derived tool rows
POST/mcp-servers/{mcpServer}/tools/{toolName}/riskSets a risk-level override for one tool name and returns the whole server with its re-evaluated tool cache

Endpoints ​

Lists the organization's MCP servers, newest first, optionally only the active ones ​

GET/mcp-servers
  • Requires mcp.read.
  • Query params: active_only, limit (default 25, capped at 100).

Query parameters

NameTypeRequiredNotes
active_onlyboolean—default false
limitinteger—default 25
bash
curl -X GET "$CALLAGENT_API_URL/mcp-servers?active_only=false&limit=25" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/mcp-servers?active_only=false&limit=25`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/mcp-servers?active_only=false&limit=25');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.get(
    f"{os.environ['CALLAGENT_API_URL']}/mcp-servers?active_only=false&limit=25",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200Paginated set of McpServerResource

Errors

StatusWhen it happens
403The key lacks mcp.read

Example response, generated from the schema:

json
{
  "data": [
    {
      "id": "01JQ0000000000000000000000",
      "object": "string",
      "name": "Support Line",
      "description": "string",
      "url": "https://example.com/hook",
      "transport": "string",
      "auth_type": "string",
      "headers": {},
      "secret_keys": {},
      "provider_credential_id": "01JQ0000000000000000000000",
      "oauth_connection_id": "01JQ0000000000000000000000",
      "tool_policy": "string",
      "allowed_tools": {},
      "denied_tools": {},
      "tool_risk_overrides": {},
      "blocked_risk_levels": {},
      "default_risk_level": "string",
      "confirmation_policy": "string",
      "timeout_seconds": 30,
      "cache_ttl_seconds": 30,
      "active": true,
      "status": "string",
      "status_message": "string",
      "protocol_version": "string",
      "server_info": {},
      "capabilities": {},
      "tool_count": 1,
      "last_discovery_at": "2026-01-01T12:00:00+00:00",
      "last_health_check_at": "2026-01-01T12:00:00+00:00",
      "tools": [],
      "created_at": "2026-01-01T12:00:00+00:00"
    }
  ],
  "links": {
    "first": "string",
    "last": "string",
    "prev": "string",
    "next": "string"
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 1,
    "links": [
      {}
    ],
    "path": "string",
    "per_page": 25,
    "to": 1,
    "total": 1
  }
}

Registers an MCP server, encrypting its secrets and refusing a URL the SSRF guard blocks ​

POST/mcp-servers
  • Requires mcp.write.
  • bearer_token and secret headers are encrypted and never echoed back by the resource. url is required unless transport is stdio.

Request body

FieldTypeRequiredNotes
namestringyesmax 255 chars
descriptionstring | null—max 255 chars
transportstreamable_http · sse · stdioyes
urlstring | null—uri. max 2048 chars
stdio_configstring[] | null—
auth_typenone · static_headers · bearer · oauth · credential · null | null—
headersstring[] | null—
bearer_tokenstring | null—Secrets arrive as their own field and are encrypted before storage; they are never echoed back by the resource.. max 4096 chars
provider_credential_idstring | null—
oauth_connection_idstring | null—
tool_policyallow_all · allow_selected · deny_selected | null—
allowed_toolsstring[] | null—
denied_toolsstring[] | null—
tool_risk_overridesstring[] | null—
blocked_risk_levelsread · write · destructive · financial · privileged[] | null—
default_risk_levelread · write · destructive · financial · privileged | null—
confirmation_policynever · destructive · always | null—
timeout_secondsinteger | null—min 1. max 120
cache_ttl_secondsinteger | null—min 60. max 86400
activeboolean | null—
metadatastring[] | null—
bash
curl -X POST "$CALLAGENT_API_URL/mcp-servers" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "name": "Support Line",
       "transport": "streamable_http",
       "url": "https://example.com/hook",
       "auth_type": "none",
       "provider_credential_id": "01JQ0000000000000000000000",
       "oauth_connection_id": "01JQ0000000000000000000000",
       "tool_policy": "allow_all"
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/mcp-servers`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "name": "Support Line",
    "transport": "streamable_http",
    "url": "https://example.com/hook",
    "auth_type": "none",
    "provider_credential_id": "01JQ0000000000000000000000",
    "oauth_connection_id": "01JQ0000000000000000000000",
    "tool_policy": "allow_all"
  }),
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/mcp-servers');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
    'name' => 'Support Line',
    'transport' => 'streamable_http',
    'url' => 'https://example.com/hook',
    'auth_type' => 'none',
    'provider_credential_id' => '01JQ0000000000000000000000',
    'oauth_connection_id' => '01JQ0000000000000000000000',
    'tool_policy' => 'allow_all',
]),
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.post(
    f"{os.environ['CALLAGENT_API_URL']}/mcp-servers",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    json={
      "name": "Support Line",
      "transport": "streamable_http",
      "url": "https://example.com/hook",
      "auth_type": "none",
      "provider_credential_id": "01JQ0000000000000000000000",
      "oauth_connection_id": "01JQ0000000000000000000000",
      "tool_policy": "allow_all"
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
201McpServerResource

Errors

StatusWhen it happens
403The key lacks mcp.write
422Validation failed, an unknown transport, a missing URL, or a URL refused by the SSRF guard

Example response, generated from the schema:

json
{
  "data": {
    "id": "01JQ0000000000000000000000",
    "object": "string",
    "name": "Support Line",
    "description": "string",
    "url": "https://example.com/hook",
    "transport": "string",
    "auth_type": "string",
    "headers": {},
    "secret_keys": {},
    "provider_credential_id": "01JQ0000000000000000000000",
    "oauth_connection_id": "01JQ0000000000000000000000",
    "tool_policy": "string",
    "allowed_tools": {},
    "denied_tools": {},
    "tool_risk_overrides": {},
    "blocked_risk_levels": {},
    "default_risk_level": "string",
    "confirmation_policy": "string",
    "timeout_seconds": 30,
    "cache_ttl_seconds": 30,
    "active": true,
    "status": "string",
    "status_message": "string",
    "protocol_version": "string",
    "server_info": {},
    "capabilities": {},
    "tool_count": 1,
    "last_discovery_at": "2026-01-01T12:00:00+00:00",
    "last_health_check_at": "2026-01-01T12:00:00+00:00",
    "tools": [
      {}
    ],
    "created_at": "2026-01-01T12:00:00+00:00"
  }
}

Returns one MCP server with its cached tool catalogue loaded ​

GET/mcp-servers/{mcpServer}
  • Requires mcp.read.
  • Secrets are never returned; only which auth type is configured.

Path parameters

NameTypeRequiredNotes
mcpServerstringyesThe mcp server ID
bash
curl -X GET "$CALLAGENT_API_URL/mcp-servers/01JQ0000000000000000000000" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/mcp-servers/01JQ0000000000000000000000`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/mcp-servers/01JQ0000000000000000000000');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.get(
    f"{os.environ['CALLAGENT_API_URL']}/mcp-servers/01JQ0000000000000000000000",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200McpServerResource

Errors

StatusWhen it happens
403The key lacks mcp.read
404No such MCP server in this organization

Example response, generated from the schema:

json
{
  "data": {
    "id": "01JQ0000000000000000000000",
    "object": "string",
    "name": "Support Line",
    "description": "string",
    "url": "https://example.com/hook",
    "transport": "string",
    "auth_type": "string",
    "headers": {},
    "secret_keys": {},
    "provider_credential_id": "01JQ0000000000000000000000",
    "oauth_connection_id": "01JQ0000000000000000000000",
    "tool_policy": "string",
    "allowed_tools": {},
    "denied_tools": {},
    "tool_risk_overrides": {},
    "blocked_risk_levels": {},
    "default_risk_level": "string",
    "confirmation_policy": "string",
    "timeout_seconds": 30,
    "cache_ttl_seconds": 30,
    "active": true,
    "status": "string",
    "status_message": "string",
    "protocol_version": "string",
    "server_info": {},
    "capabilities": {},
    "tool_count": 1,
    "last_discovery_at": "2026-01-01T12:00:00+00:00",
    "last_health_check_at": "2026-01-01T12:00:00+00:00",
    "tools": [
      {}
    ],
    "created_at": "2026-01-01T12:00:00+00:00"
  }
}

Updates an MCP server's transport, auth and tool policy, re-checking any new URL against the SSRF guard ​

PUT/mcp-servers/{mcpServer}
  • Requires mcp.write.
  • PATCH is accepted on the same path, with the same body.

Path parameters

NameTypeRequiredNotes
mcpServerstringyesThe mcp server ID

Request body

FieldTypeRequiredNotes
namestring—max 255 chars
descriptionstring | null—max 255 chars
transportstreamable_http · sse · stdio—
urlstring | null—uri. max 2048 chars
stdio_configstring[] | null—
auth_typenone · static_headers · bearer · oauth · credential · null | null—
headersstring[] | null—
bearer_tokenstring | null—Secrets arrive as their own field and are encrypted before storage; they are never echoed back by the resource.. max 4096 chars
provider_credential_idstring | null—
oauth_connection_idstring | null—
tool_policyallow_all · allow_selected · deny_selected | null—
allowed_toolsstring[] | null—
denied_toolsstring[] | null—
tool_risk_overridesstring[] | null—
blocked_risk_levelsread · write · destructive · financial · privileged[] | null—
default_risk_levelread · write · destructive · financial · privileged | null—
confirmation_policynever · destructive · always | null—
timeout_secondsinteger | null—min 1. max 120
cache_ttl_secondsinteger | null—min 60. max 86400
activeboolean | null—
metadatastring[] | null—
bash
curl -X PUT "$CALLAGENT_API_URL/mcp-servers/01JQ0000000000000000000000" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "name": "Support Line",
       "transport": "streamable_http",
       "url": "https://example.com/hook",
       "auth_type": "none",
       "provider_credential_id": "01JQ0000000000000000000000",
       "oauth_connection_id": "01JQ0000000000000000000000",
       "tool_policy": "allow_all"
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/mcp-servers/01JQ0000000000000000000000`, {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "name": "Support Line",
    "transport": "streamable_http",
    "url": "https://example.com/hook",
    "auth_type": "none",
    "provider_credential_id": "01JQ0000000000000000000000",
    "oauth_connection_id": "01JQ0000000000000000000000",
    "tool_policy": "allow_all"
  }),
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/mcp-servers/01JQ0000000000000000000000');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
    'name' => 'Support Line',
    'transport' => 'streamable_http',
    'url' => 'https://example.com/hook',
    'auth_type' => 'none',
    'provider_credential_id' => '01JQ0000000000000000000000',
    'oauth_connection_id' => '01JQ0000000000000000000000',
    'tool_policy' => 'allow_all',
]),
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.put(
    f"{os.environ['CALLAGENT_API_URL']}/mcp-servers/01JQ0000000000000000000000",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    json={
      "name": "Support Line",
      "transport": "streamable_http",
      "url": "https://example.com/hook",
      "auth_type": "none",
      "provider_credential_id": "01JQ0000000000000000000000",
      "oauth_connection_id": "01JQ0000000000000000000000",
      "tool_policy": "allow_all"
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200McpServerResource

Errors

StatusWhen it happens
403The key lacks mcp.write
404No such MCP server in this organization
422Validation failed, an unknown transport, a missing URL, or a URL refused by the SSRF guard

Example response, generated from the schema:

json
{
  "data": {
    "id": "01JQ0000000000000000000000",
    "object": "string",
    "name": "Support Line",
    "description": "string",
    "url": "https://example.com/hook",
    "transport": "string",
    "auth_type": "string",
    "headers": {},
    "secret_keys": {},
    "provider_credential_id": "01JQ0000000000000000000000",
    "oauth_connection_id": "01JQ0000000000000000000000",
    "tool_policy": "string",
    "allowed_tools": {},
    "denied_tools": {},
    "tool_risk_overrides": {},
    "blocked_risk_levels": {},
    "default_risk_level": "string",
    "confirmation_policy": "string",
    "timeout_seconds": 30,
    "cache_ttl_seconds": 30,
    "active": true,
    "status": "string",
    "status_message": "string",
    "protocol_version": "string",
    "server_info": {},
    "capabilities": {},
    "tool_count": 1,
    "last_discovery_at": "2026-01-01T12:00:00+00:00",
    "last_health_check_at": "2026-01-01T12:00:00+00:00",
    "tools": [
      {}
    ],
    "created_at": "2026-01-01T12:00:00+00:00"
  }
}

Removes an MCP server registration from the organization ​

DELETE/mcp-servers/{mcpServer}
  • Requires mcp.write.
  • This response is not data-wrapped.
  • Body is a bare {"deleted": true, "id": "..."}. Deleting needs only mcp.write; there is no separate mcp.delete permission.

Path parameters

NameTypeRequiredNotes
mcpServerstringyesThe mcp server ID
bash
curl -X DELETE "$CALLAGENT_API_URL/mcp-servers/01JQ0000000000000000000000" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/mcp-servers/01JQ0000000000000000000000`, {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/mcp-servers/01JQ0000000000000000000000');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.delete(
    f"{os.environ['CALLAGENT_API_URL']}/mcp-servers/01JQ0000000000000000000000",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200Bare JSON object, not data-wrapped

Errors

StatusWhen it happens
403The key lacks mcp.write
404No such MCP server in this organization

Example response, generated from the schema:

json
{
  "deleted": true,
  "id": null
}

Handshakes with the MCP server, lists its tools, reconciles the cache and re-projects the tool rows ​

POST/mcp-servers/{mcpServer}/discover
  • Requires mcp.write.
  • force defaults to true, so a plain call always hits the network; send force:false to accept a fresh cache. Discovery is a write, so it needs mcp.write.

Path parameters

NameTypeRequiredNotes
mcpServerstringyesThe mcp server ID

Request body

FieldTypeRequiredNotes
forceboolean—default true
bash
curl -X POST "$CALLAGENT_API_URL/mcp-servers/01JQ0000000000000000000000/discover" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "force": true
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/mcp-servers/01JQ0000000000000000000000/discover`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "force": true
  }),
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/mcp-servers/01JQ0000000000000000000000/discover');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
    'force' => true,
]),
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.post(
    f"{os.environ['CALLAGENT_API_URL']}/mcp-servers/01JQ0000000000000000000000/discover",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    json={
      "force": True
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200JSON object

Errors

StatusWhen it happens
403The key lacks mcp.write
404No such MCP server in this organization
502The handshake or tools/list call to the remote server failed

Example response, generated from the schema:

json
"string"

Handshakes with the MCP server to check reachability and records the resulting health status ​

POST/mcp-servers/{mcpServer}/test
  • Requires mcp.write.
  • Nothing is persisted beyond the health status and an audit entry. Connecting to a third party is treated as a write, so it needs mcp.write.

Path parameters

NameTypeRequiredNotes
mcpServerstringyesThe mcp server ID
bash
curl -X POST "$CALLAGENT_API_URL/mcp-servers/01JQ0000000000000000000000/test" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/mcp-servers/01JQ0000000000000000000000/test`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/mcp-servers/01JQ0000000000000000000000/test');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.post(
    f"{os.environ['CALLAGENT_API_URL']}/mcp-servers/01JQ0000000000000000000000/test",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200JSON object

Errors

StatusWhen it happens
403The key lacks mcp.write
404No such MCP server in this organization
502The handshake to the remote server failed

Example response, generated from the schema:

json
"string"

Returns the full cached tool catalogue discovered from this MCP server with each tool's risk and enabled state ​

GET/mcp-servers/{mcpServer}/tools
  • Requires mcp.read.
  • Not paginated: every cached tool is returned in one response. Reflects the last discovery, not a live call to the server.

Path parameters

NameTypeRequiredNotes
mcpServerstringyesThe mcp server ID
bash
curl -X GET "$CALLAGENT_API_URL/mcp-servers/01JQ0000000000000000000000/tools" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/mcp-servers/01JQ0000000000000000000000/tools`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/mcp-servers/01JQ0000000000000000000000/tools');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.get(
    f"{os.environ['CALLAGENT_API_URL']}/mcp-servers/01JQ0000000000000000000000/tools",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200Array of McpCachedToolResource

Errors

StatusWhen it happens
403The key lacks mcp.read
404No such MCP server in this organization

Example response, generated from the schema:

json
{
  "data": [
    {
      "id": "01JQ0000000000000000000000",
      "object": "string",
      "mcp_server_id": "01JQ0000000000000000000000",
      "name": "Support Line",
      "title": "string",
      "description": "string",
      "input_schema": {},
      "output_schema": {},
      "annotations": {},
      "risk_level": "string",
      "requires_confirmation": true,
      "enabled": true,
      "disabled_reason": "string",
      "discovered_at": "2026-01-01T12:00:00+00:00",
      "expires_at": "2026-01-01T12:00:00+00:00"
    }
  ]
}

Flips one tool's allow/deny state on the server policy and re-projects the derived tool rows ​

POST/mcp-servers/{mcpServer}/tools/{toolName}/enabled
  • Requires mcp.write.
  • Edits the server's allowed_tools/denied_tools lists, not the cache row, so the next discovery does not undo it. toolName in the path is camelCase.

Path parameters

NameTypeRequiredNotes
mcpServerstringyesThe mcp server ID
toolNamestringyes

Request body

FieldTypeRequiredNotes
enabledbooleanyes
bash
curl -X POST "$CALLAGENT_API_URL/mcp-servers/01JQ0000000000000000000000/tools/Support Line/enabled" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "enabled": true
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/mcp-servers/01JQ0000000000000000000000/tools/Support Line/enabled`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "enabled": true
  }),
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/mcp-servers/01JQ0000000000000000000000/tools/Support Line/enabled');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
    'enabled' => true,
]),
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.post(
    f"{os.environ['CALLAGENT_API_URL']}/mcp-servers/01JQ0000000000000000000000/tools/Support Line/enabled",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    json={
      "enabled": True
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200McpCachedToolResource

Errors

StatusWhen it happens
403The key lacks mcp.write
404No such MCP server, or no cached tool by that name
422enabled is missing or is not a boolean

Example response, generated from the schema:

json
{
  "data": {
    "id": "01JQ0000000000000000000000",
    "object": "string",
    "mcp_server_id": "01JQ0000000000000000000000",
    "name": "Support Line",
    "title": "string",
    "description": "string",
    "input_schema": {},
    "output_schema": {},
    "annotations": {},
    "risk_level": "string",
    "requires_confirmation": true,
    "enabled": true,
    "disabled_reason": "string",
    "discovered_at": "2026-01-01T12:00:00+00:00",
    "expires_at": "2026-01-01T12:00:00+00:00"
  }
}

Sets a risk-level override for one tool name and returns the whole server with its re-evaluated tool cache ​

POST/mcp-servers/{mcpServer}/tools/{toolName}/risk
  • Requires mcp.write.
  • Unlike the enabled route this never checks that the tool exists: an unknown toolName is stored as an override and answers 200. toolName in the path is camelCase.

Path parameters

NameTypeRequiredNotes
mcpServerstringyesThe mcp server ID
toolNamestringyes

Request body

FieldTypeRequiredNotes
risk_levelread · write · destructive · financial · privilegedyes§37. Ordered by blast radius — atLeast() is what the confirmation policy and the per-organization block list are expressed in.
bash
curl -X POST "$CALLAGENT_API_URL/mcp-servers/01JQ0000000000000000000000/tools/Support Line/risk" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "risk_level": "read"
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/mcp-servers/01JQ0000000000000000000000/tools/Support Line/risk`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "risk_level": "read"
  }),
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/mcp-servers/01JQ0000000000000000000000/tools/Support Line/risk');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
    'risk_level' => 'read',
]),
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.post(
    f"{os.environ['CALLAGENT_API_URL']}/mcp-servers/01JQ0000000000000000000000/tools/Support Line/risk",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    json={
      "risk_level": "read"
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200McpServerResource

Errors

StatusWhen it happens
403The key lacks mcp.write
404No such MCP server in this organization
422risk_level is missing or is not a valid level

Example response, generated from the schema:

json
{
  "data": {
    "id": "01JQ0000000000000000000000",
    "object": "string",
    "name": "Support Line",
    "description": "string",
    "url": "https://example.com/hook",
    "transport": "string",
    "auth_type": "string",
    "headers": {},
    "secret_keys": {},
    "provider_credential_id": "01JQ0000000000000000000000",
    "oauth_connection_id": "01JQ0000000000000000000000",
    "tool_policy": "string",
    "allowed_tools": {},
    "denied_tools": {},
    "tool_risk_overrides": {},
    "blocked_risk_levels": {},
    "default_risk_level": "string",
    "confirmation_policy": "string",
    "timeout_seconds": 30,
    "cache_ttl_seconds": 30,
    "active": true,
    "status": "string",
    "status_message": "string",
    "protocol_version": "string",
    "server_info": {},
    "capabilities": {},
    "tool_count": 1,
    "last_discovery_at": "2026-01-01T12:00:00+00:00",
    "last_health_check_at": "2026-01-01T12:00:00+00:00",
    "tools": [
      {}
    ],
    "created_at": "2026-01-01T12:00:00+00:00"
  }
}

Documented against the code. Anything not yet implemented is labelled, never described as working.