> ## 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 PraisonAI

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

[PraisonAI](https://docs.praison.ai) is an open-source framework for building multi-agent AI systems in a few lines
of Python. Like other agent frameworks, it connects to the Transform MCP server *from agent code*: you declare the
server as an MCP client and hand its tools to an agent. 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.

PraisonAI's `MCP` class connects to a remote server over streamable HTTP and carries your Unstructured API key as an
`Authorization: Bearer` header on every request, including the initial handshake.

## Requirements

Before you begin, you must have the following:

* Python 3.10 or later on your local development machine. To check, in your terminal, run `python --version` or `python3 --version`. [Install Python](https://www.python.org/downloads/).
* `praisonaiagents` 1.6.154 or later. Two fixes matter here: 1.6.152 added the remote streamable-HTTP MCP fix, without which PraisonAI cannot connect to a remote MCP server at all, and 1.6.154 made the agent's loop guard result-aware. Before 1.6.154, the loop guard counted status polls as "no progress" and halted a transform after eight tool calls, so a multi-minute job never reached an answer. See the [PraisonAI releases](https://pypi.org/project/praisonaiagents/).
* 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).
* An API key for the agent's underlying model, for example an OpenAI API key.

## Install the packages

In your terminal, install PraisonAI with the `mcp` extra:

```bash theme={null}
pip install "praisonaiagents[mcp]"
```

## Connect to the Transform MCP server

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

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

In your agent code, declare the Transform MCP server with the `MCP` class and hand it to an agent. The `headers`
setting attaches the `Authorization: Bearer` header to every request, so the handshake and the tool calls are both
authenticated.

Transforms run as asynchronous jobs that take from about 30 seconds to a few minutes, and two settings keep the agent
from giving up before a job finishes. Both are explained under [Pace the polling loop](#pace-the-polling-loop) below:

```python theme={null}
import os
import time

from praisonaiagents import Agent, MCP
from praisonaiagents.config.feature_configs import ExecutionConfig

TRANSFORM_MCP_URL = "https://mcp.transform.unstructured.io"  # root URL - do not append /mcp


def wait_seconds(seconds: int) -> str:
    """Pause before the next transform status check. Use 30 seconds unless told otherwise."""
    seconds = max(1, min(int(seconds), 120))
    time.sleep(seconds)
    return f"Waited {seconds} seconds."


transform_tools = MCP(
    TRANSFORM_MCP_URL,
    headers={"Authorization": f"Bearer {os.environ['UNSTRUCTURED_API_KEY']}"},
)

transform_agent = Agent(
    instructions=(
        "You parse documents into structured, AI-ready data with the Unstructured Transform tools. "
        "Turn PDFs, Office files, images, and other documents into clean Markdown, then answer "
        "questions about the content. Transforms are ASYNC and take 30 seconds to a few minutes. "
        "After start_transform_job returns a job_id, ALWAYS call wait_seconds(30) BEFORE each "
        "check_job_status call. Never call check_job_status twice in a row without waiting in "
        "between. Keep waiting and checking until the status is COMPLETED, then call "
        "get_job_results and answer from the parsed content."
    ),
    model="gpt-4o-mini",
    execution=ExecutionConfig(max_tool_calls_per_turn=100),
    tools=[*transform_tools, wait_seconds],
)
```

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

### Pace the polling loop

The two additions above are what make a multi-minute transform complete. Without them the agent connects and calls
the tools, but never reaches an answer:

* **`wait_seconds`, passed alongside the MCP tools.** PraisonAI has no built-in pacing, so an agent left to itself
  polls `check_job_status` every couple of seconds and then concludes the job is taking too long and stops, while
  the transform is still running. Unpacking the MCP tools with `*transform_tools` lets you add this local function
  to the same list. The instruction to call it between status checks matters as much as the tool itself.
* **`ExecutionConfig(max_tool_calls_per_turn=100)`.** PraisonAI caps a turn at 10 tool calls by default, which a
  paced polling loop passes well before a job finishes. The cap then ends the turn with "Tool call limit reached
  (10 calls)" rather than an answer.

## Run the agent

Ask the agent to parse a document and answer a question about it:

```python theme={null}
transform_agent.start(
    "Parse https://arxiv.org/pdf/1706.03762 to Markdown and list the section headings."
)
```

Transforming a document is asynchronous: the agent starts a job with `start_transform_job`, waits with
`wait_seconds`, polls `check_job_status` until it is complete, then retrieves the output with `get_job_results`.
Large or scanned documents can take a few minutes. The Transform tools the agent uses for this flow are
`request_file_upload_url`, `start_transform_job`, `check_job_status`, and `get_job_results`, alongside the local
`wait_seconds` function.

## Extract structured data

To pull specific fields out of a document rather than convert the whole document, ask the agent for an extraction:

```python theme={null}
transform_agent.start(
    "Extract each plant's name, light needs, watering instructions, and humidity level from "
    "https://docs.unstructured.io/img/pipelines/data-extractor/house-plant-care.png as JSON."
)
```

The agent parses the file first, then extracts from the parsed element JSON using
`suggest_extraction_schema_for_file` (when you have not supplied a schema) and `start_extraction_job`, polling with the
same `check_job_status` and `get_job_results` tools. Extraction runs on the element JSON that a parse produces rather
than on the raw file, so it always follows a transform job, and chaining the two takes longer than a parse alone.
Results arrive as JSON matching the schema, wrapped with the source filename and the element JSON reference they were
taken from.

Extraction can only surface what the parse captured, so ask for a higher-fidelity parse if a first attempt comes back
sparse. For prompt patterns, see [Structured data extraction](/transform/sde).

## 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 structured data extraction](/transform/sde): Control how the Unstructured Transform MCP server extracts and formats structured data from 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 general questions about Unstructured products and pricing, email Unstructured Sales at [sales@unstructured.io](mailto:sales@unstructured.io).
* For technical support, [request support](/support/request).
