Claude managed agents integration action
The Claude managed agents integration action allows workflows to create new agents or trigger agent sessions directly using your installed Claude Managed Agents integration.
Prerequisites
- A Claude Managed Agents integration installed in your Port organization.
- Actions processing must be enabled on your integration:
- Hosted by Port: actions processing is enabled automatically.
- Self-hosted (Helm or Docker): actions processing is disabled by default and must be explicitly enabled.
Configuration
| Field | Type | Description |
|---|---|---|
type | "INTEGRATION_ACTION" | Required. Must be "INTEGRATION_ACTION" |
installationId | string | Required. Your Claude Managed Agents integration installation ID |
integrationProvider | "claude-managed-agents" | Required. Must be "claude-managed-agents" |
integrationInvocationType | string | Required. Operation type: "trigger_agent" or "create_agent" |
integrationActionExecutionProperties | object | Required. Operation-specific configuration |
Trigger agent
Starts a new session or continues an existing idle session, then sends a user message to the agent.
Set reportSessionStatus: true only after configuring a webhook on your integration (see webhook configuration). With it set to true, the node waits for a session webhook to mark the run as complete; without a webhook configured, the node blocks indefinitely. The default, false, completes the node immediately after the prompt is sent.
Execution properties
| Field | Type | Description |
|---|---|---|
agentId | string | Required. The ID of the Claude agent to trigger |
environmentId | string | Required when starting a new session |
prompt | string | Required. The user message to send to the agent |
sessionId | string | An existing idle session to continue. When provided, environmentId and config are ignored |
reportSessionStatus | boolean | When true, the node waits for the session to reach a terminal state via webhook (requires a webhook configured on the integration). Defaults to false, which completes immediately after the prompt is sent |
config | object | Passed through to the sessions API for new sessions. Supports vault IDs, resources, metadata, and other session creation parameters |
Basic example
Trigger an agent with a prompt, waiting for the session to complete:
{
"identifier": "trigger-agent",
"title": "Trigger Claude Agent",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "<your-installation-id>",
"integrationProvider": "claude-managed-agents",
"integrationInvocationType": "trigger_agent",
"integrationActionExecutionProperties": {
"agentId": "{{ .outputs.trigger.agentId.identifier }}",
"environmentId": "{{ .outputs.trigger.environmentId.identifier }}",
"prompt": "{{ .outputs.trigger.prompt }}",
"reportSessionStatus": true
}
}
}
Create agent
Creates a new Claude managed agent and registers it in Port's catalog.
Execution properties
| Field | Type | Description |
|---|---|---|
name | string | Required. The agent name |
model | string | Required. The Claude model ID (e.g., claude-sonnet-4-5) |
systemPrompt | string | The agent's system prompt |
config | object | Additional agent configuration passed directly to the Anthropic agents API (e.g., tools, mcp_servers, multiagent, skills) |
Basic example
Create a minimal agent with a name, model, and system prompt:
{
"identifier": "create-agent",
"title": "Create Claude Agent",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "<your-installation-id>",
"integrationProvider": "claude-managed-agents",
"integrationInvocationType": "create_agent",
"integrationActionExecutionProperties": {
"name": "{{ .outputs.trigger.name }}",
"model": "{{ .outputs.trigger.model }}",
"systemPrompt": "{{ .outputs.trigger.systemPrompt }}"
}
}
}
The complete workflow example for Create Claude Agent shows MCP toggles, tool configuration, and agent skill selection as form fields. The MCP options reference credential vaults in Claude - see MCP server setup below for how to create them.
MCP server setup
The Create Claude Agent workflow includes Enable Port MCP and Enable GitHub MCP toggles. When enabled, they inject the corresponding MCP server configuration into the agent. To use them, you first need a Claude credential vault that holds the authentication token for each MCP server. Create vaults once and reference them by ID when creating agents and triggering sessions.
Port MCP
The Port MCP server exposes your Port catalog and platform to Claude agents. Enabling the Port MCP toggle in the Create Agent workflow adds the server to the agent's mcp_servers configuration with a read-only subset of tools (list_entities, list_blueprints, list_scorecards, load_skill, describe_user_details). You still need to attach a vault ID when triggering sessions so Claude can authenticate against the MCP server.
Two options are available for the vault credential - choose based on whose identity the agent should use:
Option A: Authorize as a Port user (OAuth 2.1 PKCE)
This option authorizes the MCP connection as the Port user who runs the script. The resulting token is user-scoped - the agent sees and acts on behalf of that specific user. It is well suited for development or for dedicated agent users. For production workloads that need a service account identity, use Option B instead.
The Port MCP server uses OAuth 2.1 Authorization Code with PKCE. The script below handles the full flow and creates the vault and credential in Claude automatically (Python 3 standard library only - no extra dependencies). Claude stores the refresh token and renews the access token automatically, so no rotation is needed.
Before running: set your Anthropic API key as an environment variable:
export ANTHROPIC_API_KEY="<your-anthropic-api-key>"
Token and vault setup script (click to expand)
#!/usr/bin/env python3
"""Port MCP OAuth token generator (DCR + PKCE, stdlib only).
Creates the Claude vault and mcp_oauth credential automatically.
Requires: ANTHROPIC_API_KEY environment variable."""
import base64
import datetime
import hashlib
import json
import os
import secrets
import urllib.parse
import urllib.request
import webbrowser
from http.server import BaseHTTPRequestHandler, HTTPServer
# EU region: MCP_URL = "https://mcp.getport.io/v1"
# US region: MCP_URL = "https://mcp.us.getport.io/v1"
MCP_URL = "https://mcp.getport.io/v1"
CALLBACK_PORT = 9000 # change if the port is already in use
CLIENT_NAME = "port-mcp" # label shown in the Port authorization screen
VAULT_DISPLAY_NAME = "Port MCP" # change to identify the agent or user this vault is for
SCOPE = "openid profile email offline_access"
REDIRECT_URI = f"http://localhost:{CALLBACK_PORT}/callback"
ANTHROPIC_API_KEY = os.environ["ANTHROPIC_API_KEY"]
ANTHROPIC_HEADERS = {
"x-api-key": ANTHROPIC_API_KEY,
"anthropic-version": "2023-06-01",
"anthropic-beta": "managed-agents-2026-04-01",
"Content-Type": "application/json",
}
# 1. Dynamic Client Registration
reg_body = json.dumps({
"client_name": CLIENT_NAME,
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "none",
"redirect_uris": [REDIRECT_URI],
"scope": SCOPE,
}).encode()
with urllib.request.urlopen(
urllib.request.Request(
f"{MCP_URL}/register",
data=reg_body,
headers={"Content-Type": "application/json"},
method="POST",
)
) as r:
client = json.load(r)
client_id = client["client_id"]
print(f"Registered client: {client_id}")
# 2. PKCE - the code_verifier proves possession at token time; no client_secret
# is needed because the server is configured for public clients
# (token_endpoint_auth_method: none).
code_verifier = secrets.token_urlsafe(48)
code_challenge = (
base64.urlsafe_b64encode(hashlib.sha256(code_verifier.encode()).digest())
.rstrip(b"=")
.decode()
)
# 3. Loopback callback server
captured: dict[str, str | None] = {"code": None}
class _Handler(BaseHTTPRequestHandler):
def do_GET(self) -> None:
captured["code"] = urllib.parse.parse_qs(
urllib.parse.urlparse(self.path).query
).get("code", [None])[0]
self.send_response(200)
self.send_header("Content-Type", "text/html")
self.end_headers()
self.wfile.write(b"<h2>Authorization complete - return to your terminal.</h2>")
def log_message(self, *_: object) -> None:
pass
server = HTTPServer(("localhost", CALLBACK_PORT), _Handler)
auth_url = (
f"{MCP_URL}/authorize"
f"?response_type=code"
f"&client_id={urllib.parse.quote(client_id)}"
f"&redirect_uri={urllib.parse.quote(REDIRECT_URI)}"
f"&scope={urllib.parse.quote(SCOPE)}"
f"&code_challenge={code_challenge}"
f"&code_challenge_method=S256"
)
print("\nOpening browser for authorization...")
webbrowser.open(auth_url)
print(f"If the browser did not open, visit:\n {auth_url}\n")
server.handle_request()
code = captured["code"]
if not code:
raise SystemExit("ERROR: no authorization code received.")
# 4. Token exchange
token_body = urllib.parse.urlencode({
"grant_type": "authorization_code",
"code": code,
"client_id": client_id,
"redirect_uri": REDIRECT_URI,
"code_verifier": code_verifier,
}).encode()
with urllib.request.urlopen(
urllib.request.Request(
f"{MCP_URL}/token",
data=token_body,
headers={"Content-Type": "application/x-www-form-urlencoded"},
method="POST",
)
) as r:
tokens = json.load(r)
expires_in = tokens.get("expires_in", 3600)
expires_at = (
datetime.datetime.now(datetime.timezone.utc)
+ datetime.timedelta(seconds=expires_in)
).isoformat()
# 5. Create Claude vault
vault_body = json.dumps({"display_name": VAULT_DISPLAY_NAME}).encode()
with urllib.request.urlopen(
urllib.request.Request(
"https://api.anthropic.com/v1/vaults",
data=vault_body,
headers=ANTHROPIC_HEADERS,
method="POST",
)
) as r:
vault = json.load(r)
vault_id = vault["id"]
print(f"\nCreated vault: {vault_id} ({VAULT_DISPLAY_NAME})")
# 6. Create mcp_oauth credential with auto-refresh block
cred_body = json.dumps({
"display_name": "Port MCP credential",
"auth": {
"type": "mcp_oauth",
"mcp_server_url": MCP_URL,
"access_token": tokens["access_token"],
"expires_at": expires_at,
"refresh": {
"token_endpoint": f"{MCP_URL}/token",
"client_id": client_id,
"refresh_token": tokens["refresh_token"],
"token_endpoint_auth": {"type": "none"},
},
},
}).encode()
with urllib.request.urlopen(
urllib.request.Request(
f"https://api.anthropic.com/v1/vaults/{vault_id}/credentials",
data=cred_body,
headers=ANTHROPIC_HEADERS,
method="POST",
)
) as r:
cred = json.load(r)
print(f"Created mcp_oauth credential: {cred['id']}")
print(f"\n=== Vault ID (pass this in vault_ids when triggering sessions) ===")
print(vault_id)
After the script completes, copy the vault ID printed at the end and pass it in the Vaults field of the Trigger Claude Agent form.
Option B: Use a Port service account token
This option uses a dedicated Port service account (a non-human bot user). The MCP connection acts under the service account's identity. This token is a static bearer - it does not support automatic refresh. It expires after a short period (20 minutes minimum), so you must rotate it on a schedule.
Create service account, generate token, and create vault credential (click to expand)
Step 1 - Create a Port service account:
Service account identifiers must use the @serviceaccounts.getport.io domain. The clientId and clientSecret are returned once in additionalData.credentials - store them securely.
curl -s -X POST 'https://api.port.io/v1/blueprints/_user/entities' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <PORT_ACCESS_TOKEN>' \
-d '{
"identifier": "claude-mcp-agent@serviceaccounts.getport.io",
"title": "Claude MCP Agent",
"blueprint": "_user",
"properties": {
"port_type": "Service Account",
"port_role": "Member",
"status": "Active"
},
"relations": {}
}'
Copy additionalData.credentials.clientId and additionalData.credentials.clientSecret from the response.
Step 2 - Generate an access token for the service account:
# EU region
curl -s -X POST \
-H 'Content-Type: application/json' \
-d '{"clientId": "<SA_CLIENT_ID>", "clientSecret": "<SA_CLIENT_SECRET>"}' \
'https://api.port.io/v1/auth/access_token' | jq -r .accessToken
# US region
# curl -s -X POST \
# -H 'Content-Type: application/json' \
# -d '{"clientId": "<SA_CLIENT_ID>", "clientSecret": "<SA_CLIENT_SECRET>"}' \
# 'https://api.us.port.io/v1/auth/access_token' | jq -r .accessToken
Step 3 - Create the Claude vault and credential:
# 1. Create a vault
curl -s https://api.anthropic.com/v1/vaults \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "Content-Type: application/json" \
-d '{"display_name": "Port service account"}' | jq -r .id
# 2. Add a static_bearer credential (use EU or US MCP URL to match your region)
# EU: "mcp_server_url": "https://mcp.getport.io/v1"
# US: "mcp_server_url": "https://mcp.us.getport.io/v1"
curl -s https://api.anthropic.com/v1/vaults/<VAULT_ID>/credentials \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "Content-Type: application/json" \
-d '{
"display_name": "Port service account token",
"auth": {
"type": "static_bearer",
"mcp_server_url": "https://mcp.getport.io/v1",
"token": "<PORT_ACCESS_TOKEN>"
}
}' | jq -r .id
Step 4 - Rotate the token:
Once the credential exists, update it in place with a fresh token by posting to its specific <CREDENTIAL_ID> (returned by Step 3) instead of the /credentials collection:
curl -s https://api.anthropic.com/v1/vaults/<VAULT_ID>/credentials/<CREDENTIAL_ID> \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "Content-Type: application/json" \
-d '{
"display_name": "Port service account token",
"auth": {
"type": "static_bearer",
"token": "<PORT_ACCESS_TOKEN>"
}
}'
Access tokens expire. Set up a cron job that repeats Steps 2 and 4 every 15 minutes to avoid session failures.
GitHub MCP (optional, for pull requests)
The GitHub MCP server gives agents access to the GitHub API through MCP. The workflow template enables only create_pull_request by default - the minimum permission needed to open a PR after the agent has committed and pushed its changes.
Clone, commit, and push operations are handled separately by the github_repository session resource together with the githubAuthorizationToken configured on the integration. You do not need GitHub MCP for those operations.
Token permissions
Use a fine-grained personal access token with the minimum required scope:
| Action | Required scope |
|---|---|
| Create pull requests | repo (classic) or Pull requests: read/write (fine-grained) |
Clone, commit, and push are handled by the github_repository session resource using the githubAuthorizationToken set on the integration - not the vault credential. Configure that token with Contents: read/write scope separately.
Setup
To enable GitHub MCP on an agent, toggle Enable GitHub MCP in the Create Agent workflow. Create the vault credential using the Claude API:
Create vault and credential (click to expand)
# 1. Create a vault (skip if reusing an existing one)
curl -s https://api.anthropic.com/v1/vaults \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "Content-Type: application/json" \
-d '{"display_name": "GitHub MCP"}' | jq -r .id
# 2. Add a static_bearer credential
curl -s https://api.anthropic.com/v1/vaults/<VAULT_ID>/credentials \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "Content-Type: application/json" \
-d '{
"display_name": "GitHub PAT",
"auth": {
"type": "static_bearer",
"mcp_server_url": "https://api.githubcopilot.com/mcp/",
"token": "<GITHUB_PERSONAL_ACCESS_TOKEN>"
}
}'
Pass the vault ID in the Vaults field of the Trigger Claude Agent form to attach it to a session.
Complete workflow examples
Replace all <...> placeholders (e.g. <your-installation-id>) with your actual values before using these workflows.
Trigger Claude Agent - full workflow JSON (click to expand)
{
"title": "Trigger Claude Agent",
"icon": "Claude",
"description": "Trigger a Claude managed agent by starting a new session or continuing an idle session with a follow-up prompt.",
"category": "Claude Agents",
"allowAnyoneToViewRuns": true,
"nodes": [
{
"identifier": "trigger",
"title": "Trigger Claude Agent",
"icon": "Claude",
"config": {
"type": "SELF_SERVE_TRIGGER",
"contexts": [
{
"on": "ENTITY",
"userInput": "sessionId"
}
],
"userInputs": {
"properties": {
"sessionMode": {
"title": "Session mode",
"description": "Start a new session, or continue an existing idle session with another prompt.",
"type": "string",
"enum": ["new", "continue"],
"default": {
"jqQuery": "if ((.form.sessionId // \"\") | length) > 0 then \"continue\" else \"new\" end"
}
},
"agentId": {
"title": "Agent",
"type": "string",
"format": "entity",
"blueprint": "claude_agent"
},
"environmentId": {
"title": "Environment",
"description": "Required when starting a new session.",
"type": "string",
"format": "entity",
"blueprint": "claude_environment",
"disabled": { "jqQuery": ".form.sessionMode != \"new\"" }
},
"sessionId": {
"title": "Session",
"description": "Select an idle session to continue.",
"type": "string",
"format": "entity",
"blueprint": "claude_session",
"dataset": {
"combinator": "and",
"rules": [
{ "property": "status", "operator": "=", "value": "idle" },
{ "relation": "agent", "operator": "=", "value": { "jqQuery": ".form.agentId.identifier" } }
]
},
"disabled": { "jqQuery": ".form.sessionMode != \"continue\"" }
},
"title": {
"title": "Session title",
"type": "string",
"disabled": { "jqQuery": ".form.sessionMode != \"new\"" }
},
"metadata": {
"title": "Metadata",
"description": "Optional key-value metadata for a new session.",
"type": "object",
"additionalProperties": true,
"disabled": { "jqQuery": ".form.sessionMode != \"new\"" }
},
"vaultIds": {
"title": "Vaults",
"description": "Vaults to attach to the session (e.g. a vault holding Port MCP credentials).",
"type": "array",
"items": {
"type": "string",
"format": "entity",
"blueprint": "claude_vault"
},
"disabled": { "jqQuery": ".form.sessionMode != \"new\"" }
},
"memoryStoreIds": {
"title": "Memory stores",
"type": "array",
"items": {
"type": "string",
"format": "entity",
"blueprint": "claude_memory_store"
},
"disabled": { "jqQuery": ".form.sessionMode != \"new\"" }
},
"githubRepoUrls": {
"title": "GitHub repositories",
"description": "Optional GitHub repository URLs to mount. Requires githubAuthorizationToken on the integration.",
"type": "array",
"items": {
"type": "string",
"format": "url"
},
"disabled": { "jqQuery": ".form.sessionMode != \"new\"" }
},
"prompt": {
"title": "Prompt",
"type": "string",
"format": "multi-line"
}
},
"required": {
"jqQuery": "if .form.sessionMode == \"new\" then [\"sessionMode\", \"agentId\", \"environmentId\", \"prompt\"] elif .form.sessionMode == \"continue\" then [\"sessionMode\", \"agentId\", \"sessionId\", \"prompt\"] else [\"sessionMode\", \"agentId\", \"prompt\"] end"
},
"order": [
"sessionMode",
"agentId",
"environmentId",
"sessionId",
"title",
"metadata",
"vaultIds",
"memoryStoreIds",
"githubRepoUrls",
"prompt"
],
"validations": []
},
"actionCardButtonText": "Trigger",
"executeActionButtonText": "Trigger",
"published": true,
"permissions": { "roles": ["Member", "Admin"] }
},
"variables": {},
"links": [],
"verbose": false
},
{
"identifier": "trigger_agent",
"title": "Trigger Claude Agent",
"icon": "Claude",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "<your-installation-id>",
"integrationProvider": "claude-managed-agents",
"integrationInvocationType": "trigger_agent",
"integrationActionExecutionProperties": {
"agentId": "{{ .outputs.trigger.agentId }}",
"environmentId": "{{ .outputs.trigger.environmentId }}",
"sessionId": "{{ .outputs.trigger.sessionId }}",
"prompt": "{{ .outputs.trigger.prompt }}",
"reportSessionStatus": true,
"config": {
"title": "{{ .outputs.trigger.title }}",
"metadata": "{{ .outputs.trigger.metadata }}",
"vault_ids": "{{ .outputs.trigger.vaultIds }}",
"resources": "{{ ([(.outputs.trigger.githubRepoUrls // [])[] | {type: \"github_repository\", url: .}] + [(.outputs.trigger.memoryStoreIds // [])[] | {type: \"memory_store\", memory_store_id: .}]) }}"
}
},
"onFailure": "terminate"
},
"variables": {},
"links": [],
"verbose": false
}
],
"connections": [
{
"description": null,
"sourceIdentifier": "trigger",
"targetIdentifier": "trigger_agent"
}
]
}
Create Claude Agent - full workflow JSON (click to expand)
{
"title": "Create Claude Agent",
"icon": "Claude",
"description": "Create a new Claude managed agent with optional Port MCP, GitHub MCP, multiagent, and skills configuration.",
"category": "Claude Agents",
"allowAnyoneToViewRuns": true,
"nodes": [
{
"identifier": "trigger",
"title": "Create Claude Agent",
"icon": "Claude",
"config": {
"type": "SELF_SERVE_TRIGGER",
"userInputs": {
"properties": {
"name": {
"title": "Agent name",
"type": "string"
},
"model": {
"title": "Model",
"type": "string",
"enum": [
"claude-opus-4-5",
"claude-sonnet-4-5",
"claude-haiku-4-5"
],
"default": "claude-sonnet-4-5"
},
"systemPrompt": {
"title": "System prompt",
"type": "string",
"format": "multi-line"
},
"description": {
"title": "Description",
"type": "string"
},
"enableAgentToolset": {
"title": "Enable agent toolset",
"description": "Gives the agent access to the default Claude toolset (web search, code execution, etc.).",
"type": "boolean",
"default": true
},
"enablePortMcp": {
"title": "Enable Port MCP",
"description": "Gives the agent read-only access to your Port catalog (entities, blueprints, scorecards). A vault with Port MCP credentials is required.",
"type": "boolean",
"default": false
},
"enableGithubMcp": {
"title": "Enable GitHub MCP",
"description": "Gives the agent the ability to open pull requests via the GitHub MCP server. Git operations (clone, push) are handled by the github_repository session resource and do not require this. A vault with a GitHub personal access token is required.",
"type": "boolean",
"default": false
},
"multiagentMode": {
"title": "Multiagent mode",
"description": "Allow this agent to delegate to other agents.",
"type": "boolean",
"default": false
},
"delegateAgentIds": {
"title": "Delegate agents",
"description": "Agents this agent can delegate tasks to. Only agents without their own subagents are shown (Claude enforces a maximum delegation depth of 1).",
"type": "array",
"items": {
"type": "string",
"format": "entity",
"blueprint": "claude_agent",
"dataset": {
"combinator": "and",
"rules": [
{
"relation": "delegateAgents",
"operator": "isEmpty"
}
]
}
},
"disabled": { "jqQuery": ".form.multiagentMode != true" }
},
"allowSelfDelegation": {
"title": "Allow self-delegation",
"type": "boolean",
"default": false,
"disabled": { "jqQuery": ".form.multiagentMode != true" }
},
"claudeSkillIds": {
"title": "Skills",
"description": "Claude skills to attach to the agent.",
"type": "array",
"items": {
"type": "string",
"format": "entity",
"blueprint": "claude_skill"
}
}
},
"required": ["name", "model"],
"order": [
"name",
"model",
"systemPrompt",
"description",
"enableAgentToolset",
"enablePortMcp",
"enableGithubMcp",
"multiagentMode",
"delegateAgentIds",
"allowSelfDelegation",
"claudeSkillIds"
]
},
"actionCardButtonText": "Create",
"executeActionButtonText": "Create",
"published": true,
"permissions": { "roles": ["Admin"] }
},
"variables": {},
"links": [],
"verbose": false
},
{
"identifier": "create_agent",
"title": "Create Claude Agent",
"icon": "Claude",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "<your-installation-id>",
"integrationProvider": "claude-managed-agents",
"integrationInvocationType": "create_agent",
"integrationActionExecutionProperties": {
"name": "{{ .outputs.trigger.name }}",
"model": "{{ .outputs.trigger.model }}",
"systemPrompt": "{{ .outputs.trigger.systemPrompt }}",
"config": {
"description": "{{ .outputs.trigger.description }}",
"mcp_servers": "{{ (if .outputs.trigger.enablePortMcp then [{\"type\": \"url\", \"name\": \"port\", \"url\": \"https://mcp.getport.io/v1\"}] else [] end) + (if .outputs.trigger.enableGithubMcp then [{\"type\": \"url\", \"name\": \"github\", \"url\": \"https://api.githubcopilot.com/mcp/\"}] else [] end) }}",
"tools": "{{ (if .outputs.trigger.enableAgentToolset then [{\"type\": \"agent_toolset_20260401\"}] else [] end) + (if .outputs.trigger.enablePortMcp then [{\"type\": \"mcp_toolset\", \"mcp_server_name\": \"port\", \"default_config\": {\"enabled\": false}, \"configs\": [{\"name\": \"list_entities\", \"enabled\": true, \"permission_policy\": {\"type\": \"always_allow\"} }, {\"name\": \"list_blueprints\", \"enabled\": true, \"permission_policy\": {\"type\": \"always_allow\"} }, {\"name\": \"list_scorecards\", \"enabled\": true, \"permission_policy\": {\"type\": \"always_allow\"} }, {\"name\": \"load_skill\", \"enabled\": true, \"permission_policy\": {\"type\": \"always_allow\"} }, {\"name\": \"describe_user_details\", \"enabled\": true, \"permission_policy\": {\"type\": \"always_allow\"} }]}] else [] end) + (if .outputs.trigger.enableGithubMcp then [{\"type\": \"mcp_toolset\", \"mcp_server_name\": \"github\", \"default_config\": {\"enabled\": false}, \"configs\": [{\"name\": \"create_pull_request\", \"enabled\": true, \"permission_policy\": {\"type\": \"always_allow\"} }]}] else [] end) }}",
"multiagent": "{{ if .outputs.trigger.multiagentMode then {\"type\": \"coordinator\", \"agents\": ([(.outputs.trigger.delegateAgentIds // [])[] | {\"type\": \"agent\", \"id\": .}] + (if (.outputs.trigger.allowSelfDelegation // false) then [{\"type\": \"self\"}] else [] end))} else null end }}",
"skills": "{{ [(.outputs.trigger.claudeSkillIds // [])[] | {\"type\": \"custom\", \"skill_id\": .}] }}"
}
},
"onFailure": "terminate"
},
"variables": {},
"links": [],
"verbose": false
}
],
"connections": [
{
"description": null,
"sourceIdentifier": "trigger",
"targetIdentifier": "create_agent"
}
]
}
If your Port account is on the US region, change the Port MCP URL to https://mcp.us.getport.io/v1.
The workflow uses "default_config": {"enabled": false} on each MCP toolset and explicitly enables only the tools the agent needs via configs. This limits the agent's blast radius to a known set without requiring tool confirmation prompts.
Port MCP default tools: list_entities, list_blueprints, list_scorecards, load_skill, describe_user_details - read-only catalog access. See the Port MCP tools reference for the full list.
GitHub MCP default tool: create_pull_request only - the minimum needed to open a PR. Git operations (clone, commit, push) are handled by the github_repository session resource and do not go through GitHub MCP. See the GitHub MCP tools reference for the full list.
To extend either set, add entries to the corresponding configs array in the workflow JQ.