Skip to main content
Glama
tookta91

Aedifion MCP Server

by tookta91
README.md
# mcp-server-aedifion

[![CI](https://github.com/bbruhn91/mcp-server-aedifion/actions/workflows/ci.yml/badge.svg)](https://github.com/bbruhn91/mcp-server-aedifion/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)

An [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server that provides tools for interacting with the [aedifion](https://www.aedifion.com/) cloud API. This server enables AI assistants to:

- Query building IoT data and timeseries
- Run and manage analytics functions and KPIs
- Configure alerts and controls
- Manage projects, components, and datapoints
- Access weather data for building locations

API documentation: https://api.cloud.aedifion.eu/ui/

## Installation

### Using `uv` (recommended)

```bash
uv pip install git+https://github.com/bbruhn91/mcp-server-aedifion.git
```

### Using `pip`

```bash
pip install git+https://github.com/bbruhn91/mcp-server-aedifion.git
```

### From source

```bash
git clone https://github.com/bbruhn91/mcp-server-aedifion.git
cd mcp-server-aedifion
uv pip install -e .
```

## Configuration

### Environment variables

The server requires aedifion API credentials. Create a `.env` file in your working directory (see `.env.example`):

```bash
cp .env.example .env
# Edit .env with your credentials
```

| Variable | Required | Default | Description |
|---|---|---|---|
| `AEDIFION_USERNAME` | Yes\* | — | Your aedifion account email |
| `AEDIFION_PASSWORD` | Yes\* | — | Your aedifion account password |
| `AEDIFION_TOKEN` | No | — | Pre-obtained bearer token (alternative to username/password) |
| `AEDIFION_BASE_URL` | No | `https://api.cloud.aedifion.eu` | API base URL |

\* Required unless `AEDIFION_TOKEN` is set.

### Claude Desktop

Add the server to your Claude Desktop configuration (`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "aedifion": {
      "command": "mcp-server-aedifion",
      "env": {
        "AEDIFION_USERNAME": "your-email@example.com",
        "AEDIFION_PASSWORD": "your-password"
      }
    }
  }
}
```

Or if running from source with `uv`:

```json
{
  "mcpServers": {
    "aedifion": {
      "command": "uv",
      "args": [
        "--directory", "/path/to/mcp-server-aedifion",
        "run", "mcp-server-aedifion"
      ],
      "env": {
        "AEDIFION_USERNAME": "your-email@example.com",
        "AEDIFION_PASSWORD": "your-password"
      }
    }
  }
}
```

### Claude Code

```bash
claude mcp add aedifion -- mcp-server-aedifion
```

Or with environment variables inline:

```bash
claude mcp add aedifion \
  --env AEDIFION_USERNAME=your-email \
  --env AEDIFION_PASSWORD=your-password \
  -- mcp-server-aedifion
```

### Other MCP hosts

Any MCP-compatible host can use this server via the `stdio` transport. Run the `mcp-server-aedifion` command with the required environment variables set.

## Tools

The server exposes **95+ tools** organized by category. Each tool maps to one or more aedifion REST API endpoints.

<!-- ============================================================ -->

<details>
<summary><strong>Meta</strong> (5 tools)</summary>

- **`ping`** &mdash; Ping the aedifion API server to check availability.

- **`get_api_version`** &mdash; Get the aedifion API version.

- **`get_endpoints`** &mdash; List all available API endpoints.

- **`get_label_definitions`** &mdash; Get all label definitions available in aedifion.

- **`get_label_systems`** &mdash; Get available label/unit systems (e.g. SI, imperial).

</details>

<!-- ============================================================ -->

<details>
<summary><strong>User</strong> (4 tools)</summary>

- **`get_user`** &mdash; Get the currently logged-in user's details.

- **`update_user`** &mdash; Update the logged-in user's details.
  - `first_name` (string, optional): New first name.
  - `last_name` (string, optional): New last name.

- **`get_user_permissions`** &mdash; Get the logged-in user's project permissions.

- **`get_user_roles`** &mdash; Get the logged-in user's roles.

</details>

<!-- ============================================================ -->

<details>
<summary><strong>AI Assistant</strong> (4 tools)</summary>

- **`ai_get_threads`** &mdash; List all AI conversation threads for the current user.
  - `page` (int, optional): Page number for pagination.
  - `per_page` (int, optional): Number of items per page.

- **`ai_get_thread`** &mdash; Get all messages in an AI conversation thread.
  - `thread_id` (string, required): The thread identifier.

- **`ai_chat`** &mdash; Send a chat message to the aedifion AI assistant.
  - `thread_id` (string, required): The thread identifier (use `'new'` for a new thread).
  - `message` (string, required): The message to send.

- **`ai_delete_thread`** &mdash; Delete an AI conversation thread.
  - `thread_id` (string, required): The thread identifier.

</details>

<!-- ============================================================ -->

<details>
<summary><strong>Company</strong> (9 tools)</summary>

- **`get_company`** &mdash; Get the current user's company details including projects and users.

- **`update_company`** &mdash; Update company details.
  - `name` (string, optional): New company name.
  - `description` (string, optional): New company description.

- **`get_company_roles`** &mdash; Get all roles defined in the company.

- **`get_company_permissions`** &mdash; Get all project permissions granted to the company.

- **`get_company_labels`** &mdash; Get all labels assigned to the company.

- **`create_project`** &mdash; Create a new project in the company.
  - `name` (string, required): Project name.
  - `description` (string, optional): Project description.

- **`create_user`** &mdash; Create a new user in the company.
  - `email` (string, required): User email address.
  - `first_name` (string, required): First name.
  - `last_name` (string, required): Last name.
  - `password` (string, required): Initial password.

- **`get_company_user`** &mdash; Get details of a user within the company.
  - `user_id` (int, required): The user's numeric ID.

- **`delete_company_user`** &mdash; Delete a user from the company.
  - `user_id` (int, required): The user's numeric ID.

</details>

<!-- ============================================================ -->

<details>
<summary><strong>Realm</strong> (3 tools)</summary>

- **`get_realm_companies`** &mdash; Get all companies in the realm.
  - `page` (int, optional): Page number.
  - `per_page` (int, optional): Items per page.

- **`get_realm_projects`** &mdash; Get all projects in the realm.
  - `page` (int, optional): Page number.
  - `per_page` (int, optional): Items per page.

- **`get_realm_users`** &mdash; Get all users in the realm.
  - `page` (int, optional): Page number.
  - `per_page` (int, optional): Items per page.

</details>

<!-- ============================================================ -->

<details>
<summary><strong>Project</strong> (35 tools)</summary>

- **`get_project`** &mdash; Get a project's details.
  - `project_id` (int, required): The project's numeric ID.

- **`update_project`** &mdash; Update a project's details.
  - `project_id` (int, required): The project's numeric ID.
  - `name` (string, optional): New project name.
  - `description` (string, optional): New project description.

- **`delete_project`** &mdash; Delete a project. Requires confirmation via the project name.
  - `project_id` (int, required): The project's numeric ID.
  - `project_name` (string, required): The project name (for confirmation).

- **`get_project_datapoints`** &mdash; Get all datapoints in a project.
  - `project_id` (int, required): The project's numeric ID.
  - `page` (int, optional): Page number.
  - `per_page` (int, optional): Items per page.
  - `filter` (string, optional): Filter string for datapoint names.

- **`get_project_timeseries`** &mdash; Get time series data for one or more datapoints.
  - `project_id` (int, required): The project's numeric ID.
  - `datapoint_ids` (string, required): Comma-separated datapoint IDs.
  - `start` (string, optional): Start time in ISO 8601 format.
  - `end` (string, optional): End time in ISO 8601 format.
  - `max` (int, optional): Maximum number of observations.
  - `samplerate` (string, optional): Resample interval (e.g. `'15min'`, `'1h'`, `'1d'`).
  - `interpolation` (string, optional): Interpolation method (e.g. `'linear'`, `'pad'`).
  - `aggregation` (string, optional): Aggregation method (e.g. `'mean'`, `'sum'`, `'max'`, `'min'`).
  - `short` (bool, optional): Return short format (timestamps + values only).
  - `units_system` (string, optional): Unit system (e.g. `'SI'`).
  - `currency_system` (string, optional): Currency system.

- **`write_project_timeseries`** &mdash; Write timeseries data to datapoints.
  - `project_id` (int, required): The project's numeric ID.
  - `timeseries_data` (string, required): JSON string with timeseries data.

- **`delete_project_timeseries`** &mdash; Delete timeseries data for a datapoint.
  - `project_id` (int, required): The project's numeric ID.
  - `datapoint_id` (string, required): The datapoint identifier.
  - `start` (string, optional): Start time in ISO 8601 format.
  - `end` (string, optional): End time in ISO 8601 format.

- **`get_project_alerts`** &mdash; Get all alerts configured in a project.
  - `project_id` (int, required): The project's numeric ID.
  - `page` (int, optional): Page number.
  - `per_page` (int, optional): Items per page.

- **`get_project_tags`** &mdash; Get all datapoint tags in a project.
  - `project_id` (int, required): The project's numeric ID.
  - `key` (string, optional): Filter by tag key.
  - `keys_only` (bool, optional): Return only tag keys without values.

- **`add_project_tag`** &mdash; Add or overwrite a tag on a datapoint.
  - `project_id` (int, required): The project's numeric ID.
  - `tag_id` (string, required): The tag identifier.
  - `key` (string, required): Tag key.
  - `value` (string, required): Tag value.

- **`delete_project_tag`** &mdash; Delete a tag.
  - `project_id` (int, required): The project's numeric ID.
  - `tag_id` (string, required): The tag identifier.

- **`get_project_components`** &mdash; Get all components configured in a project.
  - `project_id` (int, required): The project's numeric ID.
  - `page` (int, optional): Page number.
  - `per_page` (int, optional): Items per page.

- **`get_project_component`** &mdash; Get a specific component in a project.
  - `project_id` (int, required): The project's numeric ID.
  - `cip_id` (int, required): The component-in-project ID.

- **`add_project_component`** &mdash; Add a component to a project.
  - `project_id` (int, required): The project's numeric ID.
  - `component_id` (int, required): The component definition ID.

- **`delete_project_component`** &mdash; Remove a component from a project.
  - `project_id` (int, required): The project's numeric ID.
  - `cip_id` (int, required): The component-in-project ID.

- **`get_component_pins`** &mdash; Get all pin mappings for a component in a project.
  - `project_id` (int, required): The project's numeric ID.
  - `cip_id` (int, required): The component-in-project ID.

- **`map_component_pin`** &mdash; Map a component pin to a datapoint.
  - `project_id` (int, required): The project's numeric ID.
  - `cip_id` (int, required): The component-in-project ID.
  - `pin_id` (int, required): The pin ID.
  - `datapoint_id` (string, required): The datapoint identifier to map to.

- **`unmap_component_pin`** &mdash; Unmap a pin from a component in a project.
  - `project_id` (int, required): The project's numeric ID.
  - `cip_id` (int, required): The component-in-project ID.
  - `pin_id` (int, required): The pin ID.

- **`get_component_attributes`** &mdash; Get all attributes of a component in a project.
  - `project_id` (int, required): The project's numeric ID.
  - `cip_id` (int, required): The component-in-project ID.

- **`get_project_permissions`** &mdash; Get permissions configured for a project.
  - `project_id` (int, required): The project's numeric ID.

- **`get_project_labels`** &mdash; Get all labels assigned to a project.
  - `project_id` (int, required): The project's numeric ID.

- **`set_datapoint_renamings`** &mdash; Set alternate keys (renamings) for datapoints in a project.
  - `project_id` (int, required): The project's numeric ID.
  - `renamings` (string, required): JSON string with renaming mappings.

- **`get_project_setpoints`** &mdash; Get all setpoints in a project.
  - `project_id` (int, required): The project's numeric ID.

- **`write_setpoint`** &mdash; Write a setpoint value to a datapoint.
  - `project_id` (int, required): The project's numeric ID.
  - `datapoint_id` (string, required): The datapoint identifier.
  - `value` (float, required): The setpoint value.
  - `priority` (int, optional): BACnet priority (1-16).

- **`delete_setpoint`** &mdash; Delete a setpoint.
  - `project_id` (int, required): The project's numeric ID.
  - `setpoint_id` (int, required): The setpoint ID.

- **`get_setpoint_status`** &mdash; Get the status of a setpoint.
  - `project_id` (int, required): The project's numeric ID.
  - `setpoint_id` (int, required): The setpoint ID.

- **`get_project_weather`** &mdash; Get current weather for a project's location.
  - `project_id` (int, required): The project's numeric ID.
  - `units_system` (string, optional): Unit system.

- **`get_project_weather_forecast`** &mdash; Get weather forecast for a project's location.
  - `project_id` (int, required): The project's numeric ID.
  - `units_system` (string, optional): Unit system.

- **`grant_ai_consent`** &mdash; Grant or revoke consent for the AI Assistant on a project.
  - `project_id` (int, required): The project's numeric ID.
  - `consent` (bool, required): True to grant, False to revoke.

- **`get_plot_views`** &mdash; Get all saved plot views for a project.
  - `project_id` (int, required): The project's numeric ID.

- **`create_plot_view`** &mdash; Create a new plot view.
  - `project_id` (int, required): The project's numeric ID.
  - `plot_config` (string, required): JSON string with the plot configuration.

- **`delete_plot_view`** &mdash; Delete a plot view.
  - `project_id` (int, required): The project's numeric ID.
  - `plot_view_id` (int, required): The plot view ID.

- **`get_logbooks`** &mdash; Get all logbooks in a project.
  - `project_id` (int, required): The project's numeric ID.

- **`create_logbook`** &mdash; Create a new logbook in a project.
  - `project_id` (int, required): The project's numeric ID.
  - `name` (string, required): Logbook name.
  - `description` (string, optional): Logbook description.

- **`get_logbook`** &mdash; Get a specific logbook.
  - `project_id` (int, required): The project's numeric ID.
  - `logbook_id` (int, required): The logbook ID.

- **`delete_logbook`** &mdash; Delete a logbook.
  - `project_id` (int, required): The project's numeric ID.
  - `logbook_id` (int, required): The logbook ID.

- **`create_logbook_entry`** &mdash; Create a new entry in a logbook.
  - `project_id` (int, required): The project's numeric ID.
  - `logbook_id` (int, required): The logbook ID.
  - `title` (string, required): Entry title.
  - `body_text` (string, required): Entry body text.

- **`delete_logbook_entry`** &mdash; Delete a logbook entry.
  - `project_id` (int, required): The project's numeric ID.
  - `logbook_id` (int, required): The logbook ID.
  - `entry_id` (int, required): The entry ID.

- **`get_project_comments`** &mdash; Get all comments for a project.
  - `project_id` (int, required): The project's numeric ID.
  - `page` (int, optional): Page number.
  - `per_page` (int, optional): Items per page.

- **`add_project_comment`** &mdash; Add a comment to a project.
  - `project_id` (int, required): The project's numeric ID.
  - `text` (string, required): Comment text.

- **`delete_project_comment`** &mdash; Delete a project comment.
  - `project_id` (int, required): The project's numeric ID.
  - `comment_id` (int, required): The comment ID.

</details>

<!-- ============================================================ -->

<details>
<summary><strong>Datapoint</strong> (9 tools)</summary>

- **`get_datapoint`** &mdash; Get details about a specific datapoint.
  - `project_id` (int, required): The project's numeric ID.
  - `datapoint_id` (string, required): The datapoint identifier (hash key or alternate key).

- **`update_datapoint`** &mdash; Update datapoint details.
  - `project_id` (int, required): The project's numeric ID.
  - `datapoint_id` (string, required): The datapoint identifier.
  - `description` (string, optional): New description.
  - `unit` (string, optional): New unit string.

- **`delete_datapoint`** &mdash; Delete a datapoint.
  - `project_id` (int, required): The project's numeric ID.
  - `datapoint_id` (string, required): The datapoint identifier.

- **`get_datapoint_timeseries`** &mdash; Get timeseries data for a single datapoint.
  - `project_id` (int, required): The project's numeric ID.
  - `datapoint_id` (string, required): The datapoint identifier.
  - `start` (string, optional): Start time in ISO 8601 format.
  - `end` (string, optional): End time in ISO 8601 format.
  - `max` (int, optional): Maximum number of observations.
  - `samplerate` (string, optional): Resample interval (e.g. `'15min'`, `'1h'`).
  - `interpolation` (string, optional): Interpolation method.
  - `aggregation` (string, optional): Aggregation method.
  - `short` (bool, optional): Return short format.
  - `units_system` (string, optional): Unit system.

- **`get_datapoint_usage`** &mdash; Get usage information for a datapoint (where it's referenced).
  - `project_id` (int, required): The project's numeric ID.
  - `datapoint_id` (string, required): The datapoint identifier.

- **`get_favorite_datapoints`** &mdash; Get all personal favorite datapoints.
  - `project_id` (int, required): The project's numeric ID.

- **`set_favorite_datapoint`** &mdash; Mark a datapoint as a personal favorite.
  - `project_id` (int, required): The project's numeric ID.
  - `datapoint_id` (string, required): The datapoint identifier.

- **`remove_favorite_datapoint`** &mdash; Remove a datapoint from personal favorites.
  - `project_id` (int, required): The project's numeric ID.
  - `datapoint_id` (string, required): The datapoint identifier.

- **`get_datapoint_labels`** &mdash; Get all labels assigned to a datapoint.
  - `project_id` (int, required): The project's numeric ID.
  - `datapoint_id` (string, required): The datapoint identifier.

</details>

<!-- ============================================================ -->

<details>
<summary><strong>Alerts</strong> (5 tools)</summary>

- **`create_threshold_alert`** &mdash; Create a new threshold-based alert.
  - `project_id` (int, required): The project's numeric ID.
  - `name` (string, required): Alert name.
  - `datapoint_id` (string, required): The datapoint to monitor.
  - `info_threshold` (float, optional): Info-level threshold value.
  - `warn_threshold` (float, optional): Warning-level threshold value.
  - `crit_threshold` (float, optional): Critical-level threshold value.
  - `email` (string, optional): Email address for notifications.
  - `telegram_chatid` (string, optional): Telegram chat ID for notifications.
  - `period` (int, optional): Evaluation period in seconds.

- **`update_threshold_alert`** &mdash; Update a threshold alert's configuration.
  - `alert_id` (int, required): The alert ID.
  - `alert_details` (string, required): JSON string with fields to update.

- **`enable_alert`** &mdash; Enable an alert.
  - `alert_id` (int, required): The alert ID.

- **`disable_alert`** &mdash; Disable an alert.
  - `alert_id` (int, required): The alert ID.

- **`delete_alert`** &mdash; Delete an alert.
  - `alert_id` (int, required): The alert ID.

</details>

<!-- ============================================================ -->

<details>
<summary><strong>Tasks</strong> (9 tools)</summary>

- **`get_project_tasks`** &mdash; Get all tasks in a project.
  - `project_id` (int, required): The project's numeric ID.
  - `page` (int, optional): Page number.
  - `per_page` (int, optional): Items per page.

- **`create_task`** &mdash; Create a new task in a project.
  - `project_id` (int, required): The project's numeric ID.
  - `title` (string, required): Task title.
  - `description` (string, optional): Task description.

- **`get_task`** &mdash; Get details of a task.
  - `task_id` (int, required): The task ID.

- **`update_task`** &mdash; Update a task.
  - `task_id` (int, required): The task ID.
  - `task_data` (string, required): JSON string with fields to update.

- **`delete_task`** &mdash; Delete a task.
  - `task_id` (int, required): The task ID.

- **`assign_task`** &mdash; Assign a task to a user.
  - `task_id` (int, required): The task ID.
  - `user_id` (int, required): The user ID to assign.

- **`unassign_task`** &mdash; Unassign a task from a user.
  - `task_id` (int, required): The task ID.
  - `user_id` (int, required): The user ID to unassign.

- **`add_task_comment`** &mdash; Add a comment to a task.
  - `task_id` (int, required): The task ID.
  - `text` (string, required): Comment text.

- **`delete_task_comment`** &mdash; Delete a comment from a task.
  - `task_id` (int, required): The task ID.
  - `comment_id` (int, required): The comment ID.

</details>

<!-- ============================================================ -->

<details>
<summary><strong>Components</strong> (3 tools)</summary>

- **`get_components`** &mdash; Get all available component definitions.

- **`get_component_attribute_definitions`** &mdash; Get all attribute definitions for a component type.
  - `component_id` (int, required): The component definition ID.

- **`get_component_pin_definitions`** &mdash; Get all pins and their attributes for a component type.
  - `component_id` (int, required): The component definition ID.

</details>

<!-- ============================================================ -->

<details>
<summary><strong>Analytics</strong> (21 tools)</summary>

- **`get_analytics_functions`** &mdash; Get all available analysis functions.

- **`get_analytics_function`** &mdash; Get details of a specific analysis function.
  - `function_id` (string, required): The analysis function identifier.

- **`get_analytics_instances`** &mdash; Get all analytics instances in a project.
  - `project_id` (int, required): The project's numeric ID.
  - `page` (int, optional): Page number.
  - `per_page` (int, optional): Items per page.

- **`create_analytics_instance`** &mdash; Create a new analytics instance.
  - `project_id` (int, required): The project's numeric ID.
  - `instance_config` (string, required): JSON string with the instance configuration.

- **`get_analytics_instance`** &mdash; Get an analytics instance's details.
  - `instance_id` (int, required): The instance ID.
  - `project_id` (int, required): The project's numeric ID.

- **`update_analytics_instance`** &mdash; Update an analytics instance.
  - `instance_id` (int, required): The instance ID.
  - `project_id` (int, required): The project's numeric ID.
  - `instance_config` (string, required): JSON string with fields to update.

- **`delete_analytics_instance`** &mdash; Delete an analytics instance.
  - `instance_id` (int, required): The instance ID.
  - `project_id` (int, required): The project's numeric ID.

- **`enable_analytics_instance`** &mdash; Enable an analytics instance.
  - `instance_id` (int, required): The instance ID.
  - `project_id` (int, required): The project's numeric ID.

- **`disable_analytics_instance`** &mdash; Disable an analytics instance.
  - `instance_id` (int, required): The instance ID.
  - `project_id` (int, required): The project's numeric ID.

- **`trigger_analytics_instance`** &mdash; Manually trigger an analytics instance to run.
  - `instance_id` (int, required): The instance ID.
  - `project_id` (int, required): The project's numeric ID.

- **`get_analytics_instance_result`** &mdash; Get results for an analytics instance.
  - `instance_id` (int, required): The instance ID.
  - `project_id` (int, required): The project's numeric ID.
  - `start` (string, optional): Start time in ISO 8601 format.
  - `end` (string, optional): End time in ISO 8601 format.
  - `units_system` (string, optional): Unit system.
  - `currency_system` (string, optional): Currency system.

- **`get_analytics_instance_status`** &mdash; Get the status of an analytics instance.
  - `instance_id` (int, required): The instance ID.
  - `project_id` (int, required): The project's numeric ID.

- **`get_analytics_kpi_aggregation`** &mdash; Get aggregated KPI results across a project.
  - `project_id` (int, required): The project's numeric ID.

- **`get_analytics_components_kpi`** &mdash; Get aggregated KPI results per component.
  - `project_id` (int, required): The project's numeric ID.

- **`get_analytics_kpi_overview`** &mdash; Get a high-level KPI overview for a project.
  - `project_id` (int, required): The project's numeric ID.

- **`get_analytics_status`** &mdash; Get the analytics status overview for a project.
  - `project_id` (int, required): The project's numeric ID.

- **`get_technical_monitoring`** &mdash; Get technical monitoring data for a project.
  - `project_id` (int, required): The project's numeric ID.
  - `start` (string, optional): Start time in ISO 8601 format.
  - `end` (string, optional): End time in ISO 8601 format.
  - `units_system` (string, optional): Unit system.

- **`get_energy_efficiency`** &mdash; Get energy efficiency analysis data for a project.
  - `project_id` (int, required): The project's numeric ID.
  - `start` (string, optional): Start time in ISO 8601 format.
  - `end` (string, optional): End time in ISO 8601 format.
  - `units_system` (string, optional): Unit system.

- **`get_operational_optimization`** &mdash; Get operational optimization data for a project.
  - `project_id` (int, required): The project's numeric ID.
  - `start` (string, optional): Start time in ISO 8601 format.
  - `end` (string, optional): End time in ISO 8601 format.
  - `units_system` (string, optional): Unit system.

- **`get_compliance`** &mdash; Get compliance data for a project.
  - `project_id` (int, required): The project's numeric ID.

- **`get_component_results`** &mdash; Get analytics results for a specific component in a project.
  - `cip_id` (int, required): The component-in-project ID.
  - `project_id` (int, required): The project's numeric ID.
  - `units_system` (string, optional): Unit system.
  - `currency_system` (string, optional): Currency system.

</details>

<!-- ============================================================ -->

<details>
<summary><strong>Controls</strong> (10 tools)</summary>

- **`get_controls_apps`** &mdash; Get all available controls apps.

- **`get_controls_app`** &mdash; Get details of a specific controls app.
  - `app_id` (string, required): The controls app identifier.

- **`get_controls_instances`** &mdash; Get all controls instances in a project.
  - `project_id` (int, required): The project's numeric ID.
  - `page` (int, optional): Page number.
  - `per_page` (int, optional): Items per page.

- **`create_controls_instance`** &mdash; Create a new controls instance.
  - `project_id` (int, required): The project's numeric ID.
  - `instance_config` (string, required): JSON string with the controls instance configuration.

- **`get_controls_instance`** &mdash; Get a controls instance's details.
  - `instance_id` (int, required): The instance ID.
  - `project_id` (int, required): The project's numeric ID.

- **`update_controls_instance`** &mdash; Update a controls instance.
  - `instance_id` (int, required): The instance ID.
  - `project_id` (int, required): The project's numeric ID.
  - `instance_config` (string, required): JSON string with fields to update.

- **`delete_controls_instance`** &mdash; Delete a controls instance.
  - `instance_id` (int, required): The instance ID.
  - `project_id` (int, required): The project's numeric ID.

- **`enable_controls_instance`** &mdash; Enable a controls instance.
  - `instance_id` (int, required): The instance ID.
  - `project_id` (int, required): The project's numeric ID.

- **`disable_controls_instance`** &mdash; Disable a controls instance.
  - `instance_id` (int, required): The instance ID.
  - `project_id` (int, required): The project's numeric ID.

- **`get_controls_instance_status`** &mdash; Get the status of a controls instance.
  - `instance_id` (int, required): The instance ID.
  - `project_id` (int, required): The project's numeric ID.

</details>

## Usage examples

### Check API connectivity

> "Ping the aedifion API to check if it's available."

### Browse projects and data

> "Show me all projects in my company."
>
> "List all datapoints in project 42 that contain 'temperature' in their name."

### Query timeseries data

> "Get the temperature readings for datapoint 'bacnet500-4120-External-Air-Temperature' in project 42 from the last 24 hours, resampled to 15-minute intervals."

### Analytics

> "What analysis functions are available? Show me the KPI overview for project 42."
>
> "Get the energy efficiency analysis for project 42 for the last month."

### Alerts

> "Create a threshold alert on the room temperature datapoint in project 42 that warns at 26C and goes critical at 30C."

### Building controls

> "List all active controls instances in project 42 and show their current status."

### Weather

> "What's the current weather at the building location for project 42?"

## Authentication

The server supports two authentication methods:

1. **Username/Password** (recommended): Set `AEDIFION_USERNAME` and `AEDIFION_PASSWORD`. The server automatically obtains and refreshes bearer tokens via `POST /v2/user/token`.

2. **Pre-obtained token**: Set `AEDIFION_TOKEN` with a valid bearer token. Useful for short-lived sessions or when credentials shouldn't be stored.

Token refresh happens automatically when a `401 Unauthorized` response is received.

## Error handling

The server wraps all API errors into clean, structured error messages. Instead of raw HTTP exceptions or tracebacks, tools return human-readable error descriptions including:

- The HTTP status code
- The API error message
- The endpoint that failed

This makes it easy for AI assistants to understand and communicate errors to users.

## Development

### Setup

```bash
git clone https://github.com/bbruhn91/mcp-server-aedifion.git
cd mcp-server-aedifion
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
```

### Running locally

```bash
# With environment variables
AEDIFION_USERNAME=user@example.com AEDIFION_PASSWORD=pass mcp-server-aedifion

# Or with a .env file
cp .env.example .env
# Edit .env with your credentials
mcp-server-aedifion
```

### Testing

```bash
pytest -v
```

### Linting

```bash
ruff check src/ tests/
ruff format --check src/ tests/
```

### Testing with MCP Inspector

```bash
npx @modelcontextprotocol/inspector mcp-server-aedifion
```

## Architecture

```
src/mcp_server_aedifion/
  __init__.py       # Package init
  client.py         # HTTP client with auth handling and structured errors
  server.py         # MCP server with tool definitions and error handling
tests/
  test_client.py    # Client unit tests (auth, requests, errors)
  test_server.py    # Server tests (tool registration, error handling)
```

- **`client.py`** &mdash; Async HTTP client built on `httpx`. Handles Basic Auth -> bearer token exchange, automatic token refresh on 401, and raises structured `AedifionError` exceptions with status codes and API error details.
- **`server.py`** &mdash; MCP server built with `FastMCP`. Registers 95+ tools covering all 12 API categories. Each tool is wrapped with error handling that converts exceptions into clean error messages.

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for development guidelines.

## License

MIT &mdash; see [LICENSE](LICENSE).

TDQS

B3.1/5.0

Scored across 123 tools

Disambiguation4/5

Most tools are clearly distinct, targeting specific resources and actions like projects, datapoints, analytics, tasks, and AI. However, some overlap exists, such as multiple 'get_' tools for different aspects of analytics or controls, which could cause confusion if an agent doesn't carefully read descriptions. Overall, the naming and domain separation are strong enough to minimize misselection.

Naming Consistency5/5

Tool names follow a highly consistent verb_noun pattern throughout, using snake_case uniformly. Verbs like 'create_', 'delete_', 'get_', 'update_', 'enable_', 'disable_' are applied predictably across resources, making the set easy to navigate and understand. There are no deviations in style or convention.

Tool Count2/5

With 123 tools, the count is excessive for a single server, making it overwhelming and difficult for an agent to manage. While the domain (building management and analytics) is broad, this many tools suggests poor scoping, likely leading to cognitive overload and inefficiency in tool selection, even if the coverage is comprehensive.

Completeness5/5

The tool set provides comprehensive CRUD and lifecycle coverage across all major domains: projects, datapoints, analytics, controls, tasks, AI, users, and more. There are no obvious gaps; for example, each resource has create, read, update, and delete operations, and workflows are fully supported with enabling, disabling, triggering, and status checks.

Maintenance

ActivityInactive
ResponsivenessNo issues