@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 -vornode --version. Install Node.js. - An Unstructured API key, which the Transform MCP server uses as a bearer token. Get an API key.
- A Gemini API key for the model that drives the tools. Get an API key.
Install the packages
In your terminal, install Genkit, the MCP plugin, and the Google GenAI model plugin: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 for changes.Connect to the Transform MCP server
Store your API keys in environment variables rather than hard-coding them:mcpServer object, and the requestInit headers attach the Authorization: Bearer header to every request, so
the handshake and the tool calls are both authenticated:
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:request_file_upload_url: Returns a pre-signedupload_urland afile_reffor a local file.- An HTTP
PUTof the raw file bytes to the pre-signedupload_url. This is not an MCP call. start_transform_job: Starts a transform job for one or morefile_refvalues (or public HTTP(S) URLs) and returns ajob_id.check_job_status: Reports whether the job isSCHEDULED,IN_PROGRESS, orCOMPLETED.get_job_results: Returns a pre-signeddownload_urlfor the Markdown output of each transformed file.- An HTTP
GETof the Markdown from the pre-signeddownload_url. This is not an MCP call.
output_ref that get_job_results returns for each file:
suggest_extraction_schema_for_file: Drafts a JSON Schema from one parsed document. Use this only when you do not already have a schema.start_extraction_job: Starts an extraction for up to 10output_refvalues against a single JSON Schema, and returns ajob_id.
check_job_status and read with get_job_results, exactly as a transform job is.
Its results come back inline rather than behind a download_url, so there is no equivalent of the final HTTP GET.
Each result is wrapped with the source filename, file type, timestamp, and the element JSON reference it was taken
from. For prompt patterns, see Structured data extraction.
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.
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.Build the application
The following complete example gives Gemini the Transform tools plus await_seconds pacing tool, then asks it to
parse a PDF from a public URL. Save it as index.mjs:
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.Run the application
From the directory that containsindex.mjs:
wait_seconds, fetches the results, and prints its
answer. A successful run ends with output like this:
Extract structured data
To return named fields as JSON rather than the whole document as text, use the server’s two extraction tools.getActiveTools already loads them, so only the system prompt and the request change:
maxTurns. An extraction runs a second job after the parse, so it needs roughly twice the polling
turns of a parse alone.
Each result is wrapped with the source filename, file type, timestamp, and the element JSON reference it was taken
from, alongside the extracted data. Keep that wrapper when you persist results, since it is what ties each record
back to its document.
Next steps
- Control Transform file parsing 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: Control how the Unstructured Transform MCP server extracts and formats structured data from your files.
- Control Transform generated sample 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.

