> For the complete documentation index, see [llms.txt](https://docs.appfarm.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.appfarm.io/reference/flows/mcp-servers.md).

# MCP Servers

An MCP server exposes a [flow](/reference/flows.md) as a [Model Context Protocol](https://modelcontextprotocol.io/) server that external clients — such as Claude Desktop or Cursor — can connect to and call. Each non-private action in the flow becomes an MCP tool. When a tool is called, the action runs in the solution as the connected user, with that user's roles and permissions.

A flow is exposed as an MCP server by selecting **MCP** as the flow type when creating the flow. An MCP flow is dedicated to this purpose: its actions are MCP tools, and cannot also be exposed as [API Endpoints](/reference/flows/api-endpoints.md) or run on [Schedules](/reference/flows/schedules.md).

{% hint style="warning" %}
**Important**

* For an MCP server to be reachable in a given environment, the **Enable Flow Service** checkbox must be selected in the [Environment Configuration](/reference/configuration/environments.md).
* External clients connect on behalf of an individual user using OAuth. The **Allow external client access** checkbox in the [Environment Configuration](/reference/configuration/environments.md#external-clients) for the environment must also be selected. See [External clients](#external-clients) below.
  {% endhint %}

## Usage

To create an MCP flow:

* Click **Create Flow**.
* Select **MCP**.
* Set the API root path. This becomes part of the server URL.

To add an MCP tool to an existing MCP flow:

* Open the flow.
* Click **+ Create MCP Tool** in the **MCP Tools** panel.
* Enter a name for the tool.

The MCP server URL for a flow is:\
https\://`SOLUTION-HOSTNAME`/api/mcp/`API-ROOT-PATH`.

For example, if the API root path is `sales`, the URL would be:\
<https://your-solution.appfarm.app/api/mcp/sales>.

Configure your MCP client (for example, Claude Desktop or Cursor) with this URL. The client discovers Appfarm as the identity provider, and the user is prompted to sign in and approve the connection. See [External clients](#external-clients) for the connection flow, and [Connected apps](/reference/security/manage-your-appfarm-account.md#connected-apps) for where the user manages approved connections.

To view and test the tools on an MCP server, open the [MCP Inspector](/reference/flows/mcp-inspector.md).

## Server properties

The flow's own properties determine what the MCP server advertises to clients.

| Property          | Description                                                                                                                    |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| **Name**          | Used as the server name advertised to clients. Must follow the naming rules below.                                             |
| **Description**   | Used as the server instructions — guidance an agent reads to understand what the server is for and when to use its tools.      |
| **API Root Path** | The path segment used in the server URL. Must consist of valid URL characters, in kebab-case (for example, `customer-lookup`). |

## MCP tools

Each non-private action in an MCP flow is exposed as one MCP tool. The action's name, description, action params, and returnable action variables and action data sources determine how the tool is advertised and how its responses are shaped.

An action marked **Private** is not exposed as a tool. Private actions are still callable from other actions in the same flow using the [Run Action](/library/action-nodes/run-action.md) action node, which is useful for shared helper logic that should not be reachable from outside the flow.

### Tool properties

| Property        | Description                                                                                                                                                                                                             |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name**        | Used as the tool name advertised to clients. Must follow the naming rules below.                                                                                                                                        |
| **Description** | Used as the tool description. An agent reads this to decide whether and how to call the tool. The descriptions of action variables marked **Return from action** are appended automatically as a list of return values. |
| **Private**     | When selected, the action is excluded from the MCP server. The action remains callable from other actions in the flow via Run Action.                                                                                   |

### Tool input

The action's [action params](/reference/actions/action-params.md) define the tool's input schema. Each action param becomes one field on the tool input. The action param's **Data Type** determines the type advertised to the client.

| Action Param Data Type                                     | Advertised tool input type                                         |
| ---------------------------------------------------------- | ------------------------------------------------------------------ |
| Boolean                                                    | boolean                                                            |
| Integer                                                    | integer                                                            |
| Float                                                      | number                                                             |
| Multi Enum, Multi Reference                                | array of strings                                                   |
| Schema                                                     | object, with fields built recursively from the schema's properties |
| All other types (String, Enum, Reference, Date, Date Time) | string                                                             |

The action param's **Description** is exposed verbatim to the client. An action param is required on the tool input only if it is marked **Required** on the action param.

{% hint style="info" %}
**Good to know**

* Enum and reference params are advertised as plain strings. The accepted values are not enumerated in the tool schema.
* Action param names must be unique within an action. If two params resolve to the same name, only the first is exposed; the rest are dropped.
  {% endhint %}

### Tool output

When a tool is called, the action runs and returns:

* All [action variables](/reference/actions/action-variables.md) marked **Return from action**.
* All [action data sources](/reference/actions/action-data-sources.md) marked **Return from action**.

These are serialized into a single JSON payload and returned to the client. If the action throws an exception, the error is returned to the client and the call is marked as failed.

{% hint style="info" %}
**Good to know**

The response is a JSON-encoded string in an MCP text content block. Clients receive the JSON as text and parse it themselves; structured MCP output is not used.
{% endhint %}

## Naming rules

MCP clients identify servers and tools by name, and agents read those names to choose which tool to call. The platform enforces the MCP naming rules on flow names and tool names.

| Element           | Rule                                                            |
| ----------------- | --------------------------------------------------------------- |
| **Flow name**     | snake\_case ASCII, matching `[a-zA-Z0-9_.-]`, 1–128 characters. |
| **MCP Tool name** | snake\_case ASCII, matching `[a-zA-Z0-9_.-]`, 1–128 characters. |
| **API Root Path** | kebab-case URL characters (for example, `customer-lookup`).     |

Convert non-ASCII characters to ASCII equivalents. For Norwegian names, that means æ → `ae`, ø → `oe`, å → `aa`.

{% hint style="success" %}
**Best practice**

Names and descriptions are how an agent decides which tool to call. Write them so a reader who knows nothing about the flow can tell what each tool does and when to use it. Vague names like `do_thing` are unlikely to be selected even when they are the right tool.
{% endhint %}

## External clients

An external client is a third-party application — such as Claude Desktop or Cursor — that one of your users connects to an MCP server *as themselves*, using their Appfarm account. The user signs in at `accounts.appfarm.io`, approves a consent screen, and the client receives a token that lets it call the MCP server on the user's behalf. Tool calls then run as that user, with that user's roles and permissions in the solution.

This is separate from the [service account](/reference/security/service-accounts.md) and API key model used by [API Endpoints](/reference/flows/api-endpoints.md). The two models coexist; enabling external clients does not change anything about existing service accounts or API keys, which continue to work as before.

### Enabling external clients

External clients are off by default. To allow external clients to connect to MCP servers in an environment, select the **Allow external client access** checkbox in the [Environment Configuration](/reference/configuration/environments.md#external-clients) for that environment.

While **Allow external client access** is cleared:

* External MCP clients cannot discover the solution.
* External bearer tokens presented to an MCP server are rejected.
* The Appfarm sign-in flow rejects authorization requests targeting the solution.

Clearing this checkbox is a hard kill-switch. New connections cannot be made and existing connections cannot be refreshed. Access tokens that have already been issued continue to work until they expire — see [Revoking access](#revoking-access).

### The consent screen

After signing in, the user sees a consent screen before any external client can connect. The consent screen names:

* The app requesting access.
* The solution and environment being connected to.
* The full resource URL the app will call.
* What the app will be able to do — act on the user's behalf in the solution, read basic profile information, and stay signed in.
* That the user can revoke access at any time from [Connected apps](/reference/security/manage-your-appfarm-account.md#connected-apps).

The consent screen displays differently depending on whether the app is verified by Appfarm.

* **Verified app.** The app's name and logo anchor the screen, with a *Verified by Appfarm* affirmation. An app becomes verified through review by Appfarm staff, or because its sign-in redirect targets a domain Appfarm trusts (for example, `claude.ai`).
* **Unverified app.** The screen leads with the destination the sign-in is delivered to — the redirect host, such as `claude.ai` — rather than the name the app has chosen for itself. The self-claimed name is shown on a secondary line.

{% hint style="info" %}
**Good to know**

A malicious app can choose any name it likes for itself, but it cannot fake the destination its sign-in is delivered to. Leading with the destination on unverified apps is what protects users from an app impersonating a familiar brand.
{% endhint %}

### Tokens and permissions

When the user approves the consent screen, the client receives an access token that is:

* **Bound to one solution.** A token approved for one solution cannot be used against another, even if both are protected by the same Appfarm login.
* **Scoped to the approving user's permissions.** The client can do exactly what the user can do in the solution — no more. It cannot expand its access without the user approving a new consent screen.
* **Short-lived.** External client access tokens last 15 minutes. The client refreshes them silently as long as the connection remains approved.

### Revoking access

There are four ways to end an external client's access, from per-user to fleet-wide.

| Action                                                                                                                                                                        | Effect                                                                                                                                                    |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **The user revokes one app.** Done from [Connected apps](/reference/security/manage-your-appfarm-account.md#connected-apps).                                                  | The connection and stored tokens are deleted immediately. The client can no longer refresh, and its current access token stops working within 15 minutes. |
| **The user invalidates all sessions.** Done from the security panel of the user's Appfarm account.                                                                            | All of the user's sessions, including external client tokens, are invalidated immediately. Use this for lost-device or suspected-compromise situations.   |
| **An administrator clears Allow external client access.** Done per environment in the [Environment Configuration](/reference/configuration/environments.md#external-clients). | All external client connections to the solution stop refreshing immediately. Existing access tokens stop working within 15 minutes.                       |
| **Appfarm disables an app fleet-wide.**                                                                                                                                       | Appfarm can disable an individual app so it cannot be used on any solution.                                                                               |

{% hint style="warning" %}
**Important**

Revocation takes up to 15 minutes to take full effect. External client access tokens are validated locally by the platform without a callback to Appfarm, so a token already issued cannot be cancelled mid-life — it stops being valid when it expires.

For an instantaneous cutoff (for example, in a security incident), the user should invalidate all sessions in addition to revoking the connection.
{% endhint %}

## Limitations

* **One flow type per flow.** An action in an MCP flow cannot also be exposed as an API Endpoint or run on a Schedule. Share helper logic between flows by extracting it into another flow and calling it with [Run Flow](/library/action-nodes/run-flow.md).
* **Output is JSON inside a text block.** Structured MCP output is not produced; the client must parse the JSON itself.
* **No streaming, no sessions.** The server uses streamable HTTP with stateless JSON responses. Each tool call is a single request/response.
* **Enums and references are advertised as strings.** The accepted values are not listed in the tool schema.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.appfarm.io/reference/flows/mcp-servers.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
