> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.eyelevel.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.eyelevel.ai/_mcp/server.

# Connect Hosted GroundX MCP Tools

Connect your agent or app to GroundX through the Model Context Protocol (MCP),
a standard for calling tools from AI clients. Your client must support remote
MCP, and GroundX must expose the operation you need. You can also call GroundX from code through the
[Direct SDK/API Quickstart](/documentation/get-started/direct-sdk-api-quickstart). See
[SDK/REST Fallback](/documentation/agent-harness/verify-and-troubleshoot#sdkrest-fallback)
for connection and tool limitations.

## Setup

### Endpoint

> **Note**
>
> On Claude Code and Codex, [GroundX Agent Harness](/documentation/agent-harness/install-ground-x-agent-harness)
> registers this server for you. Configuring it again attaches the same server twice.

Configure your MCP client to connect to the GroundX MCP endpoint:

```http
https://api.groundx.ai/mcp
```

The same server is also reachable at the equivalent path:

```http
https://api.groundx.ai/api/v1/mcp
```

Either URL works. Use whichever form your client's configuration expects.

### Authentication

GroundX MCP supports two auth paths:

* **OAuth**: for interactive clients that can open a browser (for example Claude
  Desktop or Codex Desktop). Sign in on the GroundX authorization page. The client
  then uses short-lived MCP tokens, without requiring the key again.
* **`X-API-Key` transport**: for headless or non-interactive clients (for example
  Claude Code CLI, Codex CLI, Cursor, Replit, or CI runners). The key is sent as an
  `X-API-Key` HTTP header on the MCP transport connection:

```json
{
  "mcpServers": {
    "groundx": {
      "url": "https://api.groundx.ai/mcp",
      "headers": {
        "X-API-Key": "${GROUNDX_API_KEY}"
      }
    }
  }
}
```

Keep API keys in the connection's HTTP header or OAuth sign-in flow. Never put
them in `call_operation`, `search_content`, or any other tool's arguments.

## Available Tools

### Default Tools

A customer key can access the 12 tools below, subject to its permissions (scopes).
Partner keys may expose additional tools. See [Scope and Visibility](#scope-and-visibility).

| Tool                               | Method | Path                                    | Derived scope    |
| ---------------------------------- | ------ | --------------------------------------- | ---------------- |
| `document_ingestremote`            | POST   | `/v1/ingest/documents/remote`           | `groundx:ingest` |
| `document_getprocessingstatusbyid` | GET    | `/v1/ingest/{processId}`                | `groundx:ingest` |
| `document_list`                    | GET    | `/v1/ingest/documents`                  | `groundx:ingest` |
| `document_get`                     | GET    | `/v1/ingest/document/{documentId}`      | `groundx:ingest` |
| `search_content`                   | POST   | `/v1/search/{id}`                       | `groundx:write`  |
| `search_documents`                 | POST   | `/v1/search/documents`                  | `groundx:write`  |
| `bucket_create`                    | POST   | `/v1/bucket`                            | `groundx:write`  |
| `bucket_list`                      | GET    | `/v1/bucket`                            | `groundx:read`   |
| `group_create`                     | POST   | `/v1/group`                             | `groundx:write`  |
| `group_list`                       | GET    | `/v1/group`                             | `groundx:read`   |
| `group_addbucket`                  | POST   | `/v1/group/{groupId}/bucket/{bucketId}` | `groundx:write`  |
| `health_get`                       | GET    | `/v1/health/{service}`                  | `groundx:read`   |

Always call these tools using the normalized lowercase name shown in the left column
(for example `document_ingestremote`), never a PascalCase `operationId` form.

### Always-Present Tools

In addition to the 12 default tools, 4 tools are always registered regardless of the
session's granted scopes:

* `groundx_account_context`
* `list_operations`
* `describe_operation`
* `call_operation`

Use `list_operations`, `describe_operation`, and `call_operation` to find and run
advanced operations. `groundx_account_context` takes no input and returns the
account type, mode, scopes, base URL, and enabled tool groups.

### Local-File Upload Tool

`document_uploadlocal` requires `groundx:ingest`, as does `document_ingestremote`.
It is separate from the 12 default tools and cannot be called through
`call_operation` by its tool name. Pass `bucketId`, `fileName` and `fileType` to
use the authenticated bucket upload operation. It returns a URL, HTTP method,
`header` map, hosted URL and expiry. The same operation is available through
discovery as `Buckets_fileUpload`.

The MCP host must read the local file and send its bytes by HTTP PUT. A client
that can only call tools cannot complete the upload.

Use the `header` entries as follows:

* `Host`: the S3 upload host; HTTP clients normally set this automatically from
  `url`, so no action is usually needed.
* `GX-HOSTED-URL` (if present): the same value as `hostedUrl`. Use it as
  `sourceUrl` later. Do not send it as an S3 header.
* Any other entries: send them as request headers on the PUT.

See [Local Files](#local-files) below for the full flow.

### Scope And Visibility

Your key's scopes control which tools appear and which operations
`call_operation` can run:

1. If the path contains `/ingest`, the required scope is `groundx:ingest`.
2. Otherwise, if the method is a write verb (POST, PUT, PATCH, or DELETE), the
   required scope is `groundx:write`.
3. Otherwise, the required scope is `groundx:read`.

Both search tools (`search_content`, `search_documents`) use POST, so they require
`groundx:write`.

A session with only `groundx:read` sees three of the default tools:

* `bucket_list`
* `group_list`
* `health_get`

Ingest and write tools, including search, are hidden in a read-only session.
The four always-present tools remain visible, but `call_operation` still rejects
write and ingest calls. `document_uploadlocal` is visible only with `groundx:ingest`.

### Advanced Operations

For bucket or document deletion, workflows, file access, and existing API keys,
find and call operations in this order:

1. **`list_operations({})`**: returns every operation exposed through MCP discovery,
   each with its `operationId`, `method`, `path`, `summary`, and `description`.
2. **`describe_operation({ "operationId": "<id>" })`**: returns the full parameter
   schema (`parameters[]` and `inputSchema`) for one operation, so you can build a
   valid `args` object.
3. **`call_operation({ "operationId": "<id>", "args": { ... } })`**: executes the
   operation and returns the proxied GroundX API result.

```json
call_operation({
  "operationId": "Bucket_delete",
  "args": { "bucketId": 12345 }
})
```

Use **`operationId`** in both `describe_operation` and `call_operation`.
`operation_id` is not accepted.

`call_operation` enforces the same scopes as direct tools. Listing, updating, or
deleting existing API keys also requires `groundx:admin`. Creating API keys is
unavailable through MCP for every scope: it is hidden from `list_operations` and
rejected by `call_operation`.

## Usage Notes

### Ingest And Search Workflow

Create a bucket, ingest documents, wait for processing, then search. For a
walkthrough, see [Use GroundX With Your Agent](/documentation/agent-harness/ingest-search-and-answer-with-an-agent).

### Local Files

Your MCP host must read local files and send HTTP PUT requests to complete this
flow. Otherwise, upload through application code using the SDK/API below.

For public or protected staging, call `document_uploadlocal({ "bucketId": 1234, "fileName": "...", "fileType": "..." })` to get a
pre-signed upload target, PUT the file's bytes to the returned `url` (sending the
required `header` entries; see [Local-File Upload Tool](#local-file-upload-tool)
above for which ones), then call `document_ingestremote` with the returned `hostedUrl`
as `sourceUrl`. This matches how the Python SDK's `client.ingest()` handles local files
internally.

```json
document_uploadlocal({ "bucketId": 1234, "fileName": "invoice", "fileType": "pdf" })
// → {
//     "url": "https://eyelevel-upload.s3.us-west-2.amazonaws.com/...",
//     "method": "PUT",
//     "header": {
//       "Host": ["eyelevel-upload.s3.us-west-2.amazonaws.com"],
//       "Gx-Hosted-Url": ["https://upload.eyelevel.ai/prod/file/ssp/....pdf"]
//     },
//     "hostedUrl": "https://upload.eyelevel.ai/prod/file/ssp/....pdf"
//   }
```

If you're integrating from application code rather than an MCP client, the GroundX SDKs
handle this pre-signed upload flow automatically. See [GroundX SDKs](/sdks/ground-x-sd-ks) and the [in-depth ingest guide](/documentation/guides/ingest-tutorial) for the direct-SDK equivalent.

## File Policies, Private Upload and Sharing

File policies, private uploads, and sharing require a compatible server deployment with file gateway and storage support. Call `groundx_account_context`, then `list_operations`, and inspect each operation with `describe_operation` before using it. Use its API `operationId` through discovery.

| Operation                   | Required scope   | Purpose                                                |
| --------------------------- | ---------------- | ------------------------------------------------------ |
| `Customer_update`           | `groundx:write`  | Update your account policy with its current revision   |
| `Bucket_update`             | `groundx:write`  | Update a bucket policy with its current revision       |
| `Document_update`           | `groundx:ingest` | One document policy update                             |
| `Documents_fileLink`        | `groundx:ingest` | Create an expiring storage link for a saved file asset |
| `Buckets_fileUpload`        | `groundx:write`  | Issue an upload URL for a public or protected bucket   |
| `Document_retryFailedStage` | `groundx:ingest` | Retry an eligible failed callback using saved output   |

Request fields are flattened into `args`, not nested under `body`:

```json
{
  "operationId": "Bucket_update",
  "args": {"bucketId": 1234, "fileAccess": {"mode": "protected"}, "fileAccessRevision": 0}
}
```

Pass this object to `call_operation` after inspecting the schema. Before updating, read the current revision with GET. Send that revision with `fileAccess: null` to clear an override; omit `fileAccess` to leave it unchanged. A document policy update uses the `documents` array with one item containing only the document ID and policy fields. A stale revision returns `409`. If you receive `503`, do not assume protection was applied.

On compatible servers, `bucket_create` accepts initial `fileAccess`, and each `document_ingestremote` item or crawl input can have its own policy. Omit the policy or set it to null to inherit. Creation needs no previous revision, and account or bucket restrictions still apply. For protected local files, including one in a public bucket, discover and call:

```json
{
  "operationId": "Buckets_fileUpload",
  "args": {"bucketId": 1234, "fileName": "invoice.pdf", "fileType": "pdf", "fileAccess": {"mode": "protected"}}
}
```

Include the requested per-file policy in upload issuance and ingest. The API checks it before returning a grant; a disabled deployment returns 403 before bytes can be sent.

The tool returns upload instructions, not an uploaded file. The host must send the bytes to `uploadUrl` using the returned method and required `headers`, without GroundX credentials. Then submit `hostedUrl` through `document_ingestremote` in the same bucket, with the requested policy. If the reservation expires, reserve and upload again. `document_uploadlocal` with `bucketId` uses this same issuer for public and protected files. Calls without `bucketId` retain the legacy anonymous adapter and must not be used for protected files. Both forms use the configured API and storage, including on-prem, without a hosted broker fallback. Upload issuance remains available with read protection disabled. The host must be able to read files and send HTTP requests.

To share a saved page, discover `Documents_fileLink` and call:

```json
{
  "operationId": "Documents_fileLink",
  "args": {"documentId": "11111111-1111-4111-8111-111111111111", "asset": {"kind": "page", "pageNumber": 1}, "expiresInSeconds": 120}
}
```

Recipients can use the returned `url` unchanged until `expiresAt`, without a GroundX key. Refresh expired citations through authorized search or a new link request. To read protected stable URLs or X-Ray `?view=links`, a trusted server must send the owner's `X-API-Key`. MCP OAuth tokens do not authorize these reads. For delegated Partner calls, keep the same selected customer and follow the discovered schema; customer membership checks still apply. See [File Access and Sharing](/documentation/fundamentals/file-access-and-sharing) for inheritance, raw X-Ray, expiry, errors, and on-prem requirements.