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

# Agent MCP for Your Users

> Expose one of your Upsolve agents over MCP so your end users — or an agent acting on their behalf — can query their own data, scoped per user.

## Overview

The **Agent MCP** lets you put an Upsolve agent behind the Model Context Protocol so that **your end users**, or an **agent built into your product**, can ask questions in natural language and get trusted, data-scoped answers.

Every call is scoped to a single end user via that user's own **project-user token** — the same short-lived JWT you already mint in [Backend Setup](/ai-agent-builder/deploy-agents/backend-setup). The MCP server holds no secrets of its own; it forwards the caller's token to the agent, and row-level security does the rest. One user can never see another user's data.

<Note>
  **Not the same as the [Claude MCP Server](/ai-agent-builder/deploy-agents/mcp-server).**
  That one is for **you**, the builder, to explore your own data inside Claude (you sign
  in with your Upsolve account via OAuth, and it renders interactive charts). **This** one
  is for **your end users / your agent**, authenticated with a per-user token you mint.
  Pick this page if you're embedding analytics into your product.
</Note>

***

## How it works

```
Your end user ──▶ Your app / agent ──▶ Agent MCP ──▶ Upsolve API ──▶ your agent
                  (holds the user's      (forwards the     (RLS-scoped to
                   project-user token)    token verbatim)    that user)
```

1. You register each end user and mint a short-lived **project-user token** — exactly the [Backend Setup](/ai-agent-builder/deploy-agents/backend-setup) flow.
2. You run the **Agent MCP**, configured with the **agent id** you want to expose.
3. Your end user's agent connects to the MCP and calls one tool, `query_data`, passing the user's token. The MCP forwards it to `POST /v1/api/project-agents/{agentId}/chat`, and the agent answers within that user's data scope.

***

## Prerequisites

<Steps>
  <Step title="An agent to expose">
    Build and publish an agent in **Agent Studio**, and copy its **agent id**. This is the single agent the MCP server will serve.
  </Step>

  <Step title="A way to mint user tokens">
    Complete [Backend Setup](/ai-agent-builder/deploy-agents/backend-setup): register your [organization](/api-reference/endpoint/register-project-organization) and [users](/api-reference/endpoint/register-project-user), and be able to fetch a [project-user token](/api-reference/endpoint/get-project-user-token) on demand. That token is what your users present to this MCP.
  </Step>
</Steps>

<Warning>
  Keep your Upsolve **API key** server-side. The only credential that should ever reach an
  end user's client is their own short-lived project-user token.
</Warning>

***

## Configure the server

The Agent MCP is configured entirely through environment variables:

| Variable                       | Required   | Description                                                                          |
| ------------------------------ | ---------- | ------------------------------------------------------------------------------------ |
| `UPSOLVE_API_URL`              | Yes        | Upsolve API base URL, e.g. `https://api.upsolve.ai`                                  |
| `UPSOLVE_AGENT_ID`             | Yes        | The agent id this server exposes                                                     |
| `MCP_TRANSPORT`                | No         | `stdio` (default, local / per-user) or `http` (hosted, many users)                   |
| `UPSOLVE_PROJECT_USER_JWT`     | stdio only | The end user's project-user token (one process serves one user)                      |
| `MCP_PORT`                     | http only  | Port for the hosted server (default `3002`)                                          |
| `UPSOLVE_TOOL_NAME`            | No         | Rename the tool your agent sees (default `query_data`)                               |
| `UPSOLVE_INCLUDE_TOOL_RESULTS` | No         | `true` to append chart/table data as JSON for your agent to render (default `false`) |

***

## Connect your users

Choose the shape that matches how your users consume it.

<Tabs>
  <Tab title="Hosted (HTTP)">
    Best when **many** end users hit **one** server (a web product). Run the Agent MCP once with `MCP_TRANSPORT=http`, then have each user's agent connect over HTTP and pass **that user's token** as the bearer — the server forwards each request's token, so concurrent users stay isolated.

    ```
    POST https://<your-agent-mcp-host>/mcp
    Authorization: Bearer <end user's project-user token>
    ```

    Example MCP client config:

    ```json theme={null}
    {
      "mcpServers": {
        "upsolve-agent": {
          "url": "https://<your-agent-mcp-host>/mcp",
          "transport": "streamable-http",
          "headers": { "Authorization": "Bearer <end user's project-user token>" }
        }
      }
    }
    ```
  </Tab>

  <Tab title="Local (stdio)">
    Best for an **agent runtime** that spawns a process per user, or a per-user desktop config. The user's token is supplied via the environment, so **one process serves exactly one user**.

    ```json theme={null}
    {
      "mcpServers": {
        "upsolve-agent": {
          "command": "<command that launches the Upsolve Agent MCP>",
          "env": {
            "UPSOLVE_API_URL": "https://api.upsolve.ai",
            "UPSOLVE_AGENT_ID": "<your agent id>",
            "MCP_TRANSPORT": "stdio",
            "UPSOLVE_PROJECT_USER_JWT": "<end user's project-user token>"
          }
        }
      }
    }
    ```
  </Tab>
