---
title: "Built-in tools"
description: "The nine account, billing, credit and workspace tools the agent endpoint ships with — their scopes, what they return, how to disable them, and how to repoint them at renamed Convex functions."
canonical_url: "https://nuxt-backend.dev/docs/agents/mcp/built-in-tools"
---
# Built-in tools

> The nine account, billing, credit and workspace tools the agent endpoint ships with — their scopes, what they return, how to disable them, and how to repoint them at renamed Convex functions.

With the [agent surface](https://nuxt-backend.dev/docs/agents/mcp) enabled, nine tools are contributed to the MCP endpoint. Each one calls a scaffolded Convex function **as the signed-in user** (through the short-lived JWT the token exchange mints), so `ctx.auth`, workspace resolution and billing-entity resolution behave exactly as they do for a web session.

Every tool declares an OAuth scope. A tool whose scope the agent didn't get is **hidden from tools/list**, and a direct call to it is refused with `403` — list-time hiding is only advisory, so the handler re-checks.

## The tools

<table>
<thead>
  <tr>
    <th>
      Tool
    </th>
    
    <th>
      Scope
    </th>
    
    <th>
      Arguments
    </th>
    
    <th>
      Returns
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        profile-get
      </code>
    </td>
    
    <td>
      <code>
        profile
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      The signed-in user's profile: name, email, verification state (<code>
        { error: 'No profile found for this session.' }
      </code>
      
       when there is none)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        profile-update
      </code>
    </td>
    
    <td>
      <code>
        profile:write
      </code>
    </td>
    
    <td>
      <code>
        name
      </code>
      
       (1–256 chars)
    </td>
    
    <td>
      <code>
        { ok: true, name }
      </code>
      
       — the new display name. <strong>
        Name only
      </strong>
      
      : email changes stay in the verified web flow
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        billing-plans
      </code>
    </td>
    
    <td>
      <code>
        billing:read
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      The configured billing products (plans and credit packs) with live pricing
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        billing-subscription
      </code>
    </td>
    
    <td>
      <code>
        billing:read
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      <code>
        { subscription }
      </code>
      
       for the billing entity (active workspace, or the user) — <code>
        null
      </code>
      
       when there is none
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        credits-balance
      </code>
    </td>
    
    <td>
      <code>
        billing:read
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      The prepaid credit balances per meter (<code>
        { meters: [] }
      </code>
      
       when none)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        billing-checkout-link
      </code>
    </td>
    
    <td>
      <code>
        billing:checkout
      </code>
    </td>
    
    <td>
      <code>
        productIds
      </code>
      
       (≥ 1, from <code>
        billing-plans
      </code>
      
      ), <code>
        successPath?
      </code>
      
       (app-relative)
    </td>
    
    <td>
      <code>
        { url, note }
      </code>
      
       — a checkout <strong>
        link
      </strong>
      
       for the user to open
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        billing-portal-link
      </code>
    </td>
    
    <td>
      <code>
        billing:checkout
      </code>
    </td>
    
    <td>
      <code>
        returnPath?
      </code>
      
       (app-relative)
    </td>
    
    <td>
      <code>
        { url, note }
      </code>
      
       — a customer-portal <strong>
        link
      </strong>
      
       for managing subscription, invoices and payment methods
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        workspace-list
      </code>
    </td>
    
    <td>
      <code>
        workspace:read
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      <code>
        { workspaces }
      </code>
      
       — the user's workspaces with role, and which one is active
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        workspace-members
      </code>
    </td>
    
    <td>
      <code>
        workspace:read
      </code>
    </td>
    
    <td>
      <code>
        organizationId?
      </code>
      
       (from <code>
        workspace-list
      </code>
      
      , default: the active workspace)
    </td>
    
    <td>
      The workspace's members (<code>
        { error: 'Not a member of this workspace.' }
      </code>
      
       otherwise)
    </td>
  </tr>
</tbody>
</table>

The scopes come from the package's fixed catalogue (`BACKEND_MCP_SCOPES`): `openid`, `profile`, `email` (the OIDC identity scopes the provider always grants), plus `profile:write`, `billing:read`, `billing:checkout` and `workspace:read`. Reads never ask for more than a `*:read` scope — see [scope semantics](https://nuxt-backend.dev/docs/agents/mcp/oauth-and-consent#scope-semantics).

