Dureach exposes 14 MCP tools named dureach.<action>. Every tool validates unknown fields strictly: extra fields return a validation error. Use the exact bounds below; out-of-range values return invalid_arguments.
Which tools are available?
| Tool | Risk | Required scope | Purpose |
|---|---|---|---|
dureach.workspace.context | R0 | workspace:read | Return workspace ID, name, caller role, and granted scopes. |
dureach.workspace.capabilities | R0 | workspace:read | List actions available to this connection. |
dureach.companies.search | R1 | companies:read | Search company records by keyword. |
dureach.companies.read | R1 | companies:read | Read one company by UUID. |
dureach.trade.search | R1 | trade:read | Search trade activity records. |
dureach.trade.query | R1 | trade:read | Run a read-only SQL query against the shipments view. |
dureach.contacts.search | R1 | contacts:read | Search contact records by keyword. |
dureach.contacts.query | R1 | contacts:read | Run a read-only SQL query against the contacts view. |
dureach.leads.list | R1 | leads:read | List workspace leads with pagination. |
dureach.leads.create | R2 | leads:create | Create a lead; supports dry_run and idempotency_key. |
dureach.campaigns.list | R1 | campaigns:read | List campaigns with pagination. |
dureach.campaigns.draft | R2 | campaigns:create | Draft a campaign; supports dry_run and idempotency_key. |
dureach.email.send | R3 | emails:send | Send via an owner-reviewed standing policy; requires an active policy_id, and supports dry_run previews and idempotency keys. |
dureach.sms.send | R3 | sms:send | Send via an owner-reviewed standing policy; same rules as email send. |
Use tools/list to discover the tools available to your connection. Availability depends on the granted permissions and workspace access. Start with read scopes; ask a workspace administrator to review missing access rather than requesting broad permissions.
What arguments does each tool accept?
workspace.context and workspace.capabilities
No arguments. Send {}.
{"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {"name": "dureach.workspace.capabilities", "arguments": {}}}companies.search
| Field | Type | Bounds | Default |
|---|---|---|---|
query | string | 1–200 chars, non-blank | required |
page | integer | 1–20 | 1 |
limit | integer | 1–50 | 25 |
{"query": "industrial valves", "page": 1, "limit": 10}companies.read
| Field | Type | Details |
|---|---|---|
company_id | UUID | required |
Unknown IDs return company_not_found.
trade.search
| Field | Type | Bounds | Default |
|---|---|---|---|
query | string | 3–100 chars | required |
dataset | enum | all, imports, exports, shipments | all |
page | integer | 1–20 | 1 |
limit | integer | 1–50 | 25 |
contacts.search
| Field | Type | Bounds | Default |
|---|---|---|---|
query | string | 3–100 chars | required |
page | integer | 1–40 | 1 |
limit | integer | 1–25 | 25 |
Short queries under 3 characters return a validation error. Use contacts.query when keyword search is not selective enough.
contacts.query and trade.query
| Field | Type | Bounds | Default |
|---|---|---|---|
sql | string | at most 16 KiB UTF-8, read-only grammar | required |
page | integer | 1–20 | 1 |
limit | integer | 1–50 | 25 |
Do not include SQL LIMIT/OFFSET; use page/limit instead. Page 2 and higher require ORDER BY. Grammar details are in the MCP SQL reader.
leads.list and campaigns.list
| Field | Type | Bounds | Default |
|---|---|---|---|
page | integer | 1–20 | 1 |
limit | integer | 1–50 | 25 |
leads.create
| Field | Type | Details |
|---|---|---|
email | required, at most 254 chars | |
first_name | string | optional, at most 255 chars |
last_name | string | optional, at most 255 chars |
company_name | string | optional, at most 255 chars |
idempotency_key | UUID | Required for an actual write or send; reuse the same UUID when retrying the same action with unchanged arguments. |
dry_run | boolean | optional, default false; true previews without writing |
campaigns.draft
| Field | Type | Details |
|---|---|---|
name | string | required, at most 255 chars |
idempotency_key | UUID | Required for an actual write or send; reuse the same UUID when retrying the same action with unchanged arguments. |
dry_run | boolean | optional, default false |
email.send and sms.send
| Field | Type | Details |
|---|---|---|
policy_id | UUID | required; standing send policy that authorizes the send |
recipient | string | required, at most 255 chars |
idempotency_key | UUID | Required for an actual write or send; reuse the same UUID when retrying the same action with unchanged arguments. |
dry_run | boolean | optional, default false |
Sends without an active policy return policy_not_found or policy_not_authorized. Budget, suppression, and quota failures return policy_budget_exceeded, policy_daily_cap_exceeded, recipient_suppressed, recipient_already_attempted, or send_quota_exceeded. Never retry a send with a fresh idempotency key; reuse the original key.
How are results and errors shaped?
Success returns one text item with JSON plus a matching structuredContent object validated against the tool output contract. Results larger than 1 MiB return result_too_large instead of partial data.
Failures return isError: true:
{"error": {"code": "invalid_arguments", "details": {"field": "limit"}},
"request_id": "REQ_ID"}Common codes: unknown_action (use a name from the table with the dureach. prefix), invalid_arguments, scope_required, plan_capability_required, quota_exceeded (with limit_type, reset_at, retry_after), company_not_found, policy_not_found, policy_not_authorized, result_too_large, action_internal_error.