</Tabs>

***

## The tool your agent gets

A single tool — the same shape as the Claude MCP Server's, so it's familiar:

### `query_data`

| Parameter   | Type   | Required | Description                                                                     |
| ----------- | ------ | -------- | ------------------------------------------------------------------------------- |
| `message`   | string | Yes      | The analytical question, in plain English                                       |
| `thread_id` | string | No       | Pass back the `thread_id` from a previous response to continue the conversation |

**Returns:** the agent's analysis as text, plus a `<thread_id>…</thread_id>` marker your agent can echo back on the next call. If `UPSOLVE_INCLUDE_TOOL_RESULTS=true`, chart/table data is appended as a JSON block for your agent to render (there is no built-in chart UI on this server).

<Note>
  On the first call, omit `thread_id`. Read it back from the response and pass it on every
  follow-up so the agent keeps conversation context.
</Note>

***

## Token lifecycle

Project-user tokens are short-lived (1 hour by default — see [Backend Setup](/ai-agent-builder/deploy-agents/backend-setup)). Mint one per session and refresh it before it expires.

* **HTTP:** when a token expires the tool returns an actionable error; mint a fresh token and send it on the next request.
* **stdio:** the token lives in the process environment, so restart the process (or relaunch with a new token) when it expires. For long-lived agents, have your backend re-mint and respawn.
* **Hands-off tokens (optional, advanced):** a trusted hosted deployment can hold your API key and mint per-user tokens itself, so end users never handle tokens. This places your API key on the server — use it only for a server you control. Contact Upsolve if you want this pattern.

***

## Security

* **Per-user scoping** — every answer is filtered by the token's `properties` (row-level security). Set the correct tenant keys when you register the user; that is your isolation boundary.
* **Org-bound** — a user can only reach agents in their own organization. A wrong or foreign `UPSOLVE_AGENT_ID` returns "not found", never another tenant's data.
* **No server-side secret** — in the default flow the MCP forwards the caller's token and stores nothing; it can't see anything the token doesn't already allow.
* **Read-only** — the agent queries your data; it never writes or modifies it.

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="“No credential” / Unauthorized">
    Make sure a token is reaching the server: `UPSOLVE_PROJECT_USER_JWT` for stdio, or an `Authorization: Bearer` header for HTTP.
  </Accordion>

  <Accordion title="Session expired (401)">
    The project-user token is past its expiry. Mint a fresh one (see [Backend Setup](/ai-agent-builder/deploy-agents/backend-setup)) and reconnect.
  </Accordion>

  <Accordion title="“Agent not found for your organization”">
    Check `UPSOLVE_AGENT_ID`, and confirm the agent has a published production version in Agent Studio and belongs to the same organization as the user's token.
  </Accordion>

  <Accordion title="Empty answer">
    The question returned no rows under this user's row-level security. Verify the user's `properties` and your data model's RLS.
  </Accordion>
</AccordionGroup>

***

## Next steps

<CardGroup cols={2}>
  <Card title="Backend Setup" icon="computer-mouse" href="/ai-agent-builder/deploy-agents/backend-setup">
    Register users and mint the project-user tokens this MCP consumes.
  </Card>

  <Card title="Build Your Agent" icon="robot" href="/ai-agent-builder/agents">
    Encode KPI definitions, golden assets, and guardrails before you expose the agent.
  </Card>

  <Card title="Claude MCP Server" icon="plug" href="/ai-agent-builder/deploy-agents/mcp-server">
    The builder-facing MCP for exploring your own data inside Claude.
  </Card>

  <Card title="Frontend Setup" icon="window" href="/ai-agent-builder/deploy-agents/frontend-setup">
    Embed the agent as a UI Space instead of (or alongside) MCP.
  </Card>
</CardGroup>
