Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ or plain text.
- If the server rejects a file format, say so and list the file. Do not
convert files to another format to force them through unless the user
asks.
- On an auth error, tell the user to re-authenticate with
`/mcp auth transform`. Do not try to work around it.
- On an auth error, tell the user to re-authenticate with their MCP
client (for the Gemini CLI extension, restarting the session re-runs
the browser sign-in). Do not try to work around it.

## Boundaries

Expand Down
24 changes: 24 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,30 @@ requests are reviewed by Unstructured maintainers.
pull request.
- Run `./scripts/validate.sh` before opening a pull request.

## Transport

The manifest launches the server through `npx -y mcp-remote <url>` rather
than pointing Gemini CLI's native `httpUrl` remote transport at the
server directly. The Transform server authenticates with OAuth via
Dynamic Client Registration, and Gemini CLI's native remote-OAuth path
does not attach the acquired token on the request that follows sign-in
for DCR / auto-discovered servers, so the connection fails to establish
([google-gemini/gemini-cli#27745](https://github.com/google-gemini/gemini-cli/issues/27745)).
`mcp-remote` performs the OAuth flow correctly and caches the token, so
sign-in is a one-time browser step. The cost is a Node.js 18+ / `npx`
runtime requirement for users.

When the upstream bug is fixed and released, this can move back to the
simpler native transport:

```json
"transform": { "httpUrl": "https://mcp.transform.unstructured.io" }
```

That change also needs `scripts/validate.sh` reverted to read the URL
from `.mcpServers.transform.httpUrl` and the README install steps updated
back to `/mcp auth transform`.

## Shipping updates

This extension is installed from its GitHub URL
Expand Down
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,16 @@ manifest and the agent guidance the extension ships.
gemini extensions install https://github.com/Unstructured-IO/transform-gemini-extension
```

Then sign in once with `/mcp auth transform` (browser OAuth; no API key
needed). The extension registers the `transform` server and ships the
agent guidance in [`AGENTS.md`](AGENTS.md).
The first time the `transform` server starts, a browser window opens for
a one-time Unstructured sign-in (OAuth; no API key needed). The token is
cached, so you only sign in once. The extension ships the agent guidance
in [`AGENTS.md`](AGENTS.md).

The server is launched through [`mcp-remote`](https://www.npmjs.com/package/mcp-remote),
so you need Node.js 18+ with `npx` on your PATH. `mcp-remote` is fetched
on first use. It handles the OAuth flow that Gemini CLI's native remote
transport does not yet complete reliably; see
[CONTRIBUTING.md](CONTRIBUTING.md#transport) for the detail.

Using another tool (Claude Code, Claude Desktop, Cursor, Codex, Google
Antigravity, Cline)? See the
Expand Down
5 changes: 3 additions & 2 deletions gemini-extension.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
{
"name": "unstructured-transform",
"version": "0.1.0",
"version": "0.2.0",
"description": "Parse documents (PDF, DOCX, PPTX, XLSX, HTML, EML, images, and multiple other formats) into markdown, element JSON, HTML, or plain text with the Unstructured Transform MCP server.",
"contextFileName": "AGENTS.md",
"mcpServers": {
"transform": {
"httpUrl": "https://mcp.transform.unstructured.io"
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.transform.unstructured.io"]
}
}
}
15 changes: 8 additions & 7 deletions scripts/validate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,17 @@ else
echo "SKIP: no JSON validator found for gemini-extension.json (install jq)" >&2
fi

# Extract the canonical server URL from the manifest. Parse the JSON
# where a parser is available; only fall back to text scanning when
# neither jq nor python3 is present.
# Extract the canonical server URL from the manifest. The server is
# launched through `npx mcp-remote <url>`, so the URL is the https entry
# in the transform server's args. Parse the JSON where a parser is
# available; only fall back to text scanning when neither jq nor python3
# is present.
if command -v jq >/dev/null 2>&1; then
canonical=$(jq -r '.mcpServers.transform.httpUrl // empty' gemini-extension.json 2>/dev/null || true)
canonical=$(jq -r '.mcpServers.transform.args[]? | select(startswith("https://"))' gemini-extension.json 2>/dev/null | head -1 || true)
elif have_python; then
canonical=$(python3 -c 'import json; print(json.load(open("gemini-extension.json")).get("mcpServers", {}).get("transform", {}).get("httpUrl", ""))' 2>/dev/null || true)
canonical=$(python3 -c 'import json; args = json.load(open("gemini-extension.json")).get("mcpServers", {}).get("transform", {}).get("args", []); print(next((a for a in args if isinstance(a, str) and a.startswith("https://")), ""))' 2>/dev/null || true)
else
canonical=$(grep -oE '"httpUrl"[[:space:]]*:[[:space:]]*"https://[^"]+"' gemini-extension.json \
| grep -oE 'https://[^"]+' | head -1 || true)
canonical=$(grep -oE 'https://mcp\.[A-Za-z0-9./-]*[A-Za-z0-9/-]' gemini-extension.json | head -1 || true)
fi

if [ -z "$canonical" ]; then
Expand Down
Loading