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

# Unstructured Transform MCP server installation for Firebase Genkit

> Learn how to connect the Unstructured Transform MCP server to a Firebase Genkit application. Your flows and agents can then point to your files and have Transform start producing partitioned, enriched, chunked, and embedded data based on your files in minutes.

[Firebase Genkit](https://genkit.dev/) is Google's open-source framework for building AI-powered
JavaScript/TypeScript applications. Unlike end-user AI tools that add the Transform MCP server through a settings
screen, Genkit connects to it *from application code*: you create an MCP client and hand its tools to a model call.
Because Transform is a hosted *remote* MCP server, there is nothing to install or run locally. You point the client at
the server URL and authenticate with your Unstructured API key.

Genkit ships the building block that makes this work out of the box, so you do not need a custom transport: the
`@genkit-ai/mcp` package's `createMcpClient` function connects to a remote MCP server over the streamable HTTP
transport, and its `requestInit` setting carries your Unstructured API key as an `Authorization: Bearer` header on
every request, including the initial `initialize` handshake.

## Requirements

Before you begin, you must have the following:

* Node.js 20 or later on your local development machine. To check, in your terminal, run `node -v` or `node --version`. [Install Node.js](https://nodejs.org/en/download).
* An Unstructured API key, which the Transform MCP server uses as a bearer token. [Get an API key](/transform/code#get-your-unstructured-api-key-and-url).
* A Gemini API key for the model that drives the tools. [Get an API key](https://aistudio.google.com/apikey).

## Install the packages

In your terminal, install Genkit, the MCP plugin, and the Google GenAI model plugin:

```bash theme={null}
npm install genkit @genkit-ai/mcp @genkit-ai/google-genai
```

<Note>
  Genkit is in active development and its APIs change between releases. This guide was verified against
  `@genkit-ai/mcp` version 1.39.0. If you install a different version, check the
  [Genkit release notes](https://github.com/firebase/genkit/releases) for changes.
</Note>

## Connect to the Transform MCP server

Store your API keys in environment variables rather than hard-coding them:

```bash theme={null}
export UNSTRUCTURED_API_KEY="<your-unstructured-api-key>"
export GEMINI_API_KEY="<your-gemini-api-key>"
```

In your application code, create an MCP client for the Transform MCP server. The server connection settings go inside
the `mcpServer` object, and the `requestInit` headers attach the `Authorization: Bearer` header to every request, so
the handshake and the tool calls are both authenticated:

```typescript theme={null}
import { createMcpClient } from "@genkit-ai/mcp";

const transformClient = createMcpClient({
  name: "unstructured_transform",
  mcpServer: {
    url: "https://mcp.transform.unstructured.io",
    requestInit: {
      headers: {
        Authorization: `Bearer ${process.env.UNSTRUCTURED_API_KEY}`,
      },
    },
  },
});
```

<Warning>
  Use the server URL exactly as shown. Do not add `/mcp` or `/sse` to the end of the URL.

  Also, the server connection settings must be nested inside the `mcpServer` object as shown. Passing `url` at the
  top level of the `createMcpClient` options throws `TypeError: Cannot read properties of undefined (reading
      'disabled')` in version 1.39.0.
</Warning>

## Understand the transform job lifecycle

Transforming a document is an asynchronous, multi-step flow. Four of the steps are MCP tool calls, and two are plain
HTTP transfers that are *not* MCP calls:

1. `request_file_upload_url`: Returns a pre-signed `upload_url` and a `file_ref` for a local file.
2. An HTTP `PUT` of the raw file bytes to the pre-signed `upload_url`. This is not an MCP call.
3. `transform_files`: Starts a transform job for one or more `file_ref` values (or public HTTP(S) URLs) and returns a `job_id`.
4. `check_transform_status`: Reports whether the job is `SCHEDULED`, `IN_PROGRESS`, or `COMPLETED`.
5. `get_transform_results`: Returns a pre-signed `download_url` for the Markdown output of each transformed file.
6. An HTTP `GET` of the Markdown from the pre-signed `download_url`. This is not an MCP call.

An agent cannot perform the two raw HTTP transfers through MCP tools alone, and an unpaced polling loop wastes model
calls. Define a small `wait_seconds` tool alongside the MCP tools so the model can pause between status checks.

<Note>
  The pre-signed `upload_url` and `download_url` carry their own credentials in the URL itself. The `PUT` and `GET`
  must not send the `Authorization` header, or the storage service rejects them.
</Note>

## Build the application

The following complete example gives Gemini the Transform tools plus a `wait_seconds` pacing tool, then asks it to
parse a PDF from a public URL. Save it as `index.mjs`:

```typescript theme={null}
import { setTimeout as sleep } from "node:timers/promises";

import { googleAI } from "@genkit-ai/google-genai";
import { createMcpClient } from "@genkit-ai/mcp";
import { genkit, z } from "genkit";

const ai = genkit({ plugins: [googleAI()] });

const transformClient = createMcpClient({
  name: "unstructured_transform",
  mcpServer: {
    url: "https://mcp.transform.unstructured.io", // root URL - do not append /mcp
    requestInit: {
      headers: {
        Authorization: `Bearer ${process.env.UNSTRUCTURED_API_KEY}`,
      },
    },
  },
});

const waitSeconds = ai.defineTool(
  {
    name: "wait_seconds",
    description:
      "Pause before the next status check. Transform jobs take 30 seconds to a few " +
      "minutes; call this between check_transform_status calls instead of polling " +
      "in a tight loop. Use 30 seconds unless told otherwise.",
    inputSchema: z.object({ seconds: z.number().int().min(1).max(120) }),
    outputSchema: z.object({ waitedSeconds: z.number() }),
  },
  async ({ seconds }) => {
    await sleep(seconds * 1000);
    return { waitedSeconds: seconds };
  },
);

await transformClient.ready();
const transformTools = await transformClient.getActiveTools(ai);

const { text } = await ai.generate({
  model: googleAI.model("gemini-3.1-flash-lite"),
  system:
    "You parse documents with the Unstructured Transform MCP server. Pass public " +
    "https:// file URLs straight to transform_files. It returns a job_id; poll with " +
    "check_transform_status, calling wait_seconds(30) between checks - jobs take 30 " +
    "seconds to a few minutes. When the job completes, call get_transform_results " +
    "and report the parsed content back to the user.",
  prompt:
    "Parse this PDF with Unstructured Transform: https://arxiv.org/pdf/1706.03762 " +
    "When it completes, tell me the document title and the first three section " +
    "headings from the parsed output.",
  tools: [...transformTools, waitSeconds],
  maxTurns: 20,
});

console.log(text);
await transformClient.disable();
```

<Note>
  On the Gemini API free tier, some models allow as few as 5 requests per minute, and the model spends one request
  per step of the workflow. The `wait_seconds(30)` pacing in the system prompt keeps a polling loop from hitting
  that limit; if you see `429 RESOURCE_EXHAUSTED` or transient `503` errors, increase the wait, retry later, or
  choose a different model from the [Gemini model list](https://ai.google.dev/gemini-api/docs/models).
</Note>

## Run the application

From the directory that contains `index.mjs`:

```bash theme={null}
node index.mjs
```

The model starts the transform job, polls at a measured pace with `wait_seconds`, fetches the results, and prints its
answer. A successful run ends with output like this:

```text theme={null}
The PDF (Attention Is All You Need) has been parsed successfully.

*   Document Title: Attention Is All You Need
*   First Three Section Headings:
    1.  1 Introduction
    2.  2 Background
    3.  3 Model Architecture
```

## Next steps

* [Control Transform file parsing output](/transform/output): Control how the Unstructured Transform MCP server instructs Transform to partition, enrich, chunk, and embed the data based on your files.
* [Control Transform generated sample code](/transform/code): Control how the Unstructured Transform MCP server generates sample curl or Python code that demonstrates how to use Transform to partition, enrich, chunk, and embed the data based on your files.

## Questions? Need help?

* For technical support, [request support](/support/request).
