# Flyte MCP server

`FlyteMCPAppEnvironment` exposes Union.ai operations as standardized [MCP](https://modelcontextprotocol.io) tools, so AI assistants and LLM clients can drive your cluster programmatically — running tasks, monitoring runs, managing apps and triggers, building images, running UV scripts, and searching the SDK and docs.

Unlike [`MCPAppEnvironment`](https://www.union.ai/docs/v2/union/user-guide/build-mcp/flyte_mcp_server/mcp_server), where you supply your own tools, this environment ships a curated set of Flyte tools out of the box. You decide which of them to expose and what they're allowed to touch.

## When to use it

Use a Flyte MCP server when you want an assistant to *act on your cluster on your behalf*. Common scenarios:

- **Agentic development loops**: Let Claude Code or OpenCode run a task, wait for it, read its outputs, and iterate — without you copy-pasting commands.
- **Conversational operations**: Ask an assistant to list recent runs, check a run's status, or abort a stuck run.
- **Docs- and example-aware coding**: Enable the `search` tools so an assistant can ground its answers in the Flyte SDK examples and Union documentation.
- **Self-service automation**: Give a trusted internal agent a tightly-scoped server (a few allowlisted tasks, no destructive tools) to perform a narrow job.

If you only need to expose custom, non-Flyte tools, use [`MCPAppEnvironment`](https://www.union.ai/docs/v2/union/user-guide/build-mcp/flyte_mcp_server/mcp_server) instead.

## How to run it

There are two ways to run a Flyte MCP server, suited to different stages:

| Mode | When to use |
|------|-------------|
| **Local (stdio)** | Local development and quick experiments. The client launches the server as a subprocess on your machine, using your local Flyte config. |
| **Remote (HTTP)** | Shared or production use. The server runs as a deployed app with a stable, authenticated URL that any client can connect to. |

### Running locally with `uvx`

The `flyte[mcp]` extra ships a `flyte-mcp` CLI entrypoint. Run it with [`uvx`](https://docs.astral.sh/uv/guides/tools/) — no global install required:

```bash
uvx --from "flyte[mcp]" flyte-mcp
```

`uvx` downloads `flyte[mcp]` into an isolated environment, runs `flyte-mcp`, and exits cleanly when you're done. The server reads your active Flyte config (the same one used by the `flyte` CLI or `flyte.init_from_config()`), so whichever project and cluster you're pointed at is what the tools operate on.

> [!TIP]
> Pin to a specific SDK version: `uvx --from "flyte[mcp]==2.4.0" flyte-mcp`

Once running, register it with your client as a **stdio** transport — the client manages the process lifetime. See the [connecting a client](#connecting-a-client) section below.

### Deploying remotely

Deploy a `FlyteMCPAppEnvironment` as a long-running app to get a stable, shared HTTP endpoint:

```python
flyte.init_from_config()
handle = flyte.serve(mcp_env)
handle.activate(wait=True)
print(f"MCP endpoint: {handle.endpoint}/flyte-mcp/mcp")
```

See [Serve and deploy apps](https://www.union.ai/docs/v2/union/user-guide/build-mcp/serve-and-deploy-apps/_index) for how deployment, activation, and scaling work in general.

## Basic example

This deploys a remote server with **all** tools enabled:

```
# /// script
# requires-python = ">=3.12"
# dependencies = [
#    "flyte>=2.0.0",
#    "mcp",
#    "starlette",
#    "uvicorn",
# ]
# ///

"""A Flyte MCP server app that exposes Flyte operations as MCP tools.

This example deploys an MCP (Model Context Protocol) server that allows AI
assistants and LLM-based clients to interact with the Flyte control plane
using the standardized MCP protocol.

The server exposes tools for running tasks, monitoring runs, managing apps
and triggers, building container images, building and running UV scripts
remotely, and searching Flyte SDK/docs examples.

Requirements:
    pip install 'flyte[mcp]'

Usage:

    Deploy all tools

    $ python v2/user-guide/build-mcp/flyte_mcp_app.py

    Or serve locally for development (recommended: `uvx`)

    $ uvx --from "flyte[mcp]" flyte-mcp
"""

import flyte
from flyte.ai.mcp import FlyteMCPAppEnvironment

# {{docs-fragment flyte-mcp-all-tools}}
# Deploy an MCP server with all tools enabled
mcp_env = FlyteMCPAppEnvironment(
    name="flyte-mcp-server",
    resources=flyte.Resources(cpu=1, memory="512Mi"),
    transport="streamable-http",
    instructions=(
        "This MCP server provides tools to interact with the Flyte control plane. "
        "Use the available tools to run tasks, monitor runs, manage apps, build images, "
        "build and run UV scripts remotely, and search SDK/docs examples."
    ),
)

if __name__ == "__main__":
    flyte.init_from_config()
    app_handle = flyte.serve(mcp_env)
    app_handle.activate(wait=True)
    print(f"App is ready at {app_handle.endpoint}")
# {{/docs-fragment flyte-mcp-all-tools}}
```

*Source: https://github.com/unionai/unionai-examples/blob/main/v2/user-guide/build-mcp/flyte_mcp_app.py*

The default mount path is `/flyte-mcp`, so with the default `streamable-http` transport the MCP endpoint is `/flyte-mcp/mcp`.

> [!TIP] Set `instructions`
> The `instructions` string is sent to the LLM as guidance on what the server is for and how to use its tools. A clear, specific instruction string measurably improves how reliably the assistant picks the right tool.

## Scoping the server

A server with every tool enabled and no restrictions is convenient for trusted local use, but for anything shared you should narrow it down. There are three layers of control, from coarse to fine.

### 1. Tool groups

Tools are organized into groups. Pass `tool_groups` to enable only the groups you need:

```python
mcp_env = FlyteMCPAppEnvironment(
    name="restricted-mcp",
    tool_groups=["task", "run", "script"],  # Only these groups
)
```

| Group | Tools | Typical use |
|-------|-------|-------------|
| `all` | All tools (default when both `tool_groups` and `tools` are omitted) | Trusted local development |
| `core` | No tools (only HTTP routes) | Health-check-only / building up explicitly |
| `task` | `run_task`, `get_task`, `list_tasks` | Launching and inspecting tasks |
| `run` | `get_run`, `get_run_io`, `abort_run`, `list_runs`, `wait_for_run` | Monitoring and controlling runs |
| `app` | `get_app`, `activate_app`, `deactivate_app` | Managing deployed apps |
| `trigger` | `activate_trigger`, `deactivate_trigger` | Managing triggers |
| `build` | `build_image` | Building container images remotely |
| `script` | `build_uv_script_image_remote`, `run_uv_script_remote`, `flyte_uv_script_format`, `flyte_uv_script_example` | Running standalone UV scripts |
| `search` | `search_flyte_sdk_examples`, `search_flyte_docs_examples`, `search_full_docs` | Grounding answers in SDK/docs |

### 2. Individual tools

For the tightest control, pass `tools` with an explicit list of tool names instead of `tool_groups` (pass one or the other, not both):

```python
mcp_env = FlyteMCPAppEnvironment(
    name="read-only-mcp",
    tools=["get_run", "list_runs", "get_run_io"],  # No run_task, no abort_run
)
```

This is the way to build, for example, a strictly read-only server.

### 3. Allowlists

Even with a tool enabled, you can restrict *which resources* it may target. Allowlists are the safest way to expose `run_task` or app/trigger management to an agent:

```python
mcp_env = FlyteMCPAppEnvironment(
    name="restricted-mcp",
    task_allowlist=[
        "production/my-project/allowed-task",  # domain/project/task
        "my-project/another-task",             # project/task (any domain)
        "any-domain-task",                     # task only (any project/domain)
    ],
    app_allowlist=["my-app", "another-app"],
    trigger_allowlist=["nightly-retrain"],
)
```

When an allowlist is set, calls targeting anything outside it are rejected. Omitting an allowlist leaves that resource type unrestricted.

## Enabling the search tools

The `search` tools need a corpus to scan, so you must point them at filesystem paths that exist *inside the app image*:

- `sdk_examples_path` — Flyte SDK examples (powers `search_flyte_sdk_examples`)
- `docs_examples_path` — Union examples (powers `search_flyte_docs_examples`)
- `full_docs_path` — the docs `llms.txt` index (powers `search_full_docs`)

The default image already clones the flyte-sdk and unionai-examples repos and downloads `llms.txt` into `/root` for you. If you supply a custom `image`, bake the corpora in yourself and pass matching paths:

```python
image = (
    flyte.Image.from_debian_base()
    .with_apt_packages("ca-certificates", "git", "curl")
    .with_pip_packages("mcp", "starlette", "uvicorn")
    .with_commands([
        "git clone --depth 1 https://github.com/flyteorg/flyte-sdk.git /root/flyte-sdk",
        "git clone --depth 1 https://github.com/unionai/unionai-examples.git /root/unionai-examples",
        # Also download llms.txt to /root/llms.txt for full-docs search
    ])
)

mcp_env = FlyteMCPAppEnvironment(
    name="search-mcp",
    image=image,
    tool_groups=["search"],
    sdk_examples_path="/root/flyte-sdk/examples",
    docs_examples_path="/root/unionai-examples/v2",
    full_docs_path="/root/llms.txt",
)
```

## Putting it together: a filtered server

This example combines tool groups, an allowlist, search paths, and instructions to build a scoped, production-ready server:

```
# /// script
# requires-python = ">=3.12"
# dependencies = [
#    "flyte>=2.0.0",
#    "mcp",
#    "starlette",
#    "uvicorn",
# ]
# ///

"""A Flyte MCP server with filtered tools, scripting, and search.

This example shows how to deploy a more restricted MCP server that exposes
task, run, script, and search tools, with a task allowlist to restrict which
tasks can be accessed and configurable search paths for documentation.
"""

import flyte
from flyte.ai.mcp import FlyteMCPAppEnvironment

# Create an image with the required dependencies and search corpora baked in
image = (
    flyte.Image.from_debian_base()
    .with_apt_packages("ca-certificates", "git", "curl")
    .with_pip_packages("mcp", "starlette", "uvicorn")
)

# {{docs-fragment flyte-mcp-filtered}}
mcp_env = FlyteMCPAppEnvironment(
    name="restricted-mcp",
    image=image,
    resources=flyte.Resources(cpu=1, memory="512Mi"),
    transport="streamable-http",
    tool_groups=["task", "run", "script", "search"],
    task_allowlist=["my-project/my-task", "another-task"],
    # Search paths (see docstring): you need to clone/fetch these during image build.
    sdk_examples_path="/root/flyte-sdk/examples",
    docs_examples_path="/root/unionai-examples/v2",
    full_docs_path="/root/llms.txt",
    instructions=(
        "This MCP server provides tools to run and monitor specific Flyte tasks, "
        "build and run UV scripts remotely, and search Flyte SDK/docs examples. "
        "Only allowlisted tasks can be accessed."
    ),
)

if __name__ == "__main__":
    flyte.init_from_config()
    app_handle = flyte.serve(mcp_env)
    app_handle.activate(wait=True)
    print(f"App is ready at {app_handle.endpoint}")
# {{/docs-fragment flyte-mcp-filtered}}
```

*Source: https://github.com/unionai/unionai-examples/blob/main/v2/user-guide/build-mcp/flyte_mcp_app_filtered.py*

## Connecting a client

### Claude Code — local (stdio)

Registers the `flyte-mcp` process as a locally managed stdio server. Claude Code starts and stops the `uvx` process automatically:

```bash
claude mcp add --transport stdio flyte-mcp -- uvx --from "flyte[mcp]" flyte-mcp
```

### Claude Code — remote (HTTP)

For a deployed server with a public URL:

```bash
claude mcp add --transport http \
  --header "Authorization: Bearer $TOKEN" \
  flyte-mcp-remote https://<YOUR_HOST>/flyte-mcp/mcp
```

### OpenCode — local

OpenCode spawns the `uvx` command for you:

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "flyte-mcp": {
      "type": "local",
      "command": ["uvx", "--from", "flyte[mcp]", "flyte-mcp"],
      "enabled": true
    }
  }
}
```

### OpenCode — remote

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "flyte-mcp-remote": {
      "type": "remote",
      "url": "https://<YOUR_HOST>/flyte-mcp/mcp",
      "enabled": true,
      "headers": {
        "Authorization": "Bearer $TOKEN"
      }
    }
  }
}
```

## Best practices

1. **Start broad locally, scope down for sharing**: Run with `all` tools via `uvx` while exploring, then enable only the groups or tools you need before deploying a shared server.
2. **Always allowlist mutating tools**: If `run_task`, `abort_run`, or app/trigger management is enabled on a shared server, set the corresponding allowlist so an agent can't touch arbitrary resources.
3. **Prefer `tools` over `tool_groups` for read-only servers**: An explicit allowlist of read tools is the clearest way to guarantee an agent can't change anything.
4. **Write specific `instructions`**: Describe what the server does and any constraints (e.g. "only allowlisted tasks can be run"). This guides tool selection and reduces wasted calls.
5. **Keep auth on**: Leave `requires_auth=True` so only authenticated clients can reach a deployed server.

## MCP tools reference

| Tool | Group | Description |
|------|-------|-------------|
| `run_task` | `task` | Run a task with inputs; returns run URL and name |
| `get_task` | `task` | Get task metadata (type, required args, cache settings) |
| `list_tasks` | `task` | List tasks in a project/domain |
| `get_run` | `run` | Get run status by name |
| `wait_for_run` | `run` | Poll until a run completes |
| `get_run_io` | `run` | Get a run's inputs and outputs |
| `abort_run` | `run` | Abort a running run |
| `list_runs` | `run` | List runs for a task |
| `get_app` | `app` | Get app metadata |
| `activate_app` | `app` | Activate an app |
| `deactivate_app` | `app` | Deactivate an app |
| `activate_trigger` | `trigger` | Activate a trigger |
| `deactivate_trigger` | `trigger` | Deactivate a trigger |
| `build_image` | `build` | Build a container image remotely |
| `build_uv_script_image_remote` | `script` | Build a UV script image remotely |
| `run_uv_script_remote` | `script` | Run a UV script remotely |
| `flyte_uv_script_format` | `script` | Get the UV script template format |
| `flyte_uv_script_example` | `script` | Get a UV script example |
| `search_flyte_sdk_examples` | `search` | Search Flyte SDK examples |
| `search_flyte_docs_examples` | `search` | Search Union examples |
| `search_full_docs` | `search` | Search the full documentation |

---
**Source**: https://github.com/unionai/unionai-docs/blob/main/content/user-guide/build-mcp/flyte_mcp_server.md
**HTML**: https://www.union.ai/docs/v2/union/user-guide/build-mcp/flyte_mcp_server/
