---
title: "Build a custom client"
description: "Authenticate a custom MCP client, discover Mindtickle tools, manage conversation history, and handle errors."
contentType: "guide"
url: "https://developer.mindtickle.com/docs/mcp/build-a-custom-client/"
---

Use the client credentials flow to connect a custom AI client or agent to Mindtickle MCP without interactive sign-in. Requests still run on behalf of the Mindtickle user identified by `username` in the token request.

For an organization-managed connection through an AI client's settings, see [Set up the connector](/docs/mcp/publish-the-connector/). To connect your account to an existing connector, see [Connect your account](/docs/mcp/connect-your-account/).

:::note

Client-credentials setup is not self-service. The Mindtickle team issues the credentials for this flow. Contact your Customer Success Manager (CSM) or account team to set up this integration. User-authorized clients follow the separate OAuth registration flow described in Step 2.

:::

## Before you begin

Confirm the following:

- You can request client credentials from your Mindtickle Customer Success Manager or account team, as described in Step 1.
- You know your Mindtickle instance URL (referred to as `{mindtickle-instance-url}` throughout this article). Use only the hostname, without the protocol or path. For example, `example.mindtickle.com`.
- Your AI client supports MCP over HTTP and can send the `Authorization` header with every request. Clients such as Claude Desktop and Cursor support MCP natively. Platforms such as Slack, Salesforce Agentforce, and Microsoft 365 Copilot require a custom integration.

## Step 1: Get your client credentials

Contact your Customer Success Manager or account team to obtain the following credentials:

- `client_id`
- `client_secret`

:::note

- The `client_secret` is required to generate access tokens. Store it in a secure vault or secret manager. Never expose it in code, logs, or shared documents.
- Credentials for the client credentials grant are issued only by Mindtickle. There is no self-service API for obtaining these credentials.

:::

### Scopes

A scope grants access to one or more tools. Include one or more scopes, separated by spaces, in the `scope` parameter when requesting a token. The server checks the token's scopes before invoking any tool and returns only matching tools from `tools/list`. For what each tool does, see [Supported tools](/docs/mcp/tools/).

| Scope               | Grants access to                                                            | Description                                                                                                          |
| ------------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `read:search`       | `mindtickle_search`                                                         | Lets the client call the search tool.                                                                                |
| `read:copilot_chat` | `mindtickle_seller_copilot_ask`                                             | Lets the client call the Copilot chat tool.                                                                          |
| `read:rooms`        | `find_deals`, `find_companies`, `find_contacts`, `find_rooms`, `fetch_room` | Lets the client call the read-only Digital Sales Room tools.                                                         |
| `write:rooms`       | `create_room`, `edit_room`, `share_room`, `create_contacts`                 | Lets the client call the Digital Sales Room tools that create or modify data, including sharing a room with a buyer. |

:::note

Follow the principle of least privilege. Request only the specific scopes your integration needs.

:::

## Step 2: Generate an access token

Choose the authentication flow for your integration:

- **Unattended requests:** Use the client credentials grant below. Supply `username` to identify the Mindtickle user whose permissions apply to tool calls. This flow does not require interactive sign-in for each token request.
- **User-authorized requests:** If each user signs in and authorizes access, use the authorization code grant with Proof Key for Code Exchange (PKCE) and dynamic client registration. The AI client handles registration as part of this flow; it is separate from obtaining client credentials from Mindtickle. See [Set up the connector](/docs/mcp/publish-the-connector/) for the connection flow and [Best practices](/docs/mcp/best-practices/) for registration requirements.

For the client credentials flow, send the following request to obtain a short-lived Bearer token.

### Endpoint

```http
POST https://{mindtickle-instance-url}/api/users/v1/oauth/token
```

### Request headers

```http
Content-Type: application/json
```

### Request

