Workflow: MCP Server (McpTool & McpResource)
Every organization gets its own MCP (Model Context Protocol) server whose tools and resources are defined as workflows. AI assistants and agents (Claude, Claude Code, and any other MCP-compatible client) connect to your organization's MCP endpoint and can only see and call what your organization has explicitly defined — none of the platform's built-in tools are exposed there.
Two workflow types drive the MCP server:
McpTool— exposes the workflow as an MCP tool the AI can call with argumentsMcpResource— exposes the workflow as an MCP resource the AI can read (documentation, glossaries, live reference data)
MCP workflows are ideal when you need to:
- Give AI assistants safe, curated access to your TMS data and actions
- Build an org-specific AI toolset (order lookups, quote calculations, status updates) backed by workflow logic
- Publish org knowledge (shipping terms, process guides, live reference data) that AI assistants can read as resources
- Control exactly what an AI can do — the tool surface is precisely the set of
McpToolworkflows you activate
Endpoint
Each organization's MCP server is served at:
/public-api/v1/{orgUniqueId}/mcp
Where {orgUniqueId} is your organization's unique identifier (UUID format).
The server uses the MCP Streamable HTTP transport in stateless mode — clients POST JSON-RPC messages (initialize, tools/list, tools/call, resources/list, resources/read) directly to this URL.
Authentication
The MCP endpoint requires a Bearer token — either a user JWT or a Personal Access Token (PAT):
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
In addition to a valid token, the caller must be a member of the organization in the URL. Access is rejected otherwise:
| Status | Condition |
|---|---|
401 | Missing or invalid token. The response includes a WWW-Authenticate: Bearer resource_metadata="..." challenge for OAuth-capable MCP clients |
403 | Valid token, but the user is not a member of the organization (system administrators are exempt) |
404 | Unknown organization identifier |
Unlike Public API workflows, MCP workflows do not have a per-workflow authentication setting — authentication is enforced once at the connection level for the whole server.
Server Configuration
The MCP server's identity and instructions come from the organization configuration named tms.mcp:
| Key | Applied to | Default |
|---|---|---|
name | Server name shown to MCP clients | "{orgUniqueId} MCP Server" |
version | Server version | "1.0.0" |
instructions | Server instructions — guidance the AI receives about how to use your tools | none |
Use instructions to orient the AI: describe your organization's terminology, when to use which tool, and any conventions it should follow. The configuration is optional — missing values fall back to the defaults above.
MCP Tools (workflowType: McpTool)
An McpTool workflow becomes a callable MCP tool. The tool's name, description, and input schema are generated from the workflow manifest.
YAML Structure
mcp:
name: "get_order_status"
description: "Look up an order's current status by order number"
timeout: 60
workflow:
name: "MCP / Get Order Status"
workflowId: "00000000-0000-0000-0000-000000000000"
workflowType: "McpTool"
executionMode: "Sync" # Required: must be Sync
isActive: true
inputs:
- name: "orderNumber"
type: "string"
props:
required: true
description: "The TMS order number"
outputs:
- name: "response"
mapping: "stepName.result"
activities:
- name: myActivity
steps:
- task: "SomeTask@1"
name: "stepName"
# ...
The mcp Section (Tools)
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | - | Tool name shown to the AI. Must match ^[a-zA-Z0-9_-]{1,64}$ (letters, digits, _, -). Must be unique within the organization |
description | string | No | - | Tool description — this is how the AI decides when to use the tool, so make it specific |
timeout | number | No | 60 | Workflow execution timeout in seconds |
If two active workflows declare the same tool name, the first one (by workflow ID) wins and a warning is logged.
Inputs → Tool Schema
The workflow's inputs section is translated into the tool's JSON Schema, which MCP clients show to the AI. Unlike Public API workflows, there is no props.in location — MCP tools take named arguments, and each input becomes a named schema property.
Input type | JSON Schema type |
|---|---|
string (or omitted / unknown) | string |
integer / int | integer |
number / decimal / float / double | number |
boolean / bool | boolean |
object | object |
array | array |
Input props:
| Property | Type | Description |
|---|---|---|
required | boolean | Marks the argument as required in the tool schema. Calls missing a required argument are rejected before the workflow runs |
description | string | Argument description shown to the AI |
Argument values are validated and coerced the same way as Public API inputs: numbers and booleans accept native JSON values or parseable strings, and invalid values produce a per-argument error message. Extra arguments not declared in inputs are passed through to the workflow as-is.
Outputs
The workflow's response output becomes the tool result, serialized as JSON:
| Output Name | Required | Description |
|---|---|---|
response | No | The tool result returned to the AI. If omitted, the full outputs dictionary is returned instead |
outputs:
- name: "response"
mapping: "fetchData.result"
Execution Semantics
- Tools execute the workflow synchronously (
executionMode: Syncis required). - If the workflow fails or times out, the tool returns an error result (
isError: true) with the failure message — the AI sees the error and can react or retry. - If the arguments are invalid (missing required, wrong type), the tool returns an error result listing the problems and the workflow is not executed.
- Calling an unknown tool name returns an MCP protocol error.
MCP Resources (workflowType: McpResource)
An McpResource workflow becomes a readable MCP resource. Reading the resource executes the workflow and returns its response output as the content.
YAML Structure
mcp:
uri: "tms://docs/shipping-terms"
name: "Shipping Terms Glossary"
description: "Org-specific shipping terminology used in orders"
mimeType: "text/markdown"
timeout: 60
workflow:
name: "MCP / Shipping Terms Glossary"
workflowId: "00000000-0000-0000-0000-000000000000"
workflowType: "McpResource"
executionMode: "Sync" # Required: must be Sync
isActive: true
outputs:
- name: "response"
mapping: "buildContent.result"
activities:
- name: content
steps:
- task: "Utilities/SetVariable@1"
name: "buildContent"
# ...
The mcp Section (Resources)
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
uri | string | Yes | - | Resource URI. Must be an absolute URI (any scheme, e.g. tms://docs/shipping-terms). Must be unique within the organization |
name | string | No | workflow name | Display name shown to the AI |
description | string | No | - | Resource description |
mimeType | string | No | application/json | Content MIME type |
timeout | number | No | 60 | Workflow execution timeout in seconds |
Content Mapping
- If the
responseoutput is a string andmimeTypestarts withtext/(e.g.text/markdown,text/plain), the string is returned as-is. - Otherwise, the
responseoutput (or the full outputs dictionary when there is noresponse) is JSON-serialized. - Resources execute with no input arguments.
- Workflow failures and timeouts surface as MCP protocol (JSON-RPC) errors — resources have no
isErrorresult form.
Validation Rules
MCP workflows are validated at save time:
| Code | Rule |
|---|---|
MCP_001 | mcp section is required |
MCP_002 | mcp.name is required for McpTool workflows |
MCP_003 | mcp.name must match ^[a-zA-Z0-9_-]{1,64}$ |
MCP_004 | mcp.uri is required for McpResource workflows |
MCP_005 | mcp.uri must be an absolute URI |
MCP_006 | mcp.timeout must be zero (use default) or positive |
MCP_007 | executionMode must be Sync |
See Workflow Validation Errors for details and solutions.
Connecting an MCP Client
Point any MCP-compatible client at your organization's endpoint with a Bearer token. For example, in Claude Code (.mcp.json):
{
"mcpServers": {
"my-org-tms": {
"type": "http",
"url": "https://your-domain.com/public-api/v1/{orgUniqueId}/mcp",
"headers": {
"Authorization": "Bearer ${TMS_PAT}"
}
}
}
}
You can also probe the server directly with curl:
curl -X POST "https://your-domain.com/public-api/v1/{orgUniqueId}/mcp" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Examples
Example 1: Tool - Get Order Status
mcp:
name: "get_order_status"
description: "Look up a TMS order's current status, dates, and customer by order number. Use when the user asks about a specific order."
timeout: 30
workflow:
name: "MCP / Get Order Status"
workflowId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
workflowType: "McpTool"
executionMode: "Sync"
isActive: true
inputs:
- name: "orderNumber"
type: "string"
props:
required: true
description: "The order number, e.g. ORD-2026-0001"
outputs:
- name: "response"
mapping: "fetchOrder.result"
activities:
- name: lookup
steps:
- task: "Query/GraphQL@1"
name: "fetchOrder"
inputs:
query: |
query {
orders(
organizationId: {{ organizationId }},
filter: { orderNumber: "{{ orderNumber }}" },
take: 1
) {
items {
orderId
orderNumber
orderDate
orderStatus { orderStatusName }
customer { name }
}
}
}
outputs:
- name: "result"
mapping: "orders.items"
When the AI calls get_order_status with {"orderNumber": "ORD-2026-0001"}, the workflow runs and the tool returns the serialized order data.
Example 2: Resource - Shipping Terms Glossary
mcp:
uri: "tms://docs/shipping-terms"
name: "Shipping Terms Glossary"
description: "Definitions of org-specific shipping terminology"
mimeType: "text/markdown"
workflow:
name: "MCP / Shipping Terms Glossary"
workflowId: "b2c3d4e5-f6a7-8901-bcde-f23456789012"
workflowType: "McpResource"
executionMode: "Sync"
isActive: true
outputs:
- name: "response"
mapping: "content.result"
activities:
- name: glossary
steps:
- task: "Utilities/SetVariable@1"
name: "content"
inputs:
variables:
- name: "result"
value: |
# Shipping Terms
- **FOB** — Free on Board: seller covers costs until goods are loaded
- **Linehaul** — Long-distance transport between terminals
- **Drayage** — Short-distance container transport, typically port to warehouse
Because the response is a string and the mimeType is text/markdown, the AI receives the markdown content as-is when it reads tms://docs/shipping-terms.
Best Practices
- Write tool descriptions for the AI, not for humans — say when to use the tool and what it returns
- Use snake_case tool names (
get_order_status,create_quote) — the common MCP convention - Mark required arguments with
props.requiredand describe every argument — the schema is all the AI sees - Set
instructionsin thetms.mcpconfig to give the AI org-level context that applies across tools - Keep timeouts realistic — AI clients wait synchronously for tool results
- Use resources for stable knowledge (glossaries, guides) and tools for parameterized data access
- Deactivate a workflow (
isActive: false) to instantly remove its tool/resource from the server