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

# MCP Server

> Connect AI agents and assistants to Profile via the Model Context Protocol

Profile exposes a [Model Context Protocol](https://modelcontextprotocol.io) server that lets AI agents (ChatGPT Apps, Claude Connectors, or any MCP-compatible client) act on behalf of a Profile user. An authorized agent can send assessment invites, manage tags, and retrieve behavioral summaries through the same backend that powers the Profile web app.

This page is a human-readable overview of that surface. The **authoritative, always-current catalog** is what the MCP server itself reports in response to a `tools/list` call. If you need exact JSON schemas for a code generator, ask the server.

## How it connects

* **Endpoint:** `POST https://vanguard.profilebehavior.com/mcp` (streamable HTTP transport)
* **Discovery:** `GET /.well-known/oauth-protected-resource` returns the authorization server URL and supported scopes
* **Authentication:** OAuth 2.1 (authorization code + PKCE). See the [Authentication](/api-reference/authentication) page for the full flow.

When an MCP client hits `/mcp` without a token, the response includes a `WWW-Authenticate: Bearer resource_metadata="..."` header pointing at the protected-resource metadata. Spec-compliant clients follow this automatically and initiate the OAuth flow.

Tokens issued through this flow are scoped to **one Profile account**: the account the user was signed into when they consented. An agent connected to Account A cannot read or modify data in Account B, even if the same user belongs to both.

## Tool surface

Tools operate on the account the user consented from. Tool inputs take resource-specific IDs (tag IDs, profile IDs) but never an account ID. Every tool advertises `title`, `description`, and behavior annotations (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`) so the client can decide when to prompt for confirmation.

### Tags

Required scope: `tags:manage`

#### `list_tags`

Read-only. Returns tags on the connected account with optional paginated listing and full-text search over the tag label.

* **Inputs:** `search` (optional string), `limit` (optional number), `page` (optional 1-indexed number)
* **Returns:** array of `{ id, label, color, profiles }` plus a total count
* **Side effects:** none
* **Typical errors:** no required input is missing, so most failures are infrastructure-level and return a generic message.

#### `create_tag`

Additive write. Creates a new tag on the connected account.

* **Inputs:** `label` (string, required), `color` (string, required, one of `emerald`, `red`, `yellow`, `orange`, `blue`, `indigo`, `purple`, `pink`, `zinc`)
* **Returns:** the created tag
* **Side effects:** writes an audit-log entry
* **Typical errors:** `label is required`; `invalid color "x"`

#### `update_tag`

Destructive write (overwrites label and color). Idempotent.

* **Inputs:** `tagId` (string, required), `label` (string, required), `color` (string, required, same allowed values as create)
* **Returns:** the updated tag
* **Side effects:** writes an audit-log entry; invalidates cached views of the tag
* **Typical errors:** `Tag not found` (also returned when the tag exists but belongs to a different account); validation errors on label and color

#### `delete_tag`

Destructive write. Idempotent on subsequent calls (the tag is simply not found).

* **Inputs:** `tagId` (string, required)
* **Returns:** `{ deleted: true, tagId }`
* **Side effects:** removes the tag from every profile it was attached to; writes an audit-log entry
* **Typical errors:** `Tag not found`

#### `assign_tags_to_profiles`

Destructive write (replaces the profile set on the tag). Idempotent.

* **Inputs:** `tagId` (string, required), `profileIds` (array of strings, required, can be empty to clear all assignments)
* **Returns:** the updated tag with its new profile set
* **Side effects:** writes an audit-log entry
* **Typical errors:** `Tag not found`; `One or more profiles not found on this account` when any supplied profile ID doesn't exist on the connected account

### Profiles

Required scope: `profiles:read`

#### `list_profiles`

Read-only. Returns profiles the user has access to on the connected account.

* **Inputs:** `search` (optional string, full-text over name), `tagId` (optional string, filter by tag membership), `isCompleted` (optional boolean, filter by assessment completion), `limit` (optional number), `page` (optional 1-indexed number)
* **Returns:** array of profile summaries `{ id, name, email, phone, isCompleted, tagIds }` plus a total count
* **Side effects:** none
* **Typical errors:** `invalid tagId` if a malformed tag ID is supplied

### Assessment invites

Required scope: `profiles:write`

#### `send_assessment_invite`

Additive write. Sends a real assessment invite email or SMS to the recipient.

* **Inputs:** `email` (optional string, but required if no phone), `phone` (optional string, E.164 format, required if no email), `tagId` (optional string to attach the new profile to a tag), `customId` (optional string for external ID mapping)
* **Returns:** `{ profileId, created, email, phone }`. `created: true` means a new profile was created; `created: false` means the recipient already had a profile and the invite was added or re-sent.
* **Side effects:** sends a magic link via email or SMS; creates or updates a Profile record; writes an audit-log entry
* **Typical errors:** `Email or phone number is required`; `One or more tags not found for account`; `Maximum reports reached for trial account` (402 for trial accounts at their profile cap)

### Behavioral summary

Required scope: `profiles:read`

#### `get_behavioral_summary`

Composite read of a profile's behavioral data. Triggers debrief generation on first access.

* **Inputs:** `profileId` (string, required)
* **Returns:** profile identity (`name`, `email`, `isCompleted`), DISC scores and style, Focus trait scores and levels, Core value rankings, and the AI-generated debrief content plus its ID. `debriefGenerated: true` indicates a new debrief was created during this call.
* **Side effects:** if no debrief exists for the profile, one is generated and stored. Generation can take up to a minute and consumes AI compute on our side.
* **Typical errors:** `Profile not found`; `Profile is not on this account` (when the profile exists but belongs to a different account)

#### Why this tool is marked non-read-only

The MCP annotation for `get_behavioral_summary` has `readOnlyHint: false` because first-time calls for a given profile write a new AIReportFixture to the database. Subsequent calls for the same profile read the cached result. Clients may prompt for confirmation on first access; repeated calls do not re-prompt if the grant permits.

## Scopes

MCP tool calls use a subset of the full OAuth scope set. The complete list is in the [Authentication](/api-reference/authentication) page.

| Scope            | Used by tools                                                                    |
| ---------------- | -------------------------------------------------------------------------------- |
| `profiles:read`  | `list_profiles`, `get_behavioral_summary`                                        |
| `profiles:write` | `send_assessment_invite`                                                         |
| `tags:manage`    | `list_tags`, `create_tag`, `update_tag`, `delete_tag`, `assign_tags_to_profiles` |

Scopes the user doesn't grant at consent time block the corresponding tools entirely. An LLM calling `create_tag` without `tags:manage` receives an error, never a silent success.

## Connecting from a client

### ChatGPT Apps

Register a new app in the OpenAI Apps SDK dashboard. Point the MCP server URL at `https://vanguard.profilebehavior.com/mcp`. OpenAI's platform handles OAuth discovery and Dynamic Client Registration against the authorization server referenced in our protected-resource metadata.

### Claude Connectors

In Claude's connector settings, add a custom MCP server with URL `https://vanguard.profilebehavior.com/mcp`. Claude follows the same discovery path.

### Custom MCP clients

If you're writing a client directly against the MCP spec (e.g. using [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol)), the only Profile-specific configuration is the server URL. Everything else (DCR, authorization, token exchange, tool invocation) is standard MCP + OAuth 2.1.

## Inspecting the live tool catalog

If you need to see the tool list with exact JSON schemas, either connect with [`mcp-inspector`](https://github.com/modelcontextprotocol/inspector) (authenticates via OAuth, lets you list tools and invoke them by hand) or have a registered MCP client send a standard `tools/list` request. This is always more current than any documentation page, including this one.
