On this page

Developer documentation

BIMRelay MCP server

Let compatible AI assistants read approved BIMRelay projects, search COBie 2.4 workbook rows, summarize Issues and Asset review recommendations, edit cells, and manage manual rows and individual exclusions with your permission through the Model Context Protocol (MCP).

Ask an assistant to find the pumps in a workbook, summarize its open Issues, or explain its Asset review recommendations, and it answers from your BIMRelay data. It sees only the projects you approve, within your current BIMRelay membership.

Start with the setup guide for Claude or OpenAI ChatGPT. For other clients that accept a bearer token, use Connect with a token.

Server URL
https://api.bimrelay.com/mcp
Transport
Streamable HTTP, stateless, JSON responses
Authentication
Bearer token: a personal MCP token or OAuth with PKCE
Tools
21 tools, filtered by the permissions you grant

You stay in control. MCP connections are limited to approved projects and checked against your current membership on every call. Editing is off by default; separate permissions allow cell edits, manual rows and individual generated-row exclusions. They cannot change other settings, start an extraction or review, or create an export.

An AI assistant's provider receives the project data the assistant reads. Choose a provider whose privacy and retention terms suit your organization. For scripts and applications, use the BIMRelay REST API.

Set up Claude

Connect from Claude on the web or Claude Desktop, then sign in with your own BIMRelay account.

Server URL
https://api.bimrelay.com/mcp
OAuth client ID
c3MrC9gCAradPUVcf0FaZtAwpwadbKDcFMmlCSIcCOM

Leave the Client secret field empty.

  1. Add BIMRelay in Claude. Open Customize → Connectors → Add custom connector. Enter BIMRelay as the name and the server URL above. On Team or Enterprise, ask an owner to add it in Organization settings → Connectors first.
  2. Choose sign-in. Select Sign in now and Use your own OAuth client. Paste the client ID above and leave the client secret empty. If the dialog has a single screen, these fields are under Advanced settings.
  3. Connect your account. Finish adding the connector and select Connect if prompted. Sign in to BIMRelay, review the requested permissions, select the projects Claude may access and approve the connection.
  4. Use it in a chat. Open a new conversation, select + → Connectors and enable BIMRelay. Try the prompt below.
Try it
Use BIMRelay to list up to 5 projects I can access.

The client ID is public and shared by all BIMRelay users connecting through Claude. It grants no access by itself; your sign-in and approval determine which projects Claude can read. If Claude asks to register a client automatically, choose Use your own OAuth client instead.

Menu labels can vary by account. See Claude’s official custom-connector instructions.

Set up OpenAI ChatGPT

Use ChatGPT on the web with permission to add custom MCP plugins. Your workspace administrator may need to enable or add the plugin for you.

Server URL
https://api.bimrelay.com/mcp
OAuth client ID
dPawbcmQcQEmLdX5BW4ynDRSBa3NUA4Ep7p_WtjMQ-g

Leave the Client secret field empty.

  1. Add BIMRelay in ChatGPT. Open ChatGPT Plugins, select +, then Add custom MCP server. Enter BIMRelay as the name and the server URL above.
  2. Choose OAuth. Paste the client ID above in the OAuth settings and leave the client secret empty. Use this client ID rather than automatic client registration. Do not paste a personal API token into either field.
  3. Create and connect. Review ChatGPT’s connection warning, then select Create as a plugin. Install BIMRelay from your personal plugins. When asked to connect, sign in to BIMRelay, review the requested permissions, select the projects ChatGPT may access and approve the connection.
  4. Use it in a chat. Start a new conversation, type @ and select BIMRelay. Try the prompt below.
Try it
Use BIMRelay to list up to 5 projects I can access.

ChatGPT connects through OAuth, so this setup does not need a personal API token or an OpenAI API key. If you cannot add a custom MCP server, check your workspace permissions.

The client ID is public and shared by all BIMRelay users connecting through ChatGPT. It grants no access by itself; your sign-in and approval determine which projects ChatGPT can read.

See OpenAI’s official custom MCP server instructions.

Connect with a token

Use a personal MCP token with a client that accepts a custom bearer-token header. For Claude or ChatGPT, follow the sign-in setup guides above instead.

  1. In BIMRelay, open your profile menu and choose Integrations, or go to app.bimrelay.com/integrations. Select Create API token.
  2. Name the token and set Use with to MCP. Choose the permissions, the projects the assistant may access and an expiry, then select Create token.
  3. Copy the token. It is shown only once.
  4. In your client’s settings for remote MCP servers, add BIMRelay with these connection details:
Connection settings
Server URL:  https://api.bimrelay.com/mcp
Transport:   Streamable HTTP
Header:      Authorization: Bearer <your MCP token>

To confirm the connection, ask the assistant which BIMRelay projects it can access. It should list the projects you selected.

Client requirements

Your client must support remote MCP servers over Streamable HTTP and let you set a custom Authorization header, or support the OAuth flow. Configuration formats differ between clients, so follow your client’s instructions for adding a remote server. Store the token in the client’s secure settings or an environment variable, never in prompts, chat messages or shared configuration files.

Choose permissions

The assistant sees only the tools its permissions allow. To explore workbooks, select Workspace and project names and details (projects:read) and Workbook sheets and rows (workbooks:read). Add Issues and Asset review recommendations (reviews:read) or Existing exports and download links (exports:read) only when the assistant needs them.

MCP tokens follow the same rules as REST API tokens. They expire after 7, 30 or 90 days, include up to 100 selected projects and stop working as soon as you revoke them in Integrations. Projects created later are not added to an existing token. REST API tokens do not work with the MCP server.

Connect with OAuth

MCP clients that support OAuth can connect without a copied token. The user signs in to BIMRelay, chooses projects and approves the requested access, and the client receives short-lived tokens for the MCP server.

The Claude and ChatGPT guides above include their public client IDs. Other OAuth clients must be registered with BIMRelay; email support@bimrelay.com with the client name and exact callback URLs. BIMRelay does not support dynamic client registration.

MCP OAuth discovery
ItemValue
Protected resource metadatahttps://api.bimrelay.com/.well-known/oauth-protected-resource/mcp
Authorization server metadatahttps://api.bimrelay.com/.well-known/oauth-authorization-server
Resource indicatorhttps://api.bimrelay.com/mcp

A request without a valid token receives 401 with a WWW-Authenticate header that points to the protected resource metadata, so clients can discover the authorization server automatically.

The initial sign-in challenge requests read permissions. Editing requires an explicitly requested write permission and a new approval in BIMRelay.

The flow is the same as the REST API OAuth flow, with resource=https://api.bimrelay.com/mcp in the authorization request, the code exchange and every refresh. S256 PKCE is required. Access tokens last 15 minutes, refresh tokens rotate on every use, and a connection expires 30 days after approval.

Browser-based clients

