---
title: Tools reference | FLORA API
description: The two MCP tools the FLORA server exposes, plus the full SDK method surface available inside execute.
---

The FLORA MCP server exposes exactly **two tools**: `search_docs` and `execute`. Rather than wrapping each API endpoint as a separate tool, the agent writes TypeScript against the `@flora-ai/flora` SDK inside a single `execute` call — keeping the interface simple and the agent in full control of sequencing and error handling.

This page covers the two tools and the SDK methods available inside `execute`. For exact request and response schemas, follow the **API Reference** links in each section — the SDK and REST API share the same data shapes.

## The two tools

### `search_docs`

Searches the `@flora-ai/flora` SDK documentation to find the right method, its parameter shapes, and usage examples. The agent calls this **before writing code** whenever it is unsure of a method name, argument structure, or return type.

\| Argument | Type | Description | | --- | --- | --- | | `query` | string | Natural-language question or method name to look up | | `language` | string | Target language, e.g. `"typescript"` |

### `execute`

Runs TypeScript in a sandboxed environment with a pre-authenticated `@flora-ai/flora` client. The agent defines a function `async function run(client) { ... }` and the server invokes it, returning whatever the function returns plus any `console.log` output.

**Constraints:**

- Variables and imported state do **not** persist between `execute` calls — each call is isolated.
- Individual HTTP requests inside the sandbox time out at **30 seconds**.
- Total code execution times out at approximately **5 minutes**.

---

## SDK surface reference

The sections below describe every `client.*` namespace available inside `execute`, grouped by resource.

### Techniques

The agent uses these methods to discover Techniques and create Technique runs.

```
// List all techniques (supports async iteration)
const { techniques } = await client.techniques.list({ query: "thumbnail" });


// Inspect a specific technique's inputs, outputs, and cost
const technique = await client.techniques.retrieve("tech_...");
// → { technique_id, name, description, inputs[], outputs[], run_cost }


// Create a technique run
const run = await client.techniques.runs.create("tech_...", {
  mode: "async",
  inputs: [{ id: "image_in", type: "imageUrl", value: "https://..." }],
  callback_url: "https://yourserver.com/webhook", // optional
});
// → { run_id, status, progress, outputs? }


// List past technique runs (newest first, paginated; supports async iteration)
const { runs } = await client.techniques.runs.list({
  workspace_id: "ws_...",
  status: "completed",
  limit: 20,
});


// Poll a technique run
const status = await client.techniques.runs.retrieve("run_...", {
  techniqueId: "tech_...",
});
// → { status: 'pending'|'running'|'completed'|'failed', progress,
//     outputs: [{ output_id, type, url }], error_code?, error_message? }
```

→ **[API Reference: Techniques](/api/techniques/index.md)**

### Generations

For one-off model generations that don’t require a saved Technique, the agent calls `client.generations.create`. This is the preferred path for plain image, video, audio, or text generation.

```
// Create a generation
const run = await client.generations.create({
  type: "image",
  prompt: "a fox in the snow",
  workspace_id: "ws_...",
  project_id: "prj_...",
  model: "model_id_from_list", // optional
  params: { width: 1024, height: 768 }, // optional, model-specific
});
// → { run_id, type, charged_cost, estimated_seconds, model?, project_id? }


// List past generations (newest first, paginated; supports async iteration)
for await (const gen of client.generations.list({ workspace_id: "ws_..." })) {
  console.log(gen.run_id, gen.status);
}
```

→ **[API Reference: Generations](/api/generations/index.md)**

### Assets

Uploading local files requires an agent with shell/filesystem access (Claude Code, Cursor, Codex, Devin, etc.) so it can run `curl` to POST file bytes to the signed upload URL. Agents without terminal access (e.g. Claude.ai web, ChatGPT) can only attach files that already live at an HTTPS URL.

For workflows that need user-supplied images or videos, the agent follows a 3-step signed-upload flow: create an asset slot → upload bytes via the signed URL → mark it complete. The resulting asset URL can then be passed as a Technique input.

```
// Step 1: create a signed upload slot
const asset = await client.assets.create(/* see search_docs for full args */);


// Step 2: upload bytes via the signed URL (the agent uses curl or fetch)


// Step 3: mark the upload complete
await client.assets.complete(asset.asset_id);


// Retry if the signed URL expired
await client.assets.retry(asset.asset_id);


// List assets
const { assets } = await client.assets.list({ workspace_id: "ws_..." });


// Retrieve a specific asset
const a = await client.assets.retrieve("asset_...");
```

→ **[API Reference: Assets](/api/assets/index.md)**

### Projects, Canvas, and Actions

