UNPKG

n8n

Version:

n8n Workflow Automation Tool

361 lines (308 loc) 19.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.externalServicesSkill = externalServicesSkill; const api_types_1 = require("@n8n/api-types"); const zod_to_json_schema_1 = require("zod-to-json-schema"); const schema_text_serializer_1 = require("../../json-config/schema-text-serializer"); const initial_build_prompt_1 = require("../prompts/initial-build.prompt"); const mcpServerSchemaText = (0, schema_text_serializer_1.jsonSchemaToCompactText)((0, zod_to_json_schema_1.zodToJsonSchema)(api_types_1.McpServerConfigSchema)); function externalServicesSkill() { return { id: 'agent-builder-external-services', name: 'Agent Builder External Services', description: 'Use when connecting the target agent to any external product: deciding whether Slack, Linear, Telegram, or another platform is a chat integration/trigger versus an MCP, node, or workflow tool; adding, removing, or updating chat integrations or MCP servers; and wiring n8n node-backed tools (search_nodes/get_node_types discovery, nodeParameters, node credential slots, $fromAI usage, n8n expressions).', recommendedTools: [ 'resolve_integration', 'list_integration_types', 'configure_channel', 'search_nodes', 'get_node_types', 'ask_credential', 'verify_mcp_server', 'read_config', 'patch_config', ], allowedTools: [ 'resolve_integration', 'list_integration_types', 'configure_channel', 'search_mcp_servers', 'search_nodes', 'get_node_types', 'ask_credential', 'verify_mcp_server', 'get_resource_locator_options', 'ask_questions', 'read_config', 'patch_config', 'write_config', 'load_skill', ], instructions: `\ ## Purpose Use this to connect the target agent to external products across all three surfaces: chat integrations (the \`integrations\` array), MCP servers (\`mcpServers\`), and n8n node tools (entries in \`tools[]\` with \`nodeParameters\`). Decide the right surface first, then follow that section. ## Integration vs Callable Tool Decision Use an integration when the product is the agent's conversation or trigger surface: humans will mention, message, comment to, or resume the agent there, or the agent needs to respond in that same platform conversation context. Use an MCP, node, or workflow tool when the product is only something the agent operates on: searching records, creating tickets, updating objects, or sending a business-process notification while the conversation happens elsewhere. Examples: - Slack integration: the agent should be chatted with in Slack, respond in Slack threads, DM users, message channels, add reactions, or render rich UI to Slack users. - Linear integration: the agent should be triggered from Linear issues/comments, understand the current Linear subject, or reply in the same Linear conversation. - Linear callable tools: the agent is triggered from Slack, Preview, a task, or a workflow and only needs to search/create/update Linear tickets via MCP or node tools. For callable (non-chat) services, call \`resolve_integration\` separately per service and follow the returned \`kind\`: \`"mcp"\` -> MCP Servers section below, \`"node"\` -> Node Tools section below. ## Chat Integrations The \`integrations\` array controls how the target agent is triggered. - These are connected external chat platforms, not built-in Preview chat. - Call \`list_integration_types\` first. - Read the returned \`capabilities\`, \`useIntegrationWhen\`, and \`useNodeToolWhen\` fields before deciding to add an integration. - Pick one returned \`type\` and pass it to \`configure_channel\` as \`integrationType\`. ALWAYS use \`configure_channel\` for chat-channel credentials — never \`ask_credential\` or a raw config write. The setup UI it shows creates and persists the credential/connection itself; do not follow up with \`patch_config\`/\`write_config\` to write the credential. - ${initial_build_prompt_1.INITIAL_BUILD_NOTE} Instead of \`configure_channel\`: after \`list_integration_types\` returns the matching type, \`read_config()\` then \`patch_config\` adding \`{ "type": "<integrationType>", "credentialId": "" }\` to \`/integrations/-\` (include a minimal valid draft \`settings\` object for telegram) so the channel appears in the agent panel as needing setup. Pass the same \`integrationType\` in the trailing \`finish_setup\` call's \`channels\` array — its card connects or skips the channel itself; if skipped, list it in the closing setup checklist pointing at the channel chip in the agent panel. If \`finish_setup\` instead reports the channel as \`'blocked'\` (the agent could not be published yet), patch in the credentials/model it collected first; if that resolves every reported issue, call \`configure_channel\` directly for that channel as a follow-up. Otherwise leave it for the closing checklist. - Preserve existing chat integrations unless the user asked to remove them. - To remove an existing chat integration, call \`read_config\` and inspect \`config.integrations\`. - If exactly one existing integration matches the requested platform, remove that entry with \`patch_config\` by index (or replace \`/integrations\` with a filtered array when clearer). - If multiple existing integrations match the requested platform, ask which one to remove before editing \`integrations\`. - Removing a chat integration means deleting its entry from \`integrations[]\`. Do not call \`configure_channel\` to remove a channel. ### Gotchas - Chat integration types must come from \`list_integration_types\`. - Do not add a chat integration just because the agent needs CRUD or notifications for that product. Resolve the callable capability through \`resolve_integration\` unless the product itself is the chat/trigger context. - For recurring or scheduled runs, create a task (\`create_tasks\`), not an integration. - Omitting \`integrations\` from a config write preserves the current channels. To remove one, write an explicit filtered array or remove the exact array entry. ## MCP Servers MCP servers expose external tool catalogs to the target agent over HTTP. They live on the top-level \`mcpServers\` array, and each entry maps 1:1 to a connected MCP server. Use this section when \`resolve_integration\` returned \`kind: "mcp"\`, the user explicitly asks to add or edit an MCP server, or the user provides or asks to configure a custom MCP server. ### Discovery and setup For a generic external-service request, \`resolve_integration\` must select the integration type before MCP setup. If no resolver result is available yet, call \`resolve_integration\` with queries matching the requested service. Resolve one requested service per call; use \`queries\` only for alternative search terms for that service. - If it returns \`kind: "node"\` for a generic service request, follow the Node Tools section with the returned node results. Stop this MCP workflow. - If it returns \`kind: "node"\` but the user explicitly requested an MCP server, do not silently substitute a node tool. Continue with manual MCP setup by asking for the URL and transport/authentication decision through \`${api_types_1.ASK_QUESTIONS_TOOL_NAME}\`. - \`resolve_integration\` returns \`{ kind: "mcp", results: [...] }\` for MCP matches. Never read server fields from the wrapper; select a result first: - If \`results[]\` contains one entry, use it as \`selectedResult\`. - If the request uniquely identifies one entry by \`name\` or \`title\`, use that entry as \`selectedResult\`. - If multiple candidates remain, call \`ask_questions\` with the candidate titles and descriptions; never choose by array order. During an initial build, do not call \`ask_questions\` for this: pick the best candidate by title/description relevance yourself, and list the pick as an assumption in your summary. Use the chosen entry as \`selectedResult\`. If \`ask_questions\` returns \`{ answered: false }\`, stop MCP setup without selecting a server, asking for credentials, verifying a connection, or mutating config. Do not re-present the question. - Use \`name\`, \`url\`, \`transport\`, \`authentication\`, \`credentialType\`, \`tools\`, and optional \`metadata\` only from \`selectedResult\`. Follow these steps for the selected MCP result: 1. Credential: call \`ask_credential\` with a short \`purpose\`, using \`selectedResult.credentialType\` as \`credentialType\`. Never invent credential IDs. 2. Verify: call \`verify_mcp_server\` with the selected result's \`name\`, \`url\`, \`transport\`, and \`authentication\`, plus the returned \`credentialId\` as \`credential\` when authentication is required. 3. Capability check: confirm the verified tool names and descriptions cover the capability the user requested. 4. Write config: call \`read_config\`, then \`patch_config\` to add the entry to \`mcpServers[]\` using the patch pattern below. When the entry already exists and verify returned \`credentialApplied: true\`, skip this step — the credential is already persisted. ${initial_build_prompt_1.INITIAL_BUILD_NOTE} For MCP that means: pick the best candidate as an assumption (above), then \`read_config()\` and \`patch_config\` a draft \`/mcpServers/-\` entry using \`name\`, \`url\`, \`transport\`, \`authentication\`, and \`metadata.nodeTypeName\` from \`selectedResult\` with \`credential\` omitted, and skip \`verify_mcp_server\` — there is nothing to authenticate yet. Include the credential in the trailing \`finish_setup\` call; verify with the returned credential id — on success the tool writes the credential into the matching entry itself (\`credentialApplied: true\`); no \`read_config\`/\`patch_config\` follow-up for the credential. Existing-agent additions keep the immediate ask + verify flow above unchanged. If verification succeeds but the tools do not cover the requested capability for a generic service request, switch to the Node Tools section, call \`search_nodes\` with the same service queries, and continue with node setup. Do not add the MCP server merely because its registry entry matched. Full schema reference: ${mcpServerSchemaText} ### Tool exposure and approval - Expose every available MCP tool by default: omit \`toolFilter\` unless the user explicitly asks to restrict which tools are exposed. Do not infer an allowlist from the requested capability. - For an explicit filter or selected approval list, use only exact, unprefixed \`name\` values from \`selectedResult.tools\` or a successful \`verify_mcp_server\` result. - Never prepend the server name. Never invent MCP tool names. \`toolFilter.tools\` and \`approval.tools\` match original MCP names; the SDK adds the server prefix only when exposing tools to the model. ### Credential flow - For \`bearerAuth\`, call \`ask_credential\` with \`credentialType: "httpBearerAuth"\`. - For \`headerAuth\`, call \`ask_credential\` with \`credentialType: "httpHeaderAuth"\`. - For \`multipleHeadersAuth\`, call \`ask_credential\` with \`credentialType: "httpMultipleHeadersAuth"\`. - For \`mcpOAuth2Api\`, call \`ask_credential\` with \`credentialType: "mcpOAuth2Api"\`. ### Testing the connection Before writing to config, call \`verify_mcp_server\` with server \`name\`, \`url\`, \`transport\`, and (if applicable) the credential id from \`ask_credential\`. - Success returns \`{ ok: true, tools: [{ name, description }] }\`, and when a matching \`mcpServers\` entry exists, also \`credentialApplied: true, configMutated: true, agentId\` — the credential is written automatically; do not follow with \`read_config\`/\`patch_config\` for the credential. - When verify succeeds but \`credentialApplied: false\` and the entry already exists, fall back to \`read_config\` then \`patch_config\` for the credential. - For an explicitly requested filter or selected approval list, copy exact names from the returned tool list following Tool exposure and approval above. - Failure returns \`{ ok: false, error: "..." }\`. - If verification fails, explain the error and ask the user to check the URL or credentials before proceeding. ### Incomplete setup The user can skip the credential prompt, the URL question, or both. Never invent a credential ID or a placeholder URL to fill the gap, and never abort the server addition — always persist what is known and let the user finish setup later: - Credential skipped (\`ask_credential\` returned \`{ skipped: true }\`): omit only the \`credential\` field. - URL skipped: persist \`url: ""\`. - Either case: skip \`verify_mcp_server\` (there is nothing to authenticate or connect to), then \`read_config\` and \`patch_config\` the entry, preserving every other known field — \`name\`, \`transport\`, \`authentication\`, an already-selected credential, and registry \`metadata\`. ### Selecting credentials When using a registry-backed server, always use the \`credentialType\` returned by \`selectedResult\`. For custom MCP servers, if credential type is unknown, ask the user which credential type to use (OAuth2, Bearer Token, Header Auth, Multiple Headers Auth, or None) via \`${api_types_1.ASK_QUESTIONS_TOOL_NAME}\`. Then map to: - \`bearerAuth\` -> \`ask_credential\` with \`credentialType: "httpBearerAuth"\` - \`headerAuth\` -> \`ask_credential\` with \`credentialType: "httpHeaderAuth"\` - \`multipleHeadersAuth\` -> \`ask_credential\` with \`credentialType: "httpMultipleHeadersAuth"\` - \`mcpOAuth2Api\` -> \`ask_credential\` with \`credentialType: "mcpOAuth2Api"\` ### Patch pattern 1. Initialize the array if missing: \`{ "op": "add", "path": "/mcpServers", "value": [] }\` 2. Append each server: \`{ "op": "add", "path": "/mcpServers/-", "value": { ... } }\` ### Gotchas - Server \`name\` must be unique across \`mcpServers\` within an agent. - Never fabricate \`metadata.nodeTypeName\`. - When \`selectedResult\` includes \`metadata.nodeTypeName\`, include \`metadata: { nodeTypeName: <selectedResult.metadata.nodeTypeName> }\` in the entry so the UI can render the correct server form. - A registry match proves server availability, not support for the requested capability; use the verified live tool list for that decision. ## Node Tools Use this section to discover, configure, and wire node tools into the target agent's \`tools[]\`, including \`nodeParameters\` and n8n expressions. ### Workflow - For a generic external-service request, call \`resolve_integration\` before node discovery unless a resolver result is already available. - If it returns \`kind: "mcp"\`, follow the MCP Servers section instead and stop this node-tool workflow. - If it returns \`kind: "node"\`, use its returned node results and call \`get_node_types\`; do not repeat the same search with \`search_nodes\`. - Call \`search_nodes\` directly only when the user explicitly requests an n8n node, when refining node results, or when a verified MCP server lacks the requested capability. - Never guess node type names. - Use the tool node id from discovery, usually ending in \`Tool\`. - Put fixed values in \`nodeParameters\`; use complete n8n expressions for values the agent should decide at runtime: \`={{ $fromAI('url', 'The URL to inspect', 'string') }}\`. - For stable dynamic selectors, load \`agent-builder-resource-locators\` and follow it. - Never write literal \`"$fromAI"\` or bare \`$fromAI\`; the node will treat it as the actual value. - Do not pipe AI-chosen fields through \`$json\`. - Do not include \`inputSchema\` or \`toolDescription\` for node tools. - For each required credential slot, call \`ask_credential\` once before the config mutation for an addition to an existing agent. ${initial_build_prompt_1.INITIAL_BUILD_NOTE} Add the tool with that credential slot omitted; after the trailing \`finish_setup\` resolves the credential, copy the returned credentials into \`node.credentials\` via \`patch_config\`; for resource-locator resolution follow \`agent-builder-resource-locators\` then. Pass the node's credential key as \`credentialSlot\`. On success, copy the returned \`credentials\` object directly to \`node.credentials\`. If skipped, still add the tool and omit only that credential slot. - When the agent already has a chat channel configured and the tool needs the same credential type, \`ask_credential\` reuses the channel's credential automatically — do not ask the user to pick a different one. ### n8n Expressions Node tool parameters inside \`nodeParameters\` can use n8n expressions. Prefer \`$fromAI\` whenever the target agent should decide a value at runtime. Do not use \`$fromAI\` for stable resource IDs that the target agent cannot know at runtime, such as Linear \`teamId\`, project IDs, channel IDs, calendar IDs, database IDs, table IDs, or other dynamic "Name or ID" selectors. Resolve those with the \`agent-builder-resource-locators\` skill, \`ask_credential\`, and \`get_resource_locator_options\`; write the returned \`parameterValue\` into \`nodeParameters\`. - \`={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('fieldName', 'What value to provide', 'string') }}\` - \`={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('count', 'How many items', 'number') }}\` - \`={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('enabled', 'Whether to enable this option', 'boolean') }}\` - \`={{ $now.toISO() }}\` for current date/time. - \`={{ $today }}\` for the start of today. Always wrap expressions in \`={{ }}\`. Never pipe AI-chosen node-tool fields through \`$json\`; use \`$fromAI\` for those fields instead. ### Gotchas - Do not include \`inputSchema\` or \`toolDescription\` for node tools. - \`$fromAI(...)\` placeholders define the node tool input schema; do not add it manually. - Follow \`agent-builder-resource-locators\` for dynamic selector lookup, credentials, and \`parameterValue\` handling. - If a required node-tool credential is skipped, add the tool and omit only that credential slot. - Node tools execute inline, so never use waiting operations such as \`sendAndWait\` or \`dispatchAndWait\`. When the user requests human approval, configure the intended non-waiting operation and set \`requireApproval: true\` on the tool. ## Verify - Connected chat integrations were set up through \`configure_channel\`, not \`ask_credential\` or a manual config write. - The chosen integration matches \`useIntegrationWhen\`; otherwise resolve the callable capability through \`resolve_integration\` and use MCP, node, or workflow tools. - Generic non-chat external services were routed through \`resolve_integration\` before MCP or node setup. - The final \`integrations\` array keeps unrelated integrations intact and removes only the requested channel entries. - Node tools use discovered tool node ids and valid node parameters.`, }; } //# sourceMappingURL=external-services.skill.js.map