The Vercel AI SDK is an open-source TypeScript toolkit for building AI applications and agents.
Unlike end-user AI tools that add the Transform MCP server through a settings screen, the AI SDK connects to it from
code: you load the Transform MCP server’s tools through the SDK’s built-in MCP client and hand them to a model call
such as generateText or streamText. 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.
If you want a running app rather than a script, deploy the ready-made
Transform MCP × Vercel AI SDK template. It is a
Next.js chat app wired to the Transform MCP server, with a one-click Deploy to Vercel button that prompts for the
two API keys below.
Requirements
You will need:
- Node.js 18 or later on your local development machine. To check, in your terminal, run
node --version. Install Node.js.
- An Unstructured API key, which the Transform MCP server uses as a bearer token. Get an API key.
- An Anthropic API key, or another model provider that the AI SDK supports, for the agent’s underlying chat model.
Install the packages
In your terminal, install the AI SDK, the Anthropic provider, the AI SDK MCP client, and zod for the local tool
schema. tsx runs the TypeScript example directly:
This guide was verified against ai@7, @ai-sdk/anthropic@4, and @ai-sdk/mcp@2. Newer versions typically work, but
check the AI SDK release notes if an API has changed.
The Transform MCP server speaks the streamable HTTP transport and authenticates with your Unstructured API key sent as
a bearer token. Store your key in an environment variable rather than hard-coding it:
Create an MCP client with the http transport, then load the server’s tools with mcpClient.tools():
Always close the client with await mcpClient.close() when the request finishes (use a finally block, or
streamText’s onFinish callback) so the connection is released.
Transform’s job lifecycle needs two things the MCP tools do not cover on their own. First, transforms run as async
jobs, so the agent must pace its status polling; without a pause it will call check_job_status many times in
a row and exhaust its step budget before the job finishes. Second, get_job_results returns a pre-signed
download_url rather than the parsed text inline, so retrieving the content is a plain HTTP GET. The example below
registers two small local tools alongside the MCP tools:
wait: Pauses between status checks so a multi-second transform has time to complete.
downloadText: Fetches the finished Markdown from the pre-signed download_url with an HTTP GET.
Pre-signed URLs carry their own credentials in the URL itself. The downloadText tool must not send the
Authorization header, or the storage service rejects the request. It also restricts downloads to the
Transform host, so a crafted prompt cannot turn the tool into a server-side request forgery (SSRF) vector.
The following example connects to the Transform MCP server, registers the two helper tools, and lets the model drive
the full job lifecycle: start the transform, poll for status with paced waits, fetch the results, and download the
Markdown output. Save it as transform-agent.ts:
To use a different model provider, swap anthropic('claude-opus-4-8') for any
provider the AI SDK supports, and set that provider’s API key.
Parse your source files
Parsing requests have the following limits:
- Each file must be of a supported file type.
- Each file must be 50 MB or less in size.
- Each request must have 10 files or fewer.
- Only 5 requests can be running at a time.
The Transform MCP server is designed to report these limits back to the agent through its tool responses. Because of
this, your agent should notify you whenever it encounters a file that exceeds 50 MB in size, and it should formulate
strategies to send requests that are 10 files or fewer and not cause more than 5 requests to be running at a time. You
can reinforce this behavior in the system prompt, as the example above does for the polling sequence.
Run the agent
Set your model provider’s key, then run the example. Transforms take from about 10 seconds to several minutes,
depending on page count:
The agent works through the tool sequence — start_transform_job, paced wait and check_job_status cycles,
get_job_results, and downloadText — then prints a summary of the parsed Markdown.
Transform can also pull specific fields out of a document and return them as JSON matching a schema, rather than
converting the whole document. Two MCP tools cover this:
suggest_extraction_schema_for_file: Drafts a JSON Schema from one parsed document, for when you do not have a
schema yet.
start_extraction_job: Runs the extraction against a schema and returns a job_id.
Both tools read the element JSON that a parse produces, not the raw file, so an extraction always follows a
transform job. Every file entry that get_job_results returns carries a durable output_ref (a u10d://output/...
value) alongside its download_url. That output_ref is the input to the extraction tools, and it is present
whichever output format you rendered, so the agent does not need to download the parsed output before extracting.
Extraction reuses check_job_status and get_job_results, so it needs no new helper tools. The downloadText
helper is not used here: extraction results are returned inline rather than behind a pre-signed URL.
Point the system prompt at the sequence:
One schema applies to every reference in a single start_extraction_job call, so batch only documents of the same
kind. The transform limits carry over: up to 10 references per call, and 5 active jobs at a time.
Extraction can only surface what the parse captured, so parse quality sets the ceiling. For images, PowerPoint, and
PDFs, start with strategy: "vlm". If a result comes back sparse, re-parse with strategy: "hi_res" plus the
image_description, generative_ocr, and table_to_html enrichments, then extract from the new output_ref. For
prompt patterns, see Structured data extraction.
Troubleshooting
401 Unauthorized or an invalid_token error on connect. Confirm the UNSTRUCTURED_API_KEY environment
variable is set and that the Authorization header is formatted as Bearer <your-unstructured-api-key>.
404 or a not-found error when connecting. Verify the server URL is exactly
https://mcp.transform.unstructured.io, with no path such as /mcp appended.
- The agent stops before the job finishes. Each model step counts toward
stopWhen: stepCountIs(...), and each
poll cycle uses two steps (wait plus check_job_status). Raise the step count, or increase the seconds the
wait tool pauses, for longer transforms. An extraction runs a second job after the parse, so a parse-then-extract
prompt needs roughly twice the step budget of a parse alone.
- An extraction is rejected as invalid input. The extraction tools accept the
output_ref from a completed
transform job, not a file URL and not a file_ref. Parse the document first, then pass its output_ref in
element_json_refs. Element JSON that carries embeddings is also rejected, so extract from parse or chunk output
rather than the output of an embed stage.
- An extraction returns empty or mostly null fields. This is usually the parse rather than the schema. Re-parse
the file at higher fidelity, as described in Extract structured data, and extract from
the new
output_ref.
- The download request is rejected. The
download_url value is pre-signed. Send that request without the
Authorization header.
- A hanging or leaked connection. Call
await mcpClient.close() when the request finishes, in a finally block or
streamText’s onFinish callback.
Next steps
Questions? Need help?