---
title: ControlCom Builder MCP
description: Connect your own LLM client to your ControlCom organization to configure and inspect ControlCom Connect through the Builder MCP server.
source: https://documentation.controlcomtech.com/build/mcp
---

# ControlCom Builder MCP

The ControlCom Builder MCP is a hosted [Model Context Protocol](https://modelcontextprotocol.io) server that connects your own LLM client (Claude Code, Claude Desktop, Cursor, or any MCP-capable client) directly to your ControlCom organization, so you can configure and inspect ControlCom Connect in natural language.

> **Workflow Stage: Integrate**

It is an all-in-one endpoint: a single server exposes both the write/configuration tools that build out your platform model and the full read, discovery, and monitoring toolset used to verify that model against live data. Ready to connect? Jump to [Connect Your Client](https://documentation.controlcomtech.com/build/mcp/connect).

## What you can do

The Builder MCP drives the platform-configuration workflow, the same work you'd otherwise do by hand in the app:

* Create and organize Assets into a parent/child hierarchy.
* Manage freeform Asset Types (Generator, Switchgear, Meter, …).
* Create device Variables and bind them to Assets so the model reflects real readings.
* Define typed Asset Relationships (power flow, monitoring, adjacency) as a directed graph on top of the hierarchy.
* Read back current and historical readings, device status, alarms, and weather to sanity-check the result.

## How it works

* `Endpoint` (URL): `https://api.controlcomtech.com/primary/v1/<organizationId>/mcp/builder`
* `Transport` (http): Streamable HTTP, stateless and POST-only. Each request spins up a fresh server, handles one JSON-RPC message, and tears down.
* `Authentication` (HTTP Basic): API key only: `Authorization: Basic base64(<publicId>:<secret>)`. Session/JWT tokens are rejected.
* `Scope` (organization): Everything is scoped to the organization tied to the API key. A key cannot reach other organizations.

You need an existing organization with at least one device onboarded (so there are real publish paths to bind), and permission to create API keys for that organization.

## Concepts

The server operates on a small set of platform objects:

* **Asset**: a node in your model (a generator, a bus, a meter). Assets form a hierarchy through a `parentId` ("part of" / "organized under").
* **Asset Type**: a freeform, user-managed label such as "Generator." An Asset references one via `typeId`; resolve an existing type with `listAssetTypes` before creating an Asset.
* **Asset Relationship**: a typed, directed edge layered on the hierarchy, written `sourceAssetId --[type]--> targetAssetId`. The edge label is an **Asset Relationship Type** (e.g. `FeedsPowerTo`, `Monitors`), which can be paired with an inverse (`FeedsPowerTo` ↔ `FedFrom`) so the reverse direction is managed automatically.
* **Device / Variable**: [Devices](https://documentation.controlcomtech.com/platform/devices) publish telemetry; a [Variable](https://documentation.controlcomtech.com/platform/variables) maps a published path (`topicPropertyPath`) to a named value. Binding Variables to an Asset is what makes the model reflect live readings.

## Tool reference

The server exposes 29 tools across three groups. Your assistant chooses tools automatically. This is for understanding what each does.

### Write & configuration

| Tool                          | Purpose                                                                                                                                   |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `createAsset`                 | Create an asset. Resolve `typeId` via `listAssetTypes` (or `createAssetType`) first.                                                      |
| `createAssetType`             | Create a freeform Asset Type label.                                                                                                       |
| `createAssetRelationship`     | Create a typed directed edge between two assets. Auto-creates the inverse if the type has one.                                            |
| `createAssetRelationshipType` | Create an edge label; optionally pair an inverse in one transaction. `providerSide` = `SOURCE` / `TARGET` / omit.                         |
| `createVariable`              | Create a device variable. Needs `deviceId` + `topicPropertyPath` (must match the device's real publish path on live devices).             |
| `bindVariables`               | Attach or detach device variables to/from an asset.                                                                                       |
| `updateAsset`                 | Update asset metadata (name, description, `typeId`, `locationId`, `parentId`).                                                            |
| `updateVariable`              | Update variable metadata (description, unit, `isLoggingEnabled`). Managed-template variables are protected.                               |
| `deleteAsset`                 | **Destructive.** Cascades: unbinds variables, orphans children, removes relationships.                                                    |
| `deleteAssetType`             | **Destructive.** Fails if any asset still references it via `typeId`.                                                                     |
| `deleteAssetRelationship`     | **Destructive.** Removes one edge; auto-removes the paired inverse.                                                                       |
| `deleteAssetRelationshipType` | **Destructive.** Removes every edge of that type. The inverse type is not auto-deleted.                                                   |
| `deleteVariable`              | **Destructive (recoverable).** Soft-archives (renames `_deleted_<uuid>`, preserves history). Refuses if non-archived alarms reference it. |
| `getAssetBindings`            | Read the variables bound to one asset: the canonical post-write check for `bindVariables`.                                                |

### Read & discovery

`listAssets` · `searchAssets` · `getAsset` (detail + bound variables + 1-hop relationships, incl. edge IDs) · `listAssetTypes` · `listAssetRelationshipTypes` · `listDevices` · `searchVariables` · `getLocations`

### Monitoring & verification

`getCurrentReading` · `getDeviceStatus` · `getAlarmSummary` · `getAlarmHistory` · `getHistoricalReadings` · `getCurrentWeather` · `getHistoricalWeather`

## Safety model

The server ships a system prompt (delivered to your client as MCP instructions) that keeps routine work fast and irreversible changes deliberate:

* **Discover before writing.** The assistant resolves IDs with the read tools and verifies writes with `getAssetBindings` / `getAsset`. It never guesses IDs.
* **Additive writes run directly** when your intent is unambiguous, with no "shall I proceed?" friction.
* **Destructive operations always confirm**, restating the cascade effects first, even on a direct request. There is no undo, except for `deleteVariable`, which is a recoverable soft-archive.
* **A multi-step instruction is planned once, approved once, then executed as a batch.**

Every tool is scoped to the organization tied to the API key; a key cannot touch another organization. To work across organizations, create a key in each and add one server entry per organization.

## Limits & troubleshooting

Requests are rate-limited on three windows: **30 / second**, **100 / 10 seconds**, and **600 / minute**. Exceeding a window returns a rate-limit error and the assistant backs off and retries.

* **`401 Unauthorized`**: the API key is missing or malformed, or a session/JWT token was used instead of an API key. Regenerate it under **Settings → API Keys** and re-paste the full `Authorization: Basic <token>` header.
* **No tools appear**: confirm the `url` ends in `/<organizationId>/mcp/builder`, the `type` is `"http"`, and you restarted the client after editing its config.
* **A write seems to have no effect**: verify with `getAssetBindings` / `getAsset`; the usual cause is a `topicPropertyPath` that doesn't match the device's real publish path.