<warning>

**The checkout tools return links, never payments.** `billing-checkout-link` and `billing-portal-link` hand back a URL for the human to open in their browser — no tool in this package executes a payment, and both carry `destructiveHint: false`. The `successPath` / `returnPath` arguments must be **app-relative** (they are validated against `/^\//`) and are appended to the request origin, so a prompt-injected agent cannot bounce a paying user to an attacker's origin.

</warning>

<note>

The read tools are annotated `readOnlyHint`, `profile-update` is `idempotentHint`, and the two link tools are `openWorldHint` — hints MCP clients use to decide when to ask the human for confirmation.

</note>

## What an agent sees

An agent sees a tool only when the person it acts for consented to the tool's scope; a person who grants `billing:read` alone never exposes the checkout links. Your own tools under `server/mcp/tools/` sit beside the built-ins under the same rule — see [Custom tools](https://nuxt-backend.dev/docs/agents/mcp/custom-tools).

<tip>

The **Agents** page of the [Backend DevTools tab](https://nuxt-backend.dev/docs/start/develop/devtools#agents) lists the route and every built-in tool with its scope.

</tip>

## Repointing the Convex functions

Each tool calls a scaffolded function by `module:export` reference. Rename the scaffolded `auth.ts` / `billing.ts` files (or their exports) and the tools need to be told where the functions went — that is what `backend.mcp.functions` is for:

<table>
<thead>
  <tr>
    <th>
      <code>
        functions
      </code>
      
       key
    </th>
    
    <th>
      Default ref
    </th>
    
    <th>
      Used by
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        getAuthUser
      </code>
    </td>
    
    <td>
      <code>
        auth:getAuthUser
      </code>
    </td>
    
    <td>
      <code>
        profile-get
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        updateProfile
      </code>
    </td>
    
    <td>
      <code>
        auth:updateProfile
      </code>
    </td>
    
    <td>
      <code>
        profile-update
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        getConfiguredProducts
      </code>
    </td>
    
    <td>
      <code>
        billing:getConfiguredProducts
      </code>
    </td>
    
    <td>
      <code>
        billing-plans
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        getCurrentSubscription
      </code>
    </td>
    
    <td>
      <code>
        billing:getCurrentSubscription
      </code>
    </td>
    
    <td>
      <code>
        billing-subscription
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        getCredits
      </code>
    </td>
    
    <td>
      <code>
        billing:getCredits
      </code>
    </td>
    
    <td>
      <code>
        credits-balance
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        generateCheckoutLink
      </code>
    </td>
    
    <td>
      <code>
        billing:generateCheckoutLink
      </code>
    </td>
    
    <td>
      <code>
        billing-checkout-link
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        generateCustomerPortalUrl
      </code>
    </td>
    
    <td>
      <code>
        billing:generateCustomerPortalUrl
      </code>
    </td>
    
    <td>
      <code>
        billing-portal-link
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        listWorkspaces
      </code>
    </td>
    
    <td>
      <code>
        auth:listWorkspaces
      </code>
    </td>
    
    <td>
      <code>
        workspace-list
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        listWorkspaceMembers
      </code>
    </td>
    
    <td>
      <code>
        auth:listWorkspaceMembers
      </code>
    </td>
    
    <td>
      <code>
        workspace-members
      </code>
    </td>
  </tr>
</tbody>
</table>

```ts [nuxt.config.ts]
backend: {
  mcp: {
    functions: {
      getCredits: 'myBilling:getCredits',
      generateCheckoutLink: 'myBilling:generateCheckoutLink',
    },
  },
}
```

Only the keys you pass are overridden; the rest keep their defaults.

<note>

`doctor`'s `function-contract` finding lists any `module:export` name the deployment is missing — the same names the composables and these tools bind to. See [Troubleshooting](https://nuxt-backend.dev/docs/ship/operate/troubleshooting).

</note>


## Sitemap

See the full [sitemap](https://nuxt-backend.dev/sitemap.md) for all pages.
