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 path is organization-level OAuth: an admin establishes one OAuth connection for the organization using the organization's Client ID and Client Secret.
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.
- Start the OAuth flow and complete the one-time admin consent.
- 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.
Organization-level OAuth still requires an admin to complete the upstream provider's consent screen once in a browser. You use the organization Client ID and Client Secret to obtain the Port access token that starts the flow, but the upstream consent is a one-time interactive step. Fully headless OAuth 2.0 client credentials from Port to the upstream MCP server are not yet supported.
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: click your profile picture, open Credentials, select the Organization tab, and click Generate API token. See Create an access token.
Step 2: Complete the OAuth consent
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.
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.