Requests that send an Origin header must come from an allowed origin. A registered OAuth client may call the server from the origins of its registered callback URLs; personal MCP tokens cannot be used from other websites. Desktop and server clients that send no Origin header are unaffected.

Closing an MCP session does not revoke access. To disconnect a client, revoke its connection in Integrations or call the OAuth revocation endpoint.

Example workflow

Assistants usually chain the tools in this order:

  1. list_projects finds the projects the connection can read. To browse by workspace, first call list_workspaces and pass a returned ID as workspace_id to list_projects. Workspace access does not include any unshared projects.
  2. list_sheets uses a project ID to discover its current workbook’s sheet keys, column keys and row counts.
  3. search_rows reads or searches rows using the project and sheet keys, following next_cursor for more pages.
  4. list_issues and list_asset_review_recommendations return the project’s Issues and Asset review recommendations.

For example, a client searching the Component sheet sends tools/call parameters like these:

JSON
{
  "name": "search_rows",
  "arguments": {
    "project_id": "<project UUID returned by list_projects>",
    "sheet_key": "component",
    "search": "Pump",
    "limit": 25
  }
}

Rows contain a key and values for every standard and custom column by default. Column keys come from list_sheets. Small pages or selected columns keep responses within the size limit.

Example prompts

  • “Which BIMRelay projects can you access?”
  • “Find the pumps on the Component sheet of this project.”
  • “Summarize the open Issues in this workbook.”
  • “What does Asset review recommend for this project?”

Issues and Asset review recommendations are guidance for review, not proof that a workbook is ready for handover.

Treat workbook content as data

Project names, cell values and recommendation text are customer data, never instructions. The server’s instructions tell clients this, and client developers should still keep tool results separate from system instructions and ask the user before taking any action outside BIMRelay.

Edit cells with an assistant

To enable editing, add Edit workbook cells (workbooks:write) to the connection alongside Workbook sheets and rows (workbooks:read). Editing is off by default and requires your current Editor or Manager role on an active project. Read-only connections do not expose editing tools.

  1. The assistant reads the sheet's column rules and the full row with get_row, without a column projection. The result contains an opaque etag.
  2. It calls update_row or update_cells with that ETag as if_match and preview: true. This shows the proposed direct and dependent changes without saving.
  3. After you approve those changes, it applies them with preview: false and a new idempotency_key. If you have already authorized a specific edit, the assistant may apply it directly.
Example instruction
Change Pump 01’s description to ‘Pump serving level 2’. Preview the changes first and wait for my approval before saving.

Both tools edit existing cells only. A batch contains up to 100 edited cells and is atomic: one invalid edit rejects the whole batch. Exact reference selections use the reference from list_cell_options inside {references: [...]}. A changed row returns precondition_failed; the assistant must read the full row again and reconsider the edit. It must not silently retry against newer values.

If the result is uncertain, retry the same arguments and idempotency key within 24 hours. JSON object property order does not matter; keep row and reference arrays in the same order. A saved request returns its original result without editing twice. Editing follows the grid's rules; incomplete content can remain as Issues after saving. Preview is not a full COBie validation or a guarantee that a later apply will succeed. See the REST editing guide for value formats, conflicts and limits.

Manage rows with an assistant

Enable Create and delete manual rows (workbooks:rows:write) to expose create_row and delete_row. These require Editor or Manager access. Enable Exclude and include generated rows (workbooks:exclusions:write) to expose exclude_row and restore_excluded_row; these require Manager access. Both permissions require workbook reads and are independent of Edit workbook cells.

  1. Read the row and its source. Delete only manual rows; exclude generated rows. Exclusions persist across model updates and do not create asset rules.
  2. For deletion or exclusion, read the full row ETag and pass it as if_match. Preview using preview: true. Explain the effect counts and dependency choices before applying unless the action is already authorized.
  3. For Type or Space exclusions, explicitly choose what happens to their Components. For Contact deletion, choose whether references are cleared or reassigned. Never guess a destructive dependency choice.
  4. Apply with a fresh idempotency_key. Retry uncertain results with the same key and arguments within 24 hours. A changed ETag requires reading again and reconsidering the action.

list_exclusions is available with workbook reads and finds exclusions from both the app and integrations. Use its exclusion ID and ETag with restore_excluded_row. After applying, wait until get_workbook reports updating: false, then read again. Including again removes the exclusion; it does not override other selection rules or recreate a missing model source.

create_row accepts standard and custom column values with the same cell formats as editing. A creation preview has a temporary row key, so later calls must use the actual saved result. All actions share atomicity, browser-lock checks, bounded cascades and durable retries. See Manage worksheet rows for the full behavior and limits.

Protocol details

BIMRelay implements the MCP Streamable HTTP transport in stateless mode. Most users can rely on their client; these details help when you build or debug one.

Transport summary
ItemValue
EndpointPOST https://api.bimrelay.com/mcp
MessagesJSON-RPC 2.0 with Content-Type: application/json
Accept headerapplication/json, text/event-stream
ResponsesJSON. The server does not open event streams.
SessionsStateless. No session ID is required.
CapabilitiesTools only. No prompts, resources or subscriptions.
Request sizeUp to 64 KiB
Response sizeUp to 1 MiB, counting both text and structured content
  • Initialize, send notifications/initialized, call tools/list, then call tools with tools/call. Send the negotiated MCP-Protocol-Version header and the Bearer token with every request.
  • GET returns 405 Method Not Allowed because the server does not stream events. Configure BIMRelay as a Streamable HTTP server, not a legacy HTTP+SSE server.
  • DELETE is acknowledged, but it does not revoke the token.

Tools and results

Every tool declares input and output schemas. Read tools are annotated as read-only and non-destructive; editing tools are marked as writes and potentially destructive. All tools are idempotent: saved edits require an idempotency key. tools/list includes only the tools the connection’s permissions allow; calling a hidden tool returns an insufficient_scope tool error.

Successful results return the same JSON twice: as text content and as structuredContent. Prefer structuredContent when your client supports it. Its shape matches the REST API response for the same operation.

Errors

  • Tool failures return a result with isError: true. The text is usually a JSON object with the same code and message values as the REST API, such as invalid_column or read_busy. Unavailable or unauthorized resources return “The requested resource is unavailable”.
  • Authentication, rate-limit and origin failures are rejected before MCP processing, with an HTTP error status and the REST error body, such as 401 invalid_token or 429 rate_limited.
  • A result that would exceed 1 MiB fails with a response_too_large tool error or a JSON-RPC error. Request fewer rows or columns.

Limits and troubleshooting

