Skip to main content

Automation-Backed Action Tool

Description

This sample gives an AI agent the ability to do something rather than just read: it exposes a webhook-triggered automation as a Model Context Protocol (MCP) tool. The agent calls the tool, Stack9 runs the automation with the tool arguments as the request body, and the automation's last action output is returned to the agent.

Unlike query tools, automation tools have no schema auto-derivation — an automation tool without an inputSchema exposes zero arguments to the agent, so the inline schema below is mandatory rather than optional. Authorization comes from the same automation-permission model the automation's HTTP webhook route uses, and it fails closed: if no permission record exists for the automation, the call is refused.

Use Case

A customer-support assistant has triaged an inbound email, identified the customer, and needs to raise a ticket. Instead of the agent calling a bespoke HTTP endpoint with hand-rolled auth, it calls the create_support_ticket MCP tool on the instance and receives the created ticket's id and reference back.

Key Features

  • Write/side-effecting action exposed safely to an agent
  • Mandatory inline inputSchema with per-argument descriptions
  • Arguments passed through as the automation body (trigger.body)
  • Gated by app_automation_permissions — fail-closed, no record means no access
  • Runs as the calling user, so downstream audit fields attribute correctly
  • Returns the automation's last action output to the agent

The automation it points at

src/automations/create_support_ticket.json

{
"key": "create_support_ticket",
"name": "Create support ticket",
"entityKey": "support_ticket",
"app": "support",
"triggerType": "webhook",
"triggerParams": {
"method": "post",
"path": "/create-support-ticket"
},
"actions": [
{
"name": "Validate customer exists",
"key": "validate_customer",
"actionTypeKey": "entity_find",
"params": {
"entityKey": "customer",
"query": {
"$where": { "id": "{{trigger.body.customer_id}}" }
}
}
},
{
"name": "Create the ticket",
"key": "create_ticket",
"actionTypeKey": "entity_create",
"params": {
"entityKey": "support_ticket",
"body": {
"customer_id": "{{trigger.body.customer_id}}",
"subject": "{{trigger.body.subject}}",
"body": "{{trigger.body.body}}",
"priority": "{{trigger.body.priority}}",
"channel": "ai_assistant",
"status": "open"
}
}
}
]
}

Two things to notice:

  • The automation must have "triggerType": "webhook" — the Console's tool picker only lists webhook automations, and no other trigger type can be invoked through MCP.
  • The triggerParams.path is irrelevant to MCP. MCP invokes the automation by key, not over its HTTP route. The path only matters if you also want the automation reachable as a normal webhook endpoint.

JSON Definition

src/mcps/support_actions.json

{
"key": "support_actions",
"name": "Support Actions",
"description": "Write actions the support assistant may perform on behalf of an agent.",
"tools": [
{
"key": "create_support_ticket",
"name": "create_support_ticket",
"description": "Create a support ticket against an existing customer. Requires the numeric Stack9 customer id — look it up first if you only have a name or email. Returns the created ticket id and reference.",
"sourceType": "automation",
"inputSchema": {
"customer_id": {
"type": "number",
"description": "Numeric Stack9 customer id the ticket belongs to"
},
"subject": {
"type": "string",
"description": "One-line summary of the issue, max ~120 characters"
},
"body": {
"type": "string",
"description": "Full description of the issue, including any steps to reproduce"
},
"priority": {
"type": "string",
"description": "One of: low, medium, high. Defaults to medium when omitted.",
"optional": true
},
"metadata": {
"type": "object",
"description": "Optional free-form context, e.g. source email id or conversation id",
"optional": true
}
}
}
]
}

Permission setup

The automation belongs to the support app, so access is decided by that app's automation permission record:

  • If no permission record exists for create_support_ticket, every MCP call is refused with 403. This is deliberate — an automation is not exposed by accident.
  • If a record exists, the caller's role for the support app must meet or exceed the record's required role.
  • If the record's required role is Public, any authenticated caller passes.
warning

An automation tool is a write path. Grant the agent's principal the narrowest app role that satisfies the permission record, and prefer a dedicated Stack9 user for the agent so its actions are attributable and revocable independently of a human account.

Result

The tool returns the last action's output. With the automation above, that is the create_ticket action:

{
"content": [
{
"type": "text",
"text": "{\"id\":9114,\"reference\":\"TKT-9114\",\"status\":\"open\",\"priority\":\"medium\"}"
}
]
}

If the last action produces no output, the tool returns null. Order your actions so the one whose result the agent needs is last.

Notes

  • Always declare inputSchema for automation tools. There is no generated-model fallback for sourceType: automation; without a schema the agent can only call the tool with an empty body.
  • The whole arguments object becomes the body. Every argument is available in the automation as trigger.body.{argument}. There is no filter/variable partitioning as there is for query tools.
  • object and array are untyped. The metadata argument accepts any object shape; validate it inside the automation if the shape matters.
  • Errors are sanitized. A Stack9 validation or permission failure is returned to the agent with its message. Any other failure — a broken action, a database error — is returned as the generic Tool 'create_support_ticket' failed due to an internal error and logged server-side. Debug from the Core logs, not from the agent transcript.
  • Idempotency is your responsibility. An agent that retries a failed call may create a duplicate ticket. If that matters, add a dedupe key argument and handle it in the automation.
  • Endpoint for this config: {coreBaseUrl}/api/mcp/support_actions.