Use in workflows
Workflow type: "AI" nodes call external tools through MCP connectors. These nodes run with an organization automation token, not the triggering user's session, so a per-user OAuth connector is not callable from a workflow. The workflow-usable OAuth paths are organization-level OAuth: either one-time admin consent (authorization code) or a fully headless client credentials exchange.
This page uses the atlassian MCP connector as the running example. You can substitute any OAuth-based MCP connector your admin has registered and published.
If the connector supports API keys, shared header authentication is usually simpler for automated workflows. Use organization-level OAuth when the connector requires OAuth.
We will:
- Get an organization access token.
- Connect the connector at the organization level (authorization code or client credentials, depending on how the connector is configured).
- Validate that the connection is
usable. - Create a workflow with one
type: "AI"node scoped to a single connector tool. - Trigger the workflow and verify the tool's response.
Client credentials connectors are connected from the Port UI, once, by an admin. Port stores those tokens at the organization level, so connecting them takes two clicks and no API calls - see step 2.
Authorization code connectors store tokens per user, so connecting as yourself in the UI does not make the connector callable from a workflow. Those connectors need the API flow in step 2, run with your organization credentials.
Prerequisites
Before you start, make sure you have:
- A registered and published MCP connector with at least one tool enabled under Allowed Tools.
- Admin access in the same Port organization, including the organization's
Client IDandClient Secret. curlandjqinstalled.- The identifier of the MCP connector, as set when it was registered. Find it on the MCP servers catalog page at
app.port.io/<your-org-id>/_mcp_serversin the Identifier column.
Step 1: Set your region and get an organization access token
Set the API base URL for your region, then set your organization credentials and connector identifier. Later commands reuse $API_BASE, $CLIENT_ID, $CLIENT_SECRET, and $CONNECTOR.
- EU region
- US region
API_BASE='https://api.port.io'
API_BASE='https://api.us.port.io'
CLIENT_ID='<CLIENT_ID>'
CLIENT_SECRET='<CLIENT_SECRET>'
CONNECTOR='atlassian'
Replace <CLIENT_ID> and <CLIENT_SECRET> with your organization credentials from the Credentials page, and set CONNECTOR to your MCP connector identifier if it differs from atlassian.
Exchange your organization credentials for an access token. This token is organization-level, not personal.
TOKEN=$(curl -s -X POST "$API_BASE/v1/auth/access_token" \
-H 'Content-Type: application/json' \
-d "{\"clientId\":\"$CLIENT_ID\",\"clientSecret\":\"$CLIENT_SECRET\"}" \
| jq -r '.accessToken')
You can also generate this token in the Port UI: open the Credentials modal, select the Organization tab, and click Generate API token. See Create an access token.
Step 2: Connect at the organization level
Follow the option below that matches the connector's OAuth grant type.
Client credentials
Connect the connector from the Port UI:
- Open the MCP Servers modal and select the External MCP tab.
- Click Connect on the connector.
There is no consent screen. Port exchanges the connector's OAuth Client ID and Client Secret with the upstream server and stores the resulting tokens for the whole organization, so one admin connecting once is enough for every workflow.
Authorization code
Paste this whole block to get a short-lived session token for the connector and open the upstream provider's consent screen in your browser.
SESSION_TOKEN=$(curl -s "$API_BASE/v1/mcp/oauth2/servers/$CONNECTOR/session-token" \
-H 'Accept: application/json' \
-H "Authorization: Bearer $TOKEN" \
| jq -r '.sessionToken')
AUTH_URL=$(curl -s -o /dev/null -w '%{redirect_url}' \
"$API_BASE/v1/mcp/oauth2/authenticate?server_id=$CONNECTOR&session_token=$SESSION_TOKEN")
if [ -z "$AUTH_URL" ]; then
echo "No redirect URL returned. Check that TOKEN and SESSION_TOKEN are valid and not expired." >&2
elif command -v open >/dev/null 2>&1; then
open "$AUTH_URL"
elif command -v xdg-open >/dev/null 2>&1; then
xdg-open "$AUTH_URL"
else
echo "Open this URL in a browser: $AUTH_URL"
fi
In the browser, confirm the authorization and approve the permissions for the MCP app. Port then stores the OAuth connection at the organization level. Upstream actions in the external tool are attributed to the account you consent with, not to each workflow triggerer. This consent is needed once; Port refreshes the token where supported.
The server_id is the Port-side identifier of the registered connector (for example atlassian), not the upstream MCP URL. See Get OAuth2 session token and Initiate OAuth2 authentication.
Step 3: Validate the connection
Confirm the connector is connected and callable before wiring it into a workflow. This check applies to the authorization code flow above.
This endpoint reports whether the calling identity has connected the connector, so a client credentials connector that an admin connected in the UI can still report usable: false here. Its tokens are stored for the organization and the workflow AI node will use them, so verify with the smoke test in step 5 instead.
curl -s "$API_BASE/v1/mcp/user/servers?includeTools=true" \
-H "Authorization: Bearer $TOKEN" \
| jq --arg id "$CONNECTOR" '.servers[] | select(.identifier==$id) | {identifier, usable, error, toolNames: [.tools[].name]}'
Look for usable: true, which means the organization-level OAuth connection is live and callable by an AI node. If error is populated, recheck steps 1 and 2. The toolNames are the prefixed tool names you scope to in the workflow node's tools array.
MCP tool names follow the {identifier}_{upstream} convention, for example atlassian_atlassianUserInfo, atlassian_getJiraIssue, or atlassian_searchConfluenceUsingCql. The prefix is the connector identifier. Use these exact prefixed names in the tools array.
Step 4: Create a workflow AI node that calls the connector
We will create the simplest possible workflow: a self-serve trigger feeding one type: "AI" node that calls a single Atlassian tool through the atlassian connector, with a structured outputSchema.
Save the workflow definition to a file:
Smoke-test workflow JSON (click to expand)
{
"identifier": "mcp-atlassian-smoke-test",
"title": "MCP Atlassian smoke test",
"description": "Calls the Atlassian MCP connector from a workflow AI node.",
"icon": "Atlassian",
"nodes": [
{
"identifier": "trigger",
"title": "Trigger",
"config": {
"type": "SELF_SERVE_TRIGGER",
"userInputs": { "properties": {} }
}
},
{
"identifier": "ai-call",
"title": "Call Atlassian MCP",
"config": {
"type": "AI",
"userPrompt": "Call the atlassian_atlassianUserInfo tool once and return the authenticated user name and email as JSON.",
"systemPrompt": "Call atlassian_atlassianUserInfo exactly once, then return the JSON schema immediately. Do not call other tools. Do not loop.",
"tools": ["atlassian_atlassianUserInfo"],
"mcpServers": [{ "identifier": "atlassian" }],
"outputSchema": {
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": "string" }
},
"required": ["name", "email"]
}
}
}
],
"connections": [
{ "sourceIdentifier": "trigger", "targetIdentifier": "ai-call" }
]
}
Create the workflow with the Create a workflow API:
curl -s -X POST "$API_BASE/v1/workflows" \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d @mcp-atlassian-smoke-test.json | jq
Key fields:
mcpServers: [{ "identifier": "atlassian" }]references the connector by its Port-side identifier. This must equal$CONNECTORfrom step 1, so update it if you swapped connectors.tools: ["atlassian_atlassianUserInfo"]scopes the AI node to one tool, using the{identifier}_{upstream}naming convention from step 3. Use explicit tool lists in workflows, not defaults.systemPromptcaps the AI to one tool call and forces an immediate return, which prevents runaway loops in automated runs.outputSchemaforces a structured JSON response so downstream nodes can parse fields directly.
See external MCP connectors in workflows and MCP servers in API requests for the full node shape and patterns.
Step 5: Trigger the workflow and verify
Trigger a run, then poll it until the status is COMPLETED or FAILED (about 60 seconds max):
RUN_ID=$(curl -s -X POST "$API_BASE/v1/workflows/mcp-atlassian-smoke-test/runs" \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{}' | jq -r '.workflowRun.identifier')
for i in $(seq 1 12); do
STATUS=$(curl -s "$API_BASE/v1/workflows/runs/$RUN_ID" -H "Authorization: Bearer $TOKEN" | jq -r '.workflowRun.status')
[[ "$STATUS" == "COMPLETED" || "$STATUS" == "FAILED" ]] && break
sleep 5
done
curl -s "$API_BASE/v1/workflows/runs/$RUN_ID" \
-H "Authorization: Bearer $TOKEN" | jq '.workflowRun.status, .workflowRun.result, .workflowRun.nodeRuns'
A successful run returns status: "COMPLETED" and result: "SUCCESS", and the ai-call node output contains the tool's response. That confirms the AI node reached the connector and returned real data. If the status is FAILED, inspect nodeRuns for the error. See Trigger a workflow run and Get a workflow run by identifier.
Next steps
- Swap the smoke-test tool for a real one, such as
atlassian_getJiraIssueoratlassian_searchConfluenceUsingCql, and wire the AI node into a larger workflow with downstream nodes that parse theoutputSchemafields. - Scope the
toolsarray to the minimum set the workflow needs, and keep thesystemPromptconstrained to prevent loops in automated runs. - If the connector supports API keys, compare this approach with shared header authentication to pick the right method for automated callers.
- If a connector only needs to be callable from interactive Port AI chat (not workflows), use the per-user authenticate to connectors flow instead.