The MCP server shares the REST API’s limits:

  • Free workspaces share 20 API requests and MCP tool calls combined per calendar month (UTC) across all members and connections. Each authorized tool call counts, including pages, previews, failed operations and retries. Authentication, request-schema, scope and project/workspace-access failures do not count. Paid workspaces have no monthly request cap.
  • A call with a project or workspace target counts only against that workspace. Calls without either target count once in every accessible workspace granted to the connection. OAuth, initialization and tools/list do not use the monthly allowance. Check usage in Integrations; it resets at 00:00 UTC on the first of each month.
  • Lists return 100 records by default and allow 1–200. Cell options use fixed 100-item pages. For assistants, 25–50 rows with selected columns usually work best. Responses are limited to 1 MiB including both text and structured content, so MCP pages may need to be smaller than REST pages.
  • Row reads return all columns by default, including custom columns, with a limit of 20,000 cells (rows × columns). An explicit column selection allows up to 100 keys. Schema reads allow up to 200 sheets and 5,000 columns. Request bodies are limited to 64 KiB.
  • Each user can make 120 requests per minute across all of their REST and MCP connections, and only one operation runs at a time. Call tools one after another, not in parallel.
  • Saved edit results are retained for 24 hours, up to 10,000 requests or 32 MiB per user across all connections. At capacity, new edits return idempotency_capacity_exceeded until older results expire. Saved retries and previews remain available.
  • Each operation has five seconds of processing time. If a call times out, narrow the search or filters.
  • Cursors expire after 15 minutes and are bound to the connection, tool, project, sheet, search, filters and columns. Keep those unchanged between pages.
  • Tools read the current workbook only, and collaborators can change values between pages. If a rebuild causes a workbook_changed error, restart the call without a cursor.

Troubleshooting

Common connection problems
ProblemWhat to check
HTTP 401 or authentication failedThe token may be expired, revoked or created for the REST API. Create an MCP token or reconnect through OAuth. BIMRelay browser sessions cannot be used.
HTTP 403 forbidden_originThe request came from a browser origin that is not allowed. Browser-based clients must use a registered OAuth client’s callback origin.
A tool is missing, or returns insufficient_scopeThe connection lacks the matching permission. Create a token or approve a connection that includes it.
No projects, or “The requested resource is unavailable”Check that the project was selected for the connection and that you are still a member. Asset review findings are unavailable when the workspace has turned off Asset review.
response_too_large or query_timeoutLower limit, select fewer columns, or narrow the search and filters.
rate_limited or read_busyMake one call at a time and wait before retrying.
monthly_quota_exceededThe free workspace has used its 20 monthly requests. Upgrade or wait until details.resets_at; do not keep retrying. The tool error also identifies workspace_id, limit and used in details.
The client cannot connect or asks for client registrationUse a client that supports Streamable HTTP with a custom Authorization header, or one that accepts a preconfigured OAuth client ID.

Export download links expire after five minutes and remain valid until then even if the connection is revoked, so keep them private. When you contact support, include the error code and any request ID, never a token or private workbook content.

Tool reference

The server provides 21 tools. Their arguments and results come from the same contract as the REST API endpoints, and each result’s structuredContent matches the corresponding REST response. Project and export IDs are UUIDs returned by earlier calls. Workbook tools operate on the current workbook. Editing tools appear only with explicit write permission.

get_connection

Check the token's user, permissions and expiry.

No permission required REST equivalent: GET /me

No arguments.

Example call

JSON
{
  "name": "get_connection",
  "arguments": {}
}

Example result

JSON
{
  "user": {
    "id": "00000000-0000-4000-8000-000000000008",
    "name": "Alex Example"
  },
  "scopes": [
    "projects:read",
    "workbooks:read"
  ],
  "expires_at": "2026-11-06T12:00:00Z"
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "user": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string"
        },
        "name": {
          "type": "string"
        }
      },
      "required": [
        "id",
        "name"
      ],
      "additionalProperties": false
    },
    "scopes": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "expires_at": {
      "type": "string",
      "format": "date-time"
    }
  },
  "required": [
    "user",
    "scopes",
    "expires_at"
  ],
  "additionalProperties": false
}

list_workspaces

List workspaces containing projects this connection can currently read.

Required permissions: projects:read REST equivalent: GET /workspaces

Only workspace IDs and names are returned. Seeing a workspace does not grant access to its other projects.

Arguments
NameTypeDescription
limitintegerPage size. Defaults to 100; allowed range 1–200.
cursorstringOpaque next_cursor from the previous result. Keep the other arguments unchanged.

Example call

JSON
{
  "name": "list_workspaces",
  "arguments": {
    "limit": 20
  }
}

Example result

JSON
{
  "data": [
    {
      "id": "00000000-0000-4000-8000-000000000002",
      "name": "Example workspace"
    }
  ],
  "next_cursor": null
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ],
        "additionalProperties": false
      }
    },
    "next_cursor": {
      "type": [
        "string",
        "null"
      ]
    }
  },
  "required": [
    "data",
    "next_cursor"
  ],
  "additionalProperties": false
}

get_workspace

Read the name of a workspace containing an accessible project.

Required permissions: projects:read REST equivalent: GET /workspaces/{workspace_id}

Arguments
NameTypeDescription
workspace_idRequiredUUIDWorkspace ID returned by list_workspaces. On list_projects, restricts results to approved projects in that workspace.

Example call

JSON
{
  "name": "get_workspace",
  "arguments": {
    "workspace_id": "00000000-0000-4000-8000-000000000002"
  }
}

Example result

JSON
{
  "id": "00000000-0000-4000-8000-000000000002",
  "name": "Example workspace"
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string"
    },
    "name": {
      "type": "string"
    }
  },
  "required": [
    "id",
    "name"
  ],
  "additionalProperties": false
}

list_projects

List the approved projects you can currently access.

Required permissions: projects:read REST equivalent: GET /projects

Optionally pass workspace_id to list only approved projects in that workspace. An unavailable workspace returns 404; the filter never broadens project access.

Arguments
NameTypeDescription
limitintegerPage size. Defaults to 100; allowed range 1–200.
cursorstringOpaque next_cursor from the previous result. Keep the other arguments unchanged.
workspace_idUUIDWorkspace ID returned by list_workspaces. On list_projects, restricts results to approved projects in that workspace.

Example call

JSON
{
  "name": "list_projects",
  "arguments": {
    "limit": 20
  }
}

Example result

JSON
{
  "data": [
    {
      "id": "00000000-0000-4000-8000-000000000001",
      "workspace_id": "00000000-0000-4000-8000-000000000002",
      "name": "Example project",
      "status": "active",
      "description": "Facilities handover for the civic center.",
      "classification_system": "omniclass"
    }
  ],
  "next_cursor": null
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "workspace_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "classification_system": {
            "type": "string",
            "enum": [
              "omniclass",
              "uniclass"
            ]
          },
          "status": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "workspace_id",
          "name",
          "description",
          "classification_system",
          "status"
        ],
        "additionalProperties": false
      }
    },
    "next_cursor": {
      "type": [
        "string",
        "null"
      ]
    }
  },
  "required": [
    "data",
    "next_cursor"
  ],
  "additionalProperties": false
}