Projects organize runs and assets inside a workspace. The canvas and actions methods let the agent read and modify a project’s node graph.

```
// List and create projects
const { projects } = await client.projects.list({ workspace_id: "ws_..." });
const project = await client.projects.create({ name: "My Campaign", workspace_id: "ws_..." });


// Retrieve a project and its nodes
const p = await client.projects.retrieve("prj_...");
for await (const node of client.projects.listNodes("prj_...")) { /* ... */ }


// Attach an asset to a project canvas
await client.projects.assets.attachAsset(/* see search_docs for exact args */);


// Retrieve the canvas topology as a Mermaid flowchart
const canvas = await client.projects.canvas.retrieve("prj_...");


// Apply a Mermaid patch to add or connect nodes
await client.projects.canvas.update("prj_...", {
  diagram: "...", // Mermaid diff
  node_params: { /* optional per-node param overrides */ },
});


// Add a prebuilt action node from a raw action slug
await client.projects.actions.create("prj_...", {
  action_id: "rotate-image",
  params: { /* optional */ },
});


// Run an existing canvas action node
await client.projects.actions.run("prj_...", "node_...");
```

The `canvas` and `actions` methods are newer additions. Call `search_docs` first to get the exact argument shapes before writing code against them.

→ **[API Reference: Projects](/api/projects/index.md)**

### Workspaces

```
const { workspaces } = await client.workspaces.list();
// → [{ workspace_id, name, role, created_at }]
```

The agent typically calls this first after OAuth, or when the user has access to multiple workspaces and needs to resolve the right `workspace_id`.

→ **[API Reference: Workspaces](/api/workspaces/index.md)**

### Models

For generation workflows that accept a `model` parameter, the agent lists models to discover available IDs and their parameter schemas.

```
const { models } = await client.models.list({ type: "image" }); // type optional
// → [{ model_id, name, provider, type, estimated_credits, estimated_seconds,
//      params: [{ name, required, type, default, min, max, options }] }]
```

→ **[API Reference: Models](/api/models/index.md)**

### Feedback

```
await client.feedback.record({ /* ... */ });
```

The agent calls this when the user wants to send feedback to the FLORA team — e.g. *“tell FLORA the MCP keeps disconnecting”*, *“send feedback that I’d love a Technique for X”*, *“let FLORA know this worked great”*.

→ **[API Reference: Feedback](/api/feedback/index.md)**

---

## How the agent picks tools

You don’t call tools directly. You describe what you want, and the agent handles the sequence. For example, *“Run the Thumbnail Technique on this image”* typically resolves to:

1. **`search_docs`** — look up `client.techniques.list` and `client.techniques.runs.create` parameter shapes.
2. **`execute`** — a single function that lists Techniques (filtering by name), retrieves the matching one to confirm its inputs, creates a run, and polls until complete:

```
async function run(client) {
  // 1. Find the technique
  const { techniques } = await client.techniques.list({ query: "thumbnail" });
  const tech = techniques[0];
  console.log("Using technique:", tech.technique_id, tech.name);


  // 2. Create a run
  const run = await client.techniques.runs.create(tech.technique_id, {
    mode: "async",
    inputs: [{ id: "image_in", type: "imageUrl", value: "https://example.com/photo.jpg" }],
  });
  console.log("Run created:", run.run_id);


  // 3. Poll until complete
  let result;
  do {
    await new Promise((r) => setTimeout(r, 3000));
    result = await client.techniques.runs.retrieve(run.run_id, {
      techniqueId: tech.technique_id,
    });
    console.log("Status:", result.status, result.progress);
  } while (result.status === "pending" || result.status === "running");


  return result.outputs;
}
```

Different prompts produce different sequences. The [Recipes](/mcp/recipes/discover-and-run/index.md) section walks through several end-to-end examples.

---

## Tool naming in your client

Most clients namespace tools by server. With the new two-tool model you’ll see:

- **Claude Code** (`/mcp` listing): `flora:execute`, `flora:search_docs`
- **Cursor**: `flora.execute`, `flora.search_docs`
- **Other MCP clients**: similar namespacing depending on the client

You almost never need to type these directly — describe what you want and the agent picks the right tool.

---

## Limits and billing

- Calls that create runs (`client.techniques.runs.create(...)`, `client.generations.create(...)`) are billed in USD against your workspace. The cost is shown in `client.techniques.retrieve(...)` under `run_cost` and on the completed run as `charged_cost`.
- Rate limits apply at the workspace level and match the REST API. See the [API Reference](/api/index.md) for current limits.
- A `402 insufficient_credits` error means the workspace balance is too low — top up in FLORA → Settings → Billing.
