> ## Documentation Index
> Fetch the complete documentation index at: https://bundleup.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Agents for Many Users

> Run one agent for all your users, give each user their own accounts, and combine several providers in one agent.

In a product, one agent serves many users. Each user should only ever reach **their own** accounts. With BundleUp, the connection ID is the only per-user input, so this comes down to looking up the right connection IDs for the user you’re serving.

```mermaid theme={null}
flowchart LR
    subgraph Users
        A[User A]
        B[User B]
    end
    subgraph DB[Your database]
        CA["A: slack → conn_a1<br/>A: linear → conn_a2"]
        CB["B: slack → conn_b1"]
    end
    A --> CA
    B --> CB
    CA -->|"2 MCP servers"| AG1[Agent run for A]
    CB -->|"1 MCP server"| AG2[Agent run for B]
    AG1 --> MCP[mcp.bundleup.io]
    AG2 --> MCP
```

User A has connected Slack and Linear, so their agent run gets two MCP servers. User B has only connected Slack, so theirs gets one. Both runs use the same code and the same `mcp.bundleup.io`; only the connection IDs differ.

## The pattern

1. When a user connects an account, store `(user_id, provider, connection_id)` in your database. Setting `external_id` to your user ID when you start the [authorization flow](/docs/guides/auth/authorization-flow) lets you recover this from BundleUp too.
2. When the user starts a conversation, load their connections.
3. Give the agent one MCP server per connection.
4. Never accept a connection ID from the client side. Always look it up server-side for the authenticated user.

<Warning>
  Any API key in your workspace can use any connection in your workspace. BundleUp can’t know which of *your* users a connection belongs to. Picking the right connection for the signed-in user is your application’s job.
</Warning>

## Several providers in one agent

**Model-hosted MCP:** pass one `mcp` tool entry per connection. The model provider keeps them apart by label.

```typescript theme={null}
const connections = await db.connectionsFor(user.id);
// e.g. { slack: 'conn_a1', linear: 'conn_a2' }

const tools = Object.entries(connections).map(([label, connectionId]) => {
  const { url, token } = bundleup.mcp(connectionId).hosted();
  return {
    type: 'mcp',
    server_label: label,
    server_url: url,
    authorization: token,
    require_approval: 'never',
  };
});

const response = await openai.responses.create({ model: 'gpt-4o', input, tools });
```

**Your own MCP client:** open one client per connection. Tool names come from each provider, so two providers can both have a `search` tool. Prefix each tool name with its label (for example `slack__search`) before giving the list to the model, and route calls back by that prefix.

## Keep the tool list short

Two or three providers can easily add up to 60 tools, and models choose less accurately as the list grows. Give each agent only the tools it needs:

* Only attach the providers relevant to the task.
* Filter `tools/list` results to an allowlist before passing them to the model.
* Narrow the integration’s [scopes](/docs/guides/integrations/scopes), so the provider exposes fewer tools in the first place.

## Rate limits and cost

Each MCP message counts as one request toward the connection’s [rate limit](/docs/guides/proxy/rate-limits) (100 per minute) and toward [usage](/docs/concepts/requests#what-counts-toward-usage). An agent that lists tools on every turn uses more than its tool calls suggest. Cache the tool list for the length of a conversation where your client allows it.

## When a user disconnects

Listen for the `connection.deleted` [webhook](/docs/guides/webhooks/events) and remove the connection from your database, so the next agent run doesn’t try to use it. If an MCP call fails with `connection_invalid` or `connection_refresh_failed`, prompt the user to reconnect.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.