get_project

Read the details of one approved project.

Required permissions: projects:read REST equivalent: GET /projects/{project_id}

Arguments
NameTypeDescription
project_idRequiredUUIDProject ID returned by list_projects.

Example call

JSON
{
  "name": "get_project",
  "arguments": {
    "project_id": "00000000-0000-4000-8000-000000000001"
  }
}

Example result

JSON
{
  "id": "00000000-0000-4000-8000-000000000001",
  "workspace_id": "00000000-0000-4000-8000-000000000002",
  "name": "Example project",
  "status": "active",
  "description": "Facilities handover for the civic center.",
  "classification_system": "omniclass"
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string"
    },
    "workspace_id": {
      "type": "string"
    },
    "name": {
      "type": "string"
    },
    "description": {
      "type": [
        "string",
        "null"
      ]
    },
    "classification_system": {
      "type": "string",
      "enum": [
        "omniclass",
        "uniclass"
      ]
    },
    "status": {
      "type": "string"
    }
  },
  "required": [
    "id",
    "workspace_id",
    "name",
    "description",
    "classification_system",
    "status"
  ],
  "additionalProperties": false
}

get_workbook

Read the status of the current workbook for a project.

Required permissions: workbooks:read REST equivalent: GET /projects/{project_id}/workbook

Check whether the project’s workbook is updating. Use project_id for all workbook reads.

Arguments
NameTypeDescription
project_idRequiredUUIDProject ID returned by list_projects.

Example call

JSON
{
  "name": "get_workbook",
  "arguments": {
    "project_id": "00000000-0000-4000-8000-000000000001"
  }
}

Example result

JSON
{
  "project_id": "00000000-0000-4000-8000-000000000001",
  "updating": false,
  "latest_version_number": 2
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "project_id": {
      "type": "string"
    },
    "updating": {
      "type": "boolean"
    },
    "latest_version_number": {
      "type": [
        "integer",
        "null"
      ],
      "minimum": 1
    }
  },
  "required": [
    "project_id",
    "updating",
    "latest_version_number"
  ],
  "additionalProperties": false
}

list_sheets

Discover current worksheet keys, column keys and row counts, including custom columns.

Required permissions: workbooks:read REST equivalent: GET /projects/{project_id}/workbook/sheets

row_count is the full sheet count, not the count after a search. Use the returned keys in subsequent requests.

Arguments
NameTypeDescription
project_idRequiredUUIDProject ID returned by list_projects.

Example call

JSON
{
  "name": "list_sheets",
  "arguments": {
    "project_id": "00000000-0000-4000-8000-000000000001"
  }
}

Example result

JSON
{
  "sheets": [
    {
      "key": "component",
      "name": "Component",
      "row_count": 25,
      "columns": [
        {
          "key": "name",
          "name": "Name",
          "data_type": "string",
          "required": true,
          "editing": {
            "kind": "value",
            "allow_custom_value": true
          }
        },
        {
          "key": "maintenance_priority",
          "name": "Maintenance Priority",
          "data_type": "string",
          "required": false,
          "editing": {
            "kind": "value",
            "allow_custom_value": true
          }
        }
      ]
    }
  ]
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "sheets": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "row_count": {
            "type": "integer",
            "minimum": 0
          },
          "columns": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "data_type": {
                  "type": "string"
                },
                "required": {
                  "type": "boolean"
                },
                "editing": {
                  "type": "object",
                  "properties": {
                    "kind": {
                      "type": "string",
                      "enum": [
                        "value",
                        "choice",
                        "reference"
                      ]
                    },
                    "allow_custom_value": {
                      "type": "boolean"
                    },
                    "multiple": {
                      "type": "boolean"
                    },
                    "target_sheet": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "target_column": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "depends_on": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "kind",
                    "allow_custom_value"
                  ],
                  "additionalProperties": false
                }
              },
              "required": [
                "key",
                "name",
                "data_type",
                "required",
                "editing"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "key",
          "name",
          "row_count",
          "columns"
        ],
        "additionalProperties": false
      }
    }
  },
  "required": [
    "sheets"
  ],
  "additionalProperties": false
}

search_rows

Read current worksheet rows, with optional search, filters and selected columns.

Required permissions: workbooks:read REST equivalent: GET /projects/{project_id}/workbook/sheets/{sheet_key}/rows

Search matches cell values across the sheet, including columns omitted from the response. Multiple exact filters are combined with AND.

Arguments
NameTypeDescription
limitintegerPage size. Defaults to 100; allowed range 1–200.
cursorstringOpaque next_cursor from the previous result. Keep the other arguments unchanged.
searchstringCase-insensitive substring search across cell values. Up to 200 characters.
columnsarray of stringsColumn keys to return, up to 100 keys. Omit for all columns, including custom columns. Row reads are limited to 20,000 cells. An empty array is not allowed.
filtersobjectExact, case-sensitive values keyed by column key, such as {"name": "Pump 01"}. Up to 20 filters, combined with AND. An empty string matches an empty value, not null.
project_idRequiredUUIDProject ID returned by list_projects.
sheet_keyRequiredstringSheet key returned by list_sheets, such as component.

Example call

JSON
{
  "name": "search_rows",
  "arguments": {
    "sheet_key": "component",
    "search": "Pump",
    "limit": 25,
    "project_id": "00000000-0000-4000-8000-000000000001"
  }
}

Example result

JSON
{
  "data": [
    {
      "values": {
        "name": "Pump 01",
        "maintenance_priority": "High"
      },
      "key": "component:example",
      "source": "generated"
    }
  ],
  "next_cursor": null
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "enum": [
              "manual",
              "generated"
            ]
          },
          "values": {
            "type": "object",
            "additionalProperties": {
              "type": [
                "string",
                "null"
              ]
            }
          }
        },
        "required": [
          "key",
          "source",
          "values"
        ],
        "additionalProperties": false
      }
    },
    "next_cursor": {
      "type": [
        "string",
        "null"
      ]
    }
  },
  "required": [
    "data",
    "next_cursor"
  ],
  "additionalProperties": false
}

create_row

Add a user-created row with standard or custom column values.

Required permissions: workbooks:read, workbooks:rows:write REST equivalent: POST /projects/{project_id}/workbook/sheets/{sheet_key}/rows

Requires workbooks:rows:write and workbooks:read, plus an Editor or Manager role. Pass initial column values in values and idempotency_key as a tool argument when saving. Set preview: true to inspect a temporary row without saving; no ETag is needed for creation. Read the new row before making another change.

Arguments
NameTypeDescription
project_idRequiredUUIDProject ID returned by list_projects.
sheet_keyRequiredstringSheet key returned by list_sheets, such as component.
valuesRequiredobjectColumn keys mapped to strings, null to clear, or {references: [{sheet_key, row_key}]} for exact reference selections.
previewbooleanSet true to inspect direct and dependent changes without saving. Defaults to false.
idempotency_keystringUnique request key, up to 128 characters. Required to save. Reuse with identical arguments for retries within 24 hours.