| Parameter       | Type   | Required | Description                                                                                                                                                                                                                  |
| --------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `grant_type`    | string | Required | The OAuth grant type. Set this to `client_credentials`.                                                                                                                                                                      |
| `client_id`     | string | Required | The client ID issued by Mindtickle.                                                                                                                                                                                          |
| `client_secret` | string | Required | The client secret issued by Mindtickle.                                                                                                                                                                                      |
| `username`      | string | Required | The email address of the Mindtickle user on whose behalf the token is issued. Tool calls run in this user's context, and results respect the permissions and content access policies applied to that user inside Mindtickle. |
| `scope`         | string | Required | The scopes required for the request, separated by spaces. For example, `read:search read:copilot_chat`. See [Scopes](#scopes).                                                                                               |

#### Request example

```json
{
  "grant_type": "client_credentials",
  "client_id": "CLIENT_ID",
  "client_secret": "CLIENT_SECRET",
  "username": "user@example.com",
  "scope": "read:search read:copilot_chat"
}
```

### Response

| Parameter      | Type   | Description                                                         |
| -------------- | ------ | ------------------------------------------------------------------- |
| `access_token` | string | The JWT used to authenticate requests to the Mindtickle MCP server. |
| `token_type`   | string | The token type. The value is always `Bearer`.                       |
| `expires_in`   | number | The token's validity period, in seconds.                            |
| `scope`        | string | The scopes granted for this token.                                  |

#### Response example

This illustrative response uses a placeholder token. Use the returned `expires_in` value rather than assuming the example duration.

```json
{
  "access_token": "ACCESS_TOKEN",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "read:search read:copilot_chat"
}
```

### Token lifecycle

- Use the `expires_in` value to determine how long a token remains valid. Do not hardcode a token duration.
- Cache and reuse the token, and obtain a replacement before it expires, rather than requesting a new token on every call.
- When a token expires, call the token endpoint again to generate a new one before making further requests. The server does not refresh tokens automatically for the client credentials grant.
- The token endpoint allows 20 requests per minute per client. Requests above this limit return `429`. Reuse valid tokens to avoid unnecessary token requests.

## Step 3: Configure your client

Configure your AI client to connect to the Mindtickle MCP server using the access token generated in the previous step. Include the token in the `Authorization` header in the format `Bearer <access_token>` on every request.

**Server URL:**

```text
https://{mindtickle-instance-url}/mcp
```

**Example client configuration:**

The following example shows a Cursor-style `mcp.json` configuration. Replace `MINDTICKLE_MCP_URL` with the complete HTTPS server URL shown above, including `/mcp`, and `ACCESS_TOKEN` with your access token. These are placeholders, not environment-variable interpolation syntax. Adapt the structure and secure credential loading to your client's configuration format.

```json
{
  "mcpServers": {
    "mindtickle": {
      "url": "MINDTICKLE_MCP_URL",
      "headers": {
        "Authorization": "Bearer ACCESS_TOKEN"
      }
    }
  }
}
```

:::note

- The Mindtickle MCP server requires authentication on every request.
- Restart or refresh your client after updating the configuration.
- Store tokens in environment variables or a secure secret manager. Do not hardcode tokens in your client configuration.

:::

## Step 4: Discover and call tools

Once your client is connected, it can discover the tools available on the Mindtickle MCP server using the `tools/list` method. The tools returned depend on the scopes included in your access token. The server validates the token and enforces scope on every request.

The Mindtickle MCP server exposes several tools. For the full list, required scopes, and behavior details, see [Supported tools](/docs/mcp/tools/).

### End-user interaction guidance

End users typically ask task-based questions rather than platform-specific ones. For example:

- "Find learning content to understand product XYZ."
- "Learn more about product XYZ."
- "Find the battle card for competitor ABC."
- "Identify training for objection handling for product XYZ."

### Integrator responsibilities

- Configure your agent or copilot to map user intent to the appropriate tool.
- Do not depend on users explicitly referencing Mindtickle in their queries.
- Use explicit tool references only for manual or developer testing. Do not require explicit tool names in production user experiences.

### Example: a single tool call

The following example shows the method and parameters for a `tools/call` request that resolves a company by name. The tool-call examples in this section are request fragments, not complete JSON-RPC envelopes.

```json
{
  "method": "tools/call",
  "params": {
    "name": "find_companies",
    "arguments": {
      "query": "Acme Corp"
    }
  }
}
```

The response contains matching company records. Pass a selected company ID in the `company_ids` parameter of `find_deals`. The `find_rooms` tool supports a free-text `query`, not a company ID filter. For exact request and response schemas, see [Supported tools](/docs/mcp/tools/).

### Example: chaining tool calls

A workflow can use the result of one tool call as input to the next. This example finds a company, finds its matching deals, and retrieves a room using the `room_id` returned by `find_deals`:

```json
{
  "method": "tools/call",
  "params": {
    "name": "find_companies",
    "arguments": {
      "query": "Acme Corp"
    }
  }
}
```

```json
{
  "method": "tools/call",
  "params": {
    "name": "find_deals",
    "arguments": {
      "company_ids": ["{id from find_companies}"]
    }
  }
}
```

```json
{
  "method": "tools/call",
  "params": {
    "name": "fetch_room",
    "arguments": {
      "room_id": "{room_id from find_deals}"
    }
  }
}
```

Select the intended company and deal if a call returns multiple matches. Pass the selected deal's non-null `room_id` to `fetch_room`. If no deal matches or its `room_id` is null, this sequence has no room UUID to retrieve. Do not pass a company ID or deal ID as a room ID.

The `find_rooms` tool supports a free-text `query`, not `company_id` or `deal_id` filters. This sequence therefore uses `find_deals` to obtain the room UUID directly. See [Supported tools](/docs/mcp/tools/) for field details.

## Conversation history

For the `mindtickle_seller_copilot_ask` tool, your client must maintain the full conversation history, including all follow-up questions, and send the updated history with each request.

### Request example

```json
{
  "input": [
    { "role": "user", "content": "How do I improve readiness?" },
    { "role": "assistant", "content": "Start with coaching and role-play..." },
    { "role": "user", "content": "Create a 2-week plan." }
  ]
}
```

For full conversation handling rules, see [Supported tools](/docs/mcp/tools/).

### Streaming responses

By default, `mindtickle_seller_copilot_ask` returns a single buffered response once Seller Copilot has finished generating it. To receive the response incrementally instead, include a `progressToken` in the request's `_meta` field. When a token is present, the server sends a series of MCP `notifications/progress` messages as each chunk of the answer becomes available, in addition to the final buffered response.

:::note

Use incremental `notifications/progress` messages to display progress; their delivery is not guaranteed. Treat the final `tools/call` response as authoritative, but check its `status` and `error` before treating `fullText` as complete. A stalled response stream can return a partial answer. Streaming is opt-in and specific to this tool; no other Mindtickle MCP tool supports it.

:::

## Errors

This section documents the errors returned by the token endpoint and by the Mindtickle MCP server itself.

### Token endpoint status codes

| Status | Description                                             |
| ------ | ------------------------------------------------------- |
| 200    | The request is successful and returns a valid response. |
| 400    | The request is invalid or missing required parameters.  |
| 401    | The request contains invalid client credentials.        |
| 403    | The user is not authorized to perform this request.     |
| 429    | The client exceeded 20 token requests per minute.       |

### MCP error codes

The Mindtickle MCP server returns the following error codes on `tools/list` and `tools/call` requests.

| Code                     | Description                                                              |
| ------------------------ | ------------------------------------------------------------------------ |
| `MISSING_AUTH_HEADER`    | The request does not include the `Authorization` header.                 |
| `INVALID_AUTH_HEADER`    | The `Authorization` header is not in the correct format.                 |
| `TOKEN_EXPIRED`          | The token has expired and must be regenerated.                           |
| `TOKEN_INVALID`          | The token is invalid or cannot be verified.                              |
| `INVALID_TOKEN`          | The token is missing required claims or cannot be validated.             |
| `TOKEN_VALIDATION_ERROR` | The system encountered an error while validating the token.              |
| `INVALID_CONTEXT_TOKEN`  | The token was rejected during context validation.                        |
| `INSUFFICIENT_SCOPE`     | The token does not include the scope required for the tool being called. |
| `NO_TOKEN_FOUND`         | The `Authorization` header did not contain a valid token.                |
| `CLIENT_CANCELLED`       | The client canceled the request.                                         |
| `API_ERROR`              | A downstream Mindtickle API failed.                                      |
| `VALIDATION_ERROR`       | Request validation failed.                                               |
| `INTERNAL_ERROR`         | An unexpected system error occurred.                                     |

### Downstream API errors

These errors come from the Mindtickle APIs called by a tool. They appear inside the tool response rather than as token or MCP-level errors.

| Code                    | Description                                                                                                                                                           |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `API_AUTH_FAILED`       | The Mindtickle API the tool called rejected the request because the underlying token has expired or is no longer valid.                                               |
| `API_PERMISSION_DENIED` | The Mindtickle API the tool called rejected the request because the user does not have permission to perform it.                                                      |
| `API_TIMEOUT`           | The request reached the Mindtickle API, but no response came back before the tool's timeout. See [Supported tools](/docs/mcp/tools/#timeouts) for per-tool timeout values. |
| `GRAPHQL_ERROR`         | The Mindtickle API returned a response that also contains one or more errors, most commonly from the search tool.                                                     |
| `COPILOT_BACKEND_ERROR` | Seller Copilot reported a failure while generating a response to a `mindtickle_seller_copilot_ask` call.                                                              |

### Failure behavior

| Situation            | Behavior                                          |
| -------------------- | ------------------------------------------------- |
| `tools/list` failure | The request fails with an MCP error.              |
| `tools/call` failure | The system returns an error in the tool response. |
| Upstream API failure | The error appears in the tool output.             |

:::note

- Token-related issues are the most common cause of failures. Always validate scopes and token freshness before retrying a failed request.
- Some errors appear inside tool responses rather than as HTTP errors. Inspect both the HTTP status and the response body when debugging.
- If your MCP session expires mid-conversation, the server recovers automatically on the next tool call. You do not need to detect this and reconnect yourself.

:::

For security, reliability, and integration-design practices to follow when building against this path, see [Best practices](/docs/mcp/best-practices/).

## Related

- [Supported tools](/docs/mcp/tools/): Tool parameters, response fields, and limits.
- [Best practices](/docs/mcp/best-practices/): Security, reliability, and integration guidance.
- [Set up the connector](/docs/mcp/publish-the-connector/): The managed connector setup path.
