A CX agent can use tools from a remote Model Context Protocol (MCP) server to look up information or take action in an external system during a conversation. There are several ways to connect the two, and they differ in which credentials they can hold, how much of the MCP protocol you have to implement yourself, and how much you can reuse.
This article helps you choose a pattern, pick a credential that lasts, and avoid the problems builders most often run into. It doesn't repeat setup steps; follow the linked articles for those.
Note: The examples use the AWS MCP server because its authentication shows most of the trade-offs. The guidance applies to any remote MCP server.
Start with the native connector and move down the list only when a requirement rules it out.
Pattern | Use when | Main limits |
|---|---|---|
Native custom MCP connector | The server accepts | Bearer only. Tool sync is manual. See Native connector limits. |
Code node MCP client | The server needs custom auth or headers, and calls finish within the Code node timeout. | You implement the MCP client in Python. The code is copied into every workflow that uses it. |
Snap-in workflow operation | Auth must be signed or minted in code, the client is reused across agents or workspaces, or calls run longer. | You build, deploy, and version a snap-in. |
Hosted bridge plus native connector | Tools must sync natively, but the upstream server needs auth the connector can't hold. | You host and secure a proxy, and the native connector limits still apply. |
HTTP nodes on the workflow canvas | Prototyping only. | Can't refresh tokens, and every client obligation has to be rebuilt with nodes. |
To decide, answer these questions in order:
Does the server accept a Bearer token over Streamable HTTP, and is that token long-lived, so it can be stored without regular re-minting? If yes, use the native custom MCP connector.
Must the tools sync natively as agent tools or operations? If yes, use a hosted bridge with the native connector.
Is the client reused across agents or workspaces, does auth need to be signed or minted in code, or do calls run long? If yes, use a snap-in workflow operation.
Otherwise, use a Code node MCP client. Use HTTP nodes on the canvas only for a throwaway prototype.
An admin adds the server by URL, DevRev fetches its tools and converts them into operations, and you attach the tools to an agent or use them in workflows. This is the lowest-maintenance option. For setup, see Adding and configuring MCP connectors.
A Code node can call the MCP server with the requests library, using a credential attached as a connection (keyring). It runs the whole exchange (initialize, then the tool call) in one step. The default timeout is 30 seconds and you can raise it to 120 seconds. See Code node.
A snap-in can expose an operation that workflows use as a step. The function receives the connection's credential, signs or mints auth in code, and can use an official MCP SDK client, which handles the handshake, headers, version negotiation, and streamed responses for you. For the manifest format, see the snap-in manifest reference.
Note: When you create a snap-in version, the manifest must declare service_account.scopes and static_scopes on every operation, even if the snap-in needs no DevRev access. Empty lists (self: []) are accepted. Manifest validation doesn't catch a missing list; version creation rejects it.
A small MCP proxy that you host accepts a long-lived Bearer secret from DevRev and handles the upstream auth, for example by signing requests. This lets the native connector sync the proxy's tools as if they came from the upstream server. It adds infrastructure to run and secure, plus a network hop.
You can implement an MCP client from HTTP nodes, Code nodes, and If/Else nodes. Use this only to prototype: it can't refresh a token, and each obligation in If you build your own MCP client has to be rebuilt on the canvas.
"The server accepts Bearer tokens" isn't enough to choose the native connector. Check how long the token lives and how it is renewed.
A connection whose secret you paste in, including the token of a custom MCP connector, is static. DevRev stores the value and doesn't renew it. If the server issues short-lived tokens with no refresh token, a static connection stops working when the token expires.
For example, an unattended client of the AWS MCP server gets its Bearer token through a client-credentials grant that is signed with AWS credentials. The token lasts one hour and comes with no refresh token, so a pasted token breaks within the hour.
DevRev also has connection types that it renews itself. Snap-ins declare them:
Connection type | What DevRev does | Example |
|---|---|---|
Static secret, custom MCP connector token | Stores the value you enter. No renewal. | Long-lived API keys and personal access tokens. |
Short-lived secret | Fetches an access token with the client ID and secret you enter, and fetches a new one before it expires. | |
AWS session token | You enter a role ARN and an external ID. DevRev assumes the role, caches the temporary credentials, and renews them. | Snap-ins that call AWS, including the AWS MCP server |
Because snap-ins declare the renewing types, a server that needs one usually points you to a snap-in operation, or to a marketplace snap-in that already declares it.
Warning: Don't build a scheduled job that re-mints a token and writes it into a static connection. A missed run silently breaks every call. Use a renewing connection type instead.
For AWS, prefer an AWS session-token connection bound to a least-privilege role over pasted access keys.
An agent skill is a workflow with an AI Agent Skill trigger (see Workflow triggers). When an agent calls a skill, the workflow runs as the agent's service account, not as the customer or the teammate in the conversation.
Use an org-level connection for any credential a skill workflow needs. In testing, per-user OAuth connections didn't work from agent skill workflows, because the service account has no personal connection of its own. Don't design a CX skill that depends on each user's personal OAuth connection.
When the tools reach the agent through a skill workflow rather than as natively synced tools, split the work into two skills:
Discovery skill. Lists the available tools with their names, descriptions, and input schemas, after applying any filtering (see Read-only tools).
Call skill. Takes an exact tool name and a JSON object of arguments, calls the tool, and returns the result or a structured error.
In testing, agents chained the two skills on their own in one turn: list the tools, then call the right one.
The trigger's input parameters and their descriptions are the contract the agent sees. Write them precisely:
Tell the agent to use the exact tool name returned by the discovery skill.
Ask for arguments as a JSON object, and {} when the tool takes none.
State any scope limits, such as "only resources that belong to this ticket's customer".
Mark inputs the workflow can't run without as required.
Some MCP servers and clients offer a "read-only mode." This is often a client-side filter. MCP tools can declare a readOnlyHint annotation, and a read-only client hides tools without readOnlyHint: true from the tool list and refuses calls to them. The server doesn't enforce it.
For example, the read-only mode of the AWS MCP proxy is implemented in the proxy. A client that talks to the server directly gets no read-only protection unless it applies the same filter.
If you build your own client and want read-only behavior:
Filter the tool list to readOnlyHint: true before the agent sees it.
Before each tool call, check that tool's hint in the same session. If the lookup fails, return an upstream error rather than a denial.
Bind a least-privilege, read-only identity on the external system. The hint is metadata declared by the server, so the external system's permissions are the real boundary.
Warning: Read-only filtering can remove the tools a CX agent needs most. In testing with the AWS MCP server, the only tool that could read the customer's account resources wasn't marked read-only, so a read-only agent could search documentation but not inspect the account. Decide per server what a read-only agent can actually answer.
Tools from a custom MCP connector that you add to an agent are set to Needs approval by default; you can change each tool to Always allow (see Adding and configuring MCP connectors). Skills can also require approval.
Approval interacts with conversation flow:
Approval wording in the agent's instructions can make the agent ask for approval at every step.
After an approval turn, the agent can lose track of the original request and ask the customer to repeat it.
Require approval only on tools and skills that change something, not on discovery or read-only lookups. Test the full approve-then-act conversation before going live.
If you need a durable, per-ticket record of what the agent did on an external system, log each MCP call to a custom object linked to the ticket. Useful fields include the method, tool name, session, request and response bodies, status, and a link to the ticket.
Build each request body once and reference the same value from both the call step and the log step. Bodies copied by hand drift, and the log stops matching what was sent.
A snap-in operation can create the record itself from the exact request it sent.
A token that can run the workflow that creates these records may still be refused when it reads them through the API. Check the records in the app, or grant read access explicitly.
The native connector and an MCP SDK handle these obligations for you. A Code node client or a canvas prototype must handle them itself.
Accept header. Send Accept: application/json, text/event-stream on every POST. Some servers return 400 without both.
Streamed responses. A server may reply with text/event-stream. The HTTP node doesn't parse it and returns the body as a raw string; parse it in code.
Protocol version. Use the protocol version the server returns from initialize, and send it as MCP-Protocol-Version on later requests.
Session expiry. A server can end a session and answer HTTP 404. Run initialize again once, retry once, then return a structured error. If you store the session (for example, on the ticket), clear it on 404. Two calls that start at the same time can each create a session; accept that or store the session elsewhere.
Tool errors. Tool failures can arrive as HTTP 200. Check the JSON-RPC error field and result.isError before treating the response as a result.
HTTP status. The HTTP node completes normally on non-2xx responses and puts the code in its status output, so an error path doesn't catch a 404. Branch on the status code. See HTTP node.
Route & Merge. Check how the merge is configured. A merge that doesn't wait for all branches continues with the first branch to finish, even if that branch ended on an error path or at a skill output step. Gate downstream steps on the values you need instead of relying on a branch dead-ending. See Route & Merge control node.
Code node outputs. Only inputs you configure reach inputs, keys missing from the output schema are dropped, and returning None produces an empty output while the step still succeeds. Name keys exactly as the schema does. See Code node.
One session per invocation (initialize, call, close in the same step) avoids stored sessions and their races, at the cost of extra round trips per call.
Keep these in mind when you choose the native connector:
Only Authorization: Bearer over Streamable HTTP. No custom headers, Basic auth, or PKCE (see Adding and configuring MCP connectors).
Tool sync is manual. Resync after the server adds, changes, or removes tools.
Renaming a tool on the server behaves like deleting it and adding a new one, which breaks workflows and skills bound to the old tool.
The platform client doesn't re-initialize a session that the server has ended before retrying.
Connections are bound per step, per workflow version. You don't need to deactivate an active workflow to bind one: use Edit draft version, bind the connection in the draft, and publish (see Version, publish, and monitor).
Workflow templates don't carry connection bindings. After you create a workflow or a version from a template, bind the connections again before you publish.
If the agent says "Timeout occurred while waiting for skill call output", don't assume the external server was slow. The same message appears when a step in the skill fails, including a snap-in step that fails to load.
Go to Settings > Workflows, open the skill workflow, and select the Runs tab.
Filter by the conversation the skill was invoked from (see Version, publish, and monitor).
Open the run and select each step to see its input, output, and error message. The failing step's summary has the real error.
Note: Only admins can view the Runs tab.