Example call

JSON
{
  "name": "create_row",
  "arguments": {
    "project_id": "00000000-0000-4000-8000-000000000001",
    "sheet_key": "component",
    "idempotency_key": "example-create-001",
    "values": {
      "name": "Additional pump",
      "maintenance_priority": "High"
    }
  }
}

Example result

JSON
{
  "applied": true,
  "row": {
    "key": "manual:00000000-0000-4000-8000-000000000006",
    "source": "manual",
    "values": {
      "name": "Additional pump",
      "maintenance_priority": "High"
    }
  },
  "etag": "\"br-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"",
  "affected": {
    "rows_created": 1,
    "rows_removed": 0,
    "cells_updated": 2
  },
  "validation_pending": true
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "applied": {
      "type": "boolean"
    },
    "row": {
      "type": "object",
      "properties": {
        "key": {
          "type": "string"
        },
        "source": {
          "type": "string",
          "enum": [
            "manual",
            "generated"
          ]
        },
        "values": {
          "type": "object",
          "additionalProperties": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "required": [
        "key",
        "source",
        "values"
      ],
      "additionalProperties": false
    },
    "etag": {
      "type": "string"
    },
    "affected": {
      "type": "object",
      "properties": {
        "rows_created": {
          "type": "integer",
          "minimum": 0
        },
        "rows_removed": {
          "type": "integer",
          "minimum": 0
        },
        "cells_updated": {
          "type": "integer",
          "minimum": 0
        }
      },
      "required": [
        "rows_created",
        "rows_removed",
        "cells_updated"
      ],
      "additionalProperties": false
    },
    "validation_pending": {
      "type": "boolean"
    }
  },
  "required": [
    "applied",
    "row",
    "etag",
    "affected",
    "validation_pending"
  ],
  "additionalProperties": false
}

get_row

Read one current row using its key, not its displayed Name.

Required permissions: workbooks:read REST equivalent: GET /projects/{project_id}/workbook/sheets/{sheet_key}/rows/{row_key}

Pass the key returned by search_rows unchanged as row_key, together with the same project_id and sheet_key.

Arguments
NameTypeDescription
project_idRequiredUUIDProject ID returned by list_projects.
sheet_keyRequiredstringSheet key returned by list_sheets, such as component.
row_keyRequiredstringThe row’s key, exactly as returned by search_rows.
columnsarray of stringsColumn keys to return, up to 100 keys. Omit for all columns, including custom columns. Row reads are limited to 20,000 cells. An empty array is not allowed.

Example call

JSON
{
  "name": "get_row",
  "arguments": {
    "sheet_key": "component",
    "row_key": "component:example",
    "project_id": "00000000-0000-4000-8000-000000000001"
  }
}

Example result

JSON
{
  "row": {
    "values": {
      "name": "Pump 01",
      "maintenance_priority": "High"
    },
    "key": "component:example",
    "source": "generated"
  },
  "etag": "\"br-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\""
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "row": {
      "type": "object",
      "properties": {
        "key": {
          "type": "string"
        },
        "source": {
          "type": "string",
          "enum": [
            "manual",
            "generated"
          ]
        },
        "values": {
          "type": "object",
          "additionalProperties": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "required": [
        "key",
        "source",
        "values"
      ],
      "additionalProperties": false
    },
    "etag": {
      "type": "string"
    }
  },
  "required": [
    "row",
    "etag"
  ],
  "additionalProperties": false
}

update_row

Update existing cells in one row atomically. Only supplied columns change; null clears a value.

Required permissions: workbooks:read, workbooks:write REST equivalent: PATCH /projects/{project_id}/workbook/sheets/{sheet_key}/rows/{row_key}

Requires workbooks:write and workbooks:read, plus an Editor or Manager role on an active project. Pass if_match and idempotency_key as tool arguments. Set preview: true to evaluate the same changes without saving. Preview still needs if_match but no idempotency key. Validation runs after saving; validation_pending does not mean the edit failed.

Arguments
NameTypeDescription
project_idRequiredUUIDProject ID returned by list_projects.
sheet_keyRequiredstringSheet key returned by list_sheets, such as component.
row_keyRequiredstringThe row’s key, exactly as returned by search_rows.
if_matchstringExact etag from get_row without a column projection, or list_exclusions when including again. Required for destructive previews and application.
valuesRequiredobjectColumn keys mapped to strings, null to clear, or {references: [{sheet_key, row_key}]} for exact reference selections.
previewbooleanSet true to inspect direct and dependent changes without saving. Defaults to false.
idempotency_keystringUnique request key, up to 128 characters. Required to save. Reuse with identical arguments for retries within 24 hours.

Example call

JSON
{
  "name": "update_row",
  "arguments": {
    "project_id": "00000000-0000-4000-8000-000000000001",
    "sheet_key": "component",
    "row_key": "component:example",
    "if_match": "\"br-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"",
    "idempotency_key": "example-edit-001",
    "values": {
      "description": "Circulation pump serving level 2"
    }
  }
}

Example result

JSON
{
  "applied": true,
  "changes": [
    {
      "sheet_key": "component",
      "row_key": "component:example",
      "column_key": "description",
      "old_value": "Circulation pump",
      "value": "Circulation pump serving level 2",
      "requested": true
    }
  ],
  "rows": [
    {
      "sheet_key": "component",
      "row_key": "component:example",
      "etag": "\"br-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\""
    }
  ],
  "validation_pending": true
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "applied": {
      "type": "boolean"
    },
    "changes": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "sheet_key": {
            "type": "string"
          },
          "row_key": {
            "type": "string"
          },
          "column_key": {
            "type": "string"
          },
          "old_value": {
            "type": [
              "string",
              "null"
            ]
          },
          "value": {
            "type": [
              "string",
              "null"
            ]
          },
          "requested": {
            "type": "boolean"
          }
        },
        "required": [
          "sheet_key",
          "row_key",
          "column_key",
          "old_value",
          "value",
          "requested"
        ],
        "additionalProperties": false
      }
    },
    "rows": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "sheet_key": {
            "type": "string"
          },
          "row_key": {
            "type": "string"
          },
          "etag": {
            "type": "string"
          }
        },
        "required": [
          "sheet_key",
          "row_key",
          "etag"
        ],
        "additionalProperties": false
      }
    },
    "validation_pending": {
      "type": "boolean"
    }
  },
  "required": [
    "applied",
    "changes",
    "rows",
    "validation_pending"
  ],
  "additionalProperties": false
}

delete_row

Delete a user-created row and settle references to it. Generated rows must be excluded instead.

