Skip to main content
The ForceAI Connector is a single MCP server that fronts roughly 1090 third-party providers. Connect a provider once, and any model or agent with access can drive it as a tool. Because it is one server, ordinary per-server permissions cannot express “this team may use Slack but not Salesforce” — that is decided per provider, on the Providers page
One MCP server, many providers. The connector exposes four tools — list_apps, search_actions, get_action_guide and execute_action — and the provider is chosen by the actionId argument, for example hackernews.get_top_stories

Browse and connect a provider

Go to MCP Servers and choose + Add New MCP Server. This opens the provider catalog rather than a form for registering another server, because in ForceAI the connector is already registered and adding a tool means connecting one of its providers Click any provider to see what it actually does: its categories, its authentication type, and every action it exposes with an id, a description and the names of the input fields it accepts. Connecting is a button inside that view, so you choose a provider knowing what it can do rather than being asked for a credential first
The input field names are the part most easily got wrong. An action called with an argument it does not declare is refused by the connector’s schema check, and the error arrives from several hops away. hackernews.get_top_stories takes no limit, and the action list says so before you write the call
Providers differ in what they need: A credential submitted here is forwarded to the connector once and never stored, logged or echoed by the dashboard. Errors from the provider are surfaced as a code rather than a message, because some providers quote the submitted value back in the message text

Restrict a provider to access groups

Every connected provider is usable by everyone until you narrow it. On a provider’s row in the catalog, the access line reads Access: open; click it to assign one or more access groups, and it becomes Restricted: <groups> Restriction is deliberately opt-in. Connecting a provider is what makes it usable, and an admin narrows that on purpose rather than having to grant every provider individually. The failure mode is a team seeing a provider it did not need, not a credential reaching someone who should not have it Access groups come from the caller’s own grants, the same ones that flow SSO to team to key. A caller reaches a restricted provider when it holds at least one of the assigned groups. Proxy admins bypass the restriction
A caller that holds no groups is refused a restricted provider. That is the intended behaviour: restriction means restriction, and the only way past it is the admin bypass

Agents and per-task keys

An ephemeral agent runs on a short-lived key minted for its task, which has no object permission of its own. The access groups of whoever dispatched the task are stamped into that key when it is minted, so an agent reaches exactly the providers its dispatcher could The agent orchestrator’s sub-runners are the exception. They run as their own service principal rather than as the initiating user, so they carry no user groups and a restricted provider stays denied to them

Read the audit trail

Every connector action is recorded, whether it ran or was refused: Each row carries the provider, the tool, the action id, the caller’s access groups and the groups the provider requires. The action id is the part that matters: the spend log records the tool name, which is execute_action for every one of the catalog’s actions and so identifies nothing on its own Refusals are worth their own row because a denied call leaves no other trace. The gate blocks before the tool runs, so nothing bills and no spend-log entry is written; without the audit row there is no record that a caller reached for a provider it may not use Admin calls are audited too. They bypass the restriction, not the record

Seeing what a tool returned

The result of a tool call is stored only when FORCEAI_STORE_MCP_RESULTS is set. A result is whatever the third-party provider returned — story ids today, but Slack messages, mail and CRM records once those providers are connected — so keeping it is a retention decision rather than a display one, gated the same way prompt content is Stored results are capped in size, and a truncated result says so rather than being silently clipped

Using the connector from a model

In the Playground, pick a model, add forceai_connector under MCP Servers, and ask for something the provider can do. The model discovers the tools and calls them; the MCP events panel shows each call and its result Narrowing Limit tools to execute_action is worth doing when you already know the action, since it stops the model spending a round on discovery

Tool rounds

A tool round is one completion in which the model may call a tool. The budget is not a single global number; it follows the servers the request can reach, because a server’s shape decides whether chaining is intrinsic to it: Every round is a further billed completion, and rounds are not equal: each one re-sends the tool definitions, the question and every prior tool result, so a fourth round can cost several times the first The budget is checked before a round starts and never inside one. A round that has begun runs to completion and bills in full; the next simply does not begin. On the last round the budget allows, the request is sent without tools, so the model answers in prose with what it gathered rather than announcing a call nothing will run
FORCEAI_MCP_TOOL_ROUNDS still overrides everything when set, which is how you pin the number down to bound spend. Leave it unset to let the budget follow the servers

Configuration

Known limitations

Tool policies do not currently apply to MCP tools. Policy reads tool names from OpenAI function specs, and an MCP tool arrives in a different shape, so connector traffic is governed by per-provider access and the audit trail rather than by tool policies Non-streaming requests run a single tool round regardless of FORCEAI_MCP_TOOL_ROUNDS