Required permissions: workbooks:read, workbooks:rows:write REST equivalent: DELETE /projects/{project_id}/workbook/sheets/{sheet_key}/rows/{row_key}

Deletes manual rows only. Pass the full-row ETag as if_match and idempotency_key as tool arguments. Set preview: true without an idempotency key to inspect the impact first. For Contacts, explicitly choose reference_action: clear, or reassign with replacement_row_key. Generated rows must use exclude_row instead.

Arguments
NameTypeDescription
project_idRequiredUUIDProject ID returned by list_projects.
sheet_keyRequiredstringSheet key returned by list_sheets, such as component.
row_keyRequiredstringThe row’s key, exactly as returned by search_rows.
if_matchstringExact etag from get_row without a column projection, or list_exclusions when including again. Required for destructive previews and application.
reference_actionstringFor Contact deletion, explicitly choose clear or reassign.Allowed: clear, reassign
replacement_row_keystringSame-sheet replacement row key, required with reassign. Type and Space replacements must be generated rows.
previewbooleanSet true to inspect direct and dependent changes without saving. Defaults to false.
idempotency_keystringUnique request key, up to 128 characters. Required to save. Reuse with identical arguments for retries within 24 hours.

Example call

JSON
{
  "name": "delete_row",
  "arguments": {
    "project_id": "00000000-0000-4000-8000-000000000001",
    "sheet_key": "component",
    "row_key": "manual:00000000-0000-4000-8000-000000000006",
    "if_match": "\"br-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"",
    "idempotency_key": "example-delete-001"
  }
}

Example result

JSON
{
  "applied": true,
  "affected": {
    "rows_created": 0,
    "rows_removed": 1,
    "cells_updated": 0
  },
  "validation_pending": true
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "applied": {
      "type": "boolean"
    },
    "affected": {
      "type": "object",
      "properties": {
        "rows_created": {
          "type": "integer",
          "minimum": 0
        },
        "rows_removed": {
          "type": "integer",
          "minimum": 0
        },
        "cells_updated": {
          "type": "integer",
          "minimum": 0
        }
      },
      "required": [
        "rows_created",
        "rows_removed",
        "cells_updated"
      ],
      "additionalProperties": false
    },
    "validation_pending": {
      "type": "boolean"
    }
  },
  "required": [
    "applied",
    "affected",
    "validation_pending"
  ],
  "additionalProperties": false
}

list_cell_options

Load choices or reference rows for one cell, in pages of 100.

Required permissions: workbooks:read REST equivalent: GET /projects/{project_id}/workbook/sheets/{sheet_key}/rows/{row_key}/cells/{column_key}/options

Reference choices include stable row keys so duplicate or comma-containing names can be selected unambiguously. An empty list on a free-text column means there are no suggested choices, not that the cell is uneditable.

Arguments
NameTypeDescription
project_idRequiredUUIDProject ID returned by list_projects.
sheet_keyRequiredstringSheet key returned by list_sheets, such as component.
row_keyRequiredstringThe row’s key, exactly as returned by search_rows.
column_keyRequiredstringColumn key returned by list_sheets.
searchstringCase-insensitive substring search across cell values. Up to 200 characters.
cursorstringOpaque next_cursor from the previous result. Keep the other arguments unchanged.

Example call

JSON
{
  "name": "list_cell_options",
  "arguments": {
    "project_id": "00000000-0000-4000-8000-000000000001",
    "sheet_key": "component",
    "row_key": "component:example",
    "column_key": "type_name",
    "search": "Pump"
  }
}

Example result

JSON
{
  "data": [
    {
      "value": "Circulation Pump",
      "reference": {
        "sheet_key": "type",
        "row_key": "type:circulation-pump"
      }
    }
  ],
  "next_cursor": null
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "value": {
            "type": "string"
          },
          "reference": {
            "type": "object",
            "properties": {
              "sheet_key": {
                "type": "string"
              },
              "row_key": {
                "type": "string"
              }
            },
            "required": [
              "sheet_key",
              "row_key"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "value"
        ],
        "additionalProperties": false
      }
    },
    "next_cursor": {
      "type": [
        "string",
        "null"
      ]
    }
  },
  "required": [
    "data",
    "next_cursor"
  ],
  "additionalProperties": false
}

update_cells

Apply up to 100 cell edits across existing rows. Every edit succeeds or none is saved.

Required permissions: workbooks:read, workbooks:write REST equivalent: POST /projects/{project_id}/workbook/cells/batch

Include each row once with its full-row ETag as if_match and its values. Pass idempotency_key as a tool argument when saving. Set preview: true to inspect direct and dependent changes without saving. Retry an uncertain result with the exact same arguments and idempotency key within 24 hours; a different edit needs a new key.

Arguments
NameTypeDescription
project_idRequiredUUIDProject ID returned by list_projects.
previewbooleanSet true to inspect direct and dependent changes without saving. Defaults to false.
idempotency_keystringUnique request key, up to 128 characters. Required to save. Reuse with identical arguments for retries within 24 hours.
rowsRequiredarray of objectsRows with sheet_key, row_key, if_match and values. Include each row once, up to 100 edited cells across the batch.

Example call

JSON
{
  "name": "update_cells",
  "arguments": {
    "project_id": "00000000-0000-4000-8000-000000000001",
    "idempotency_key": "example-batch-001",
    "rows": [
      {
        "sheet_key": "component",
        "row_key": "component:example",
        "if_match": "\"br-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"",
        "values": {
          "description": "Circulation pump serving level 2"
        }
      }
    ]
  }
}

Example result

JSON
{
  "applied": true,
  "changes": [
    {
      "sheet_key": "component",
      "row_key": "component:example",
      "column_key": "description",
      "old_value": "Circulation pump",
      "value": "Circulation pump serving level 2",
      "requested": true
    }
  ],
  "rows": [
    {
      "sheet_key": "component",
      "row_key": "component:example",
      "etag": "\"br-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\""
    }
  ],
  "validation_pending": true
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "applied": {
      "type": "boolean"
    },
    "changes": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "sheet_key": {
            "type": "string"
          },
          "row_key": {
            "type": "string"
          },
          "column_key": {
            "type": "string"
          },
          "old_value": {
            "type": [
              "string",
              "null"
            ]
          },
          "value": {
            "type": [
              "string",
              "null"
            ]
          },
          "requested": {
            "type": "boolean"
          }
        },
        "required": [
          "sheet_key",
          "row_key",
          "column_key",
          "old_value",
          "value",
          "requested"
        ],
        "additionalProperties": false
      }
    },
    "rows": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "sheet_key": {
            "type": "string"
          },
          "row_key": {
            "type": "string"
          },
          "etag": {
            "type": "string"
          }
        },
        "required": [
          "sheet_key",
          "row_key",
          "etag"
        ],
        "additionalProperties": false
      }
    },
    "validation_pending": {
      "type": "boolean"
    }
  },
  "required": [
    "applied",
    "changes",
    "rows",
    "validation_pending"
  ],
  "additionalProperties": false
}

exclude_row

Keep this individual model-derived row out of the workbook through future model updates.

Required permissions: workbooks:read, workbooks:exclusions:write REST equivalent: POST /projects/{project_id}/workbook/sheets/{sheet_key}/exclusions

Requires workbooks:exclusions:write and workbooks:read, plus a Manager role. Pass the full-row ETag as if_match and idempotency_key as tool arguments. Set preview: true to inspect the affected rows and cells without saving. For Types and Spaces, choose how dependent Components are handled. This creates an individual exclusion, not an asset rule.

Arguments
NameTypeDescription
project_idRequiredUUIDProject ID returned by list_projects.
sheet_keyRequiredstringSheet key returned by list_sheets, such as component.
row_keyRequiredstringThe row’s key, exactly as returned by search_rows.
if_matchstringExact etag from get_row without a column projection, or list_exclusions when including again. Required for destructive previews and application.
component_actionstringType: exclude, clear_type or reassign. Space: exclude, resolve_space or reassign. Required for Type and Space only.Allowed: exclude, clear_type, resolve_space, reassign
replacement_row_keystringSame-sheet replacement row key, required with reassign. Type and Space replacements must be generated rows.
previewbooleanSet true to inspect direct and dependent changes without saving. Defaults to false.
idempotency_keystringUnique request key, up to 128 characters. Required to save. Reuse with identical arguments for retries within 24 hours.

Example call

JSON
{
  "name": "exclude_row",
  "arguments": {
    "project_id": "00000000-0000-4000-8000-000000000001",
    "sheet_key": "component",
    "row_key": "component:example",
    "if_match": "\"br-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"",
    "idempotency_key": "example-exclude-001"
  }
}

Example result

JSON
{
  "applied": true,
  "exclusion": {
    "id": "00000000-0000-4000-8000-000000000005",
    "name": "Pump 01",
    "component_action": null,
    "replacement_name": null,
    "dependent_row_count": 0,
    "etag": "\"br-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\""
  },
  "affected": {
    "rows_created": 0,
    "rows_removed": 1,
    "cells_updated": 0
  },
  "validation_pending": true
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "applied": {
      "type": "boolean"
    },
    "exclusion": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string"
        },
        "name": {
          "type": "string"
        },
        "component_action": {
          "type": [
            "string",
            "null"
          ]
        },
        "replacement_name": {
          "type": [
            "string",
            "null"
          ]
        },
        "dependent_row_count": {
          "type": "integer",
          "minimum": 0
        },
        "etag": {
          "type": "string"
        }
      },
      "required": [
        "id",
        "name",
        "component_action",
        "replacement_name",
        "dependent_row_count",
        "etag"
      ],
      "additionalProperties": false
    },
    "affected": {
      "type": "object",
      "properties": {
        "rows_created": {
          "type": "integer",
          "minimum": 0
        },
        "rows_removed": {
          "type": "integer",
          "minimum": 0
        },
        "cells_updated": {
          "type": "integer",
          "minimum": 0
        }
      },
      "required": [
        "rows_created",
        "rows_removed",
        "cells_updated"
      ],
      "additionalProperties": false
    },
    "validation_pending": {
      "type": "boolean"
    }
  },
  "required": [
    "applied",
    "exclusion",
    "affected",
    "validation_pending"
  ],
  "additionalProperties": false
}

list_exclusions

Read the individual exclusions shown in the sheet’s Settings, including validators for Include again.

Required permissions: workbooks:read REST equivalent: GET /projects/{project_id}/workbook/sheets/{sheet_key}/exclusions

Requires workbooks:read. Exclusion IDs remain usable while an exclusion is active, even after model updates. The list does not include broad asset or parameter selection rules, Floor settings or removed Contact mappings.

Arguments
NameTypeDescription
project_idRequiredUUIDProject ID returned by list_projects.
sheet_keyRequiredstringSheet key returned by list_sheets, such as component.
limitintegerPage size. Defaults to 100; allowed range 1–200.
cursorstringOpaque next_cursor from the previous result. Keep the other arguments unchanged.

Example call

JSON
{
  "name": "list_exclusions",
  "arguments": {
    "project_id": "00000000-0000-4000-8000-000000000001",
    "sheet_key": "component",
    "limit": 25
  }
}

Example result

JSON
{
  "data": [
    {
      "id": "00000000-0000-4000-8000-000000000005",
      "name": "Pump 01",
      "component_action": null,
      "replacement_name": null,
      "dependent_row_count": 0,
      "etag": "\"br-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\""
    }
  ],
  "next_cursor": null
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "component_action": {
            "type": [
              "string",
              "null"
            ]
          },
          "replacement_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "dependent_row_count": {
            "type": "integer",
            "minimum": 0
          },
          "etag": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "component_action",
          "replacement_name",
          "dependent_row_count",
          "etag"
        ],
        "additionalProperties": false
      }
    },
    "next_cursor": {
      "type": [
        "string",
        "null"
      ]
    }
  },
  "required": [
    "data",
    "next_cursor"
  ],
  "additionalProperties": false
}

restore_excluded_row

Remove an individual exclusion and schedule the workbook update that can bring its row back.

Required permissions: workbooks:read, workbooks:exclusions:write REST equivalent: DELETE /projects/{project_id}/workbook/sheets/{sheet_key}/exclusions/{exclusion_id}

Use an ID and ETag returned by list_exclusions; pass the ETag as if_match and idempotency_key as tool arguments. Set preview: true to check whether the exclusion can be removed without saving. Applying schedules a workbook update; poll get_workbook until updating is false, then search_rows for the current row. Current model and settings may still prevent the row from appearing.

Arguments
NameTypeDescription
project_idRequiredUUIDProject ID returned by list_projects.
sheet_keyRequiredstringSheet key returned by list_sheets, such as component.
exclusion_idRequiredUUIDExclusion ID returned by list_exclusions or exclude_row.
if_matchstringExact etag from get_row without a column projection, or list_exclusions when including again. Required for destructive previews and application.
previewbooleanSet true to inspect direct and dependent changes without saving. Defaults to false.
idempotency_keystringUnique request key, up to 128 characters. Required to save. Reuse with identical arguments for retries within 24 hours.

Example call

JSON
{
  "name": "restore_excluded_row",
  "arguments": {
    "project_id": "00000000-0000-4000-8000-000000000001",
    "sheet_key": "component",
    "exclusion_id": "00000000-0000-4000-8000-000000000005",
    "if_match": "\"br-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"",
    "idempotency_key": "example-include-001"
  }
}

Example result

JSON
{
  "applied": true,
  "exclusion_id": "00000000-0000-4000-8000-000000000005",
  "updating": true
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "applied": {
      "type": "boolean"
    },
    "exclusion_id": {
      "type": "string"
    },
    "updating": {
      "type": "boolean"
    }
  },
  "required": [
    "applied",
    "exclusion_id",
    "updating"
  ],
  "additionalProperties": false
}

list_issues

Read existing validation findings for a workbook.

Required permissions: reviews:read REST equivalent: GET /projects/{project_id}/workbook/issues

This endpoint reads existing findings; it does not run validation.

Arguments
NameTypeDescription
limitintegerPage size. Defaults to 100; allowed range 1–200.
cursorstringOpaque next_cursor from the previous result. Keep the other arguments unchanged.
project_idRequiredUUIDProject ID returned by list_projects.
statusstringReturn only findings with this status. Omit for all statuses.Allowed: open, ignored, resolved
severitystringReturn only findings with this severity. Omit for all severities.Allowed: error, warning
sheet_keystringReturn findings for one sheet key.

Example call

JSON
{
  "name": "list_issues",
  "arguments": {
    "status": "open",
    "limit": 20,
    "project_id": "00000000-0000-4000-8000-000000000001"
  }
}

Example result

JSON
{
  "data": [
    {
      "id": "00000000-0000-4000-8000-000000000009",
      "code": "missing_value",
      "severity": "warning",
      "status": "open",
      "message": "A value needs review.",
      "location": {
        "sheet_key": "component",
        "row_key": "component:example",
        "column_key": "description"
      }
    }
  ],
  "next_cursor": null
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "severity": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "location": {
            "type": "object",
            "properties": {
              "sheet_key": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "row_key": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "column_key": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "sheet_key",
              "row_key",
              "column_key"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "id",
          "code",
          "severity",
          "status",
          "message",
          "location"
        ],
        "additionalProperties": false
      }
    },
    "next_cursor": {
      "type": [
        "string",
        "null"
      ]
    }
  },
  "required": [
    "data",
    "next_cursor"
  ],
  "additionalProperties": false
}

list_asset_review_recommendations

Read existing Asset review recommendations and their affected assets or attributes.

Required permissions: reviews:read REST equivalent: GET /projects/{project_id}/workbook/asset-review/recommendations

Available only when the workspace allows Asset review. Reading findings does not start a review or change selections.

Arguments
NameTypeDescription
limitintegerPage size. Defaults to 100; allowed range 1–200.
cursorstringOpaque next_cursor from the previous result. Keep the other arguments unchanged.
project_idRequiredUUIDProject ID returned by list_projects.
statusstringReturn only findings with this status. Omit for all statuses.Allowed: open, addressed, ignored, no_longer_flagged

Example call

JSON
{
  "name": "list_asset_review_recommendations",
  "arguments": {
    "status": "open",
    "limit": 20,
    "project_id": "00000000-0000-4000-8000-000000000001"
  }
}

Example result

JSON
{
  "data": [
    {
      "id": "00000000-0000-4000-8000-000000000010",
      "status": "open",
      "title": "Consider excluding reference geometry",
      "explanation": "Review whether these objects belong in the handover.",
      "recommendation": {
        "action": "exclude",
        "target": "asset"
      },
      "affected": [
        {
          "category": "Generic Models",
          "family": "Reference Geometry",
          "type": "Coordination",
          "included_count": 3,
          "total_count": 3
        }
      ],
      "last_reviewed_at": "2026-10-07T12:00:00Z"
    }
  ],
  "next_cursor": null
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "explanation": {
            "type": "string"
          },
          "recommendation": {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "include",
                  "exclude"
                ]
              },
              "target": {
                "type": "string",
                "enum": [
                  "asset",
                  "attribute"
                ]
              }
            },
            "required": [
              "action",
              "target"
            ],
            "additionalProperties": false
          },
          "affected": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "category": {
                  "type": "string"
                },
                "family": {
                  "type": "string"
                },
                "type": {
                  "type": "string"
                },
                "parameter": {
                  "type": "string"
                },
                "unit": {
                  "type": "string"
                },
                "included_count": {
                  "type": "integer",
                  "minimum": 0
                },
                "total_count": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "required": [],
              "additionalProperties": false
            }
          },
          "last_reviewed_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "status",
          "title",
          "explanation",
          "recommendation",
          "affected",
          "last_reviewed_at"
        ],
        "additionalProperties": false
      }
    },
    "next_cursor": {
      "type": [
        "string",
        "null"
      ]
    }
  },
  "required": [
    "data",
    "next_cursor"
  ],
  "additionalProperties": false
}

list_exports

List exports that have already been requested in BIMRelay.

Required permissions: exports:read REST equivalent: GET /projects/{project_id}/workbook/exports

This endpoint lists existing exports; it does not create them.

Arguments
NameTypeDescription
limitintegerPage size. Defaults to 100; allowed range 1–200.
cursorstringOpaque next_cursor from the previous result. Keep the other arguments unchanged.
project_idRequiredUUIDProject ID returned by list_projects.

Example call

JSON
{
  "name": "list_exports",
  "arguments": {
    "limit": 20,
    "project_id": "00000000-0000-4000-8000-000000000001"
  }
}

Example result

JSON
{
  "data": [
    {
      "id": "00000000-0000-4000-8000-000000000012",
      "status": "completed",
      "format": "xlsx",
      "created_at": "2026-10-07T12:00:00Z",
      "completed_at": "2026-10-07T12:00:00Z"
    }
  ],
  "next_cursor": null
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "format": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "status",
          "format",
          "created_at",
          "completed_at"
        ],
        "additionalProperties": false
      }
    },
    "next_cursor": {
      "type": [
        "string",
        "null"
      ]
    }
  },
  "required": [
    "data",
    "next_cursor"
  ],
  "additionalProperties": false
}

get_export_download

Get a temporary URL for an existing completed Excel export.

Required permissions: exports:read REST equivalent: GET /projects/{project_id}/workbook/exports/{export_id}/download

Download from the returned URL within five minutes. Treat it as a secret; it remains usable until expiry even if the connection is revoked. An incomplete or failed export returns an export_not_ready error.

Arguments
NameTypeDescription
project_idRequiredUUIDProject ID returned by list_projects.
export_idRequiredUUIDExport ID returned by list_exports.

Example call

JSON
{
  "name": "get_export_download",
  "arguments": {
    "export_id": "00000000-0000-4000-8000-000000000012",
    "project_id": "00000000-0000-4000-8000-000000000001"
  }
}

Example result

JSON
{
  "url": "https://storage.example.com/example.xlsx?temporary=example",
  "expires_at": "2026-10-07T12:05:00Z"
}

Result schema

JSON
{
  "type": "object",
  "properties": {
    "url": {
      "type": "string",
      "format": "uri"
    },
    "expires_at": {
      "type": "string",
      "format": "date-time"
    }
  },
  "required": [
    "url",
    "expires_at"
  ],
  "additionalProperties": false
}