Aedifion MCP Server
The Aedifion MCP Server provides AI assistants with 95+ tools to interact with the aedifion cloud API for building IoT data management, analytics, and control across these key areas:
Data & Timeseries: Query, write, and delete IoT timeseries data with resampling, interpolation, aggregation, and multi-unit support; manage datapoint details, favorites, labels, and alternate keys.
Project Management: Full CRUD for projects, including managing datapoints, alerts, tags, components, setpoints, permissions, plot views, logbooks, and comments.
User & Company Administration: View/update user profiles, permissions, and roles; manage company details, roles, labels, and users.
Realm Administration: List all companies, projects, and users across the realm (with pagination).
Analytics & KPIs: Manage analytics function instances (create, run, enable/disable); retrieve KPI overviews, energy efficiency, technical monitoring, operational optimization, and compliance data.
Alerts: Create, update, enable/disable, and delete threshold-based alerts with email/Telegram notifications.
Building Controls: Manage controls app instances — create, configure, enable/disable, and check status.
AI Assistant: Create and manage AI conversation threads and send messages to the aedifion AI assistant.
Tasks: Create, assign, update, delete, and comment on project tasks for team collaboration.
Component Definitions: Browse reusable component types, pin definitions, and attribute definitions.
Weather: Retrieve current conditions and forecasts for a building's location.
System & Diagnostics: Ping the API, check version, list all endpoints, and retrieve label/unit system definitions.
Allows configuring alerts to send notifications to Telegram channels or users via chat ID.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Aedifion MCP Serverget the temperature timeseries for the Berlin office project"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-server-aedifion
An MCP (Model Context Protocol) server that provides tools for interacting with the aedifion 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)
uv pip install git+https://github.com/bbruhn91/mcp-server-aedifion.gitUsing pip
pip install git+https://github.com/bbruhn91/mcp-server-aedifion.gitFrom source
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):
cp .env.example .env
# Edit .env with your credentialsVariable | Required | Default | Description |
| Yes* | — | Your aedifion account email |
| Yes* | — | Your aedifion account password |
| No | — | Pre-obtained bearer token (alternative to username/password) |
| No |
| API base URL |
* Required unless AEDIFION_TOKEN is set.
Claude Desktop
Add the server to your Claude Desktop configuration (claude_desktop_config.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:
{
"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
claude mcp add aedifion -- mcp-server-aedifionOr with environment variables inline:
claude mcp add aedifion \
--env AEDIFION_USERNAME=your-email \
--env AEDIFION_PASSWORD=your-password \
-- mcp-server-aedifionOther 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.
ping— Ping the aedifion API server to check availability.get_api_version— Get the aedifion API version.get_endpoints— List all available API endpoints.get_label_definitions— Get all label definitions available in aedifion.get_label_systems— Get available label/unit systems (e.g. SI, imperial).
get_user— Get the currently logged-in user's details.update_user— Update the logged-in user's details.first_name(string, optional): New first name.last_name(string, optional): New last name.
get_user_permissions— Get the logged-in user's project permissions.get_user_roles— Get the logged-in user's roles.
ai_get_threads— 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— Get all messages in an AI conversation thread.thread_id(string, required): The thread identifier.
ai_chat— 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— Delete an AI conversation thread.thread_id(string, required): The thread identifier.
get_company— Get the current user's company details including projects and users.update_company— Update company details.name(string, optional): New company name.description(string, optional): New company description.
get_company_roles— Get all roles defined in the company.get_company_permissions— Get all project permissions granted to the company.get_company_labels— Get all labels assigned to the company.create_project— Create a new project in the company.name(string, required): Project name.description(string, optional): Project description.
create_user— 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— Get details of a user within the company.user_id(int, required): The user's numeric ID.
delete_company_user— Delete a user from the company.user_id(int, required): The user's numeric ID.
get_realm_companies— Get all companies in the realm.page(int, optional): Page number.per_page(int, optional): Items per page.
get_realm_projects— Get all projects in the realm.page(int, optional): Page number.per_page(int, optional): Items per page.
get_realm_users— Get all users in the realm.page(int, optional): Page number.per_page(int, optional): Items per page.
get_project— Get a project's details.project_id(int, required): The project's numeric ID.
update_project— 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— 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— 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— 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— 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— 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— 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— 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— 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— Delete a tag.project_id(int, required): The project's numeric ID.tag_id(string, required): The tag identifier.
get_project_components— 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— 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— 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— 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— 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— 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— 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— 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— Get permissions configured for a project.project_id(int, required): The project's numeric ID.
get_project_labels— Get all labels assigned to a project.project_id(int, required): The project's numeric ID.
set_datapoint_renamings— 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— Get all setpoints in a project.project_id(int, required): The project's numeric ID.
write_setpoint— 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— Delete a setpoint.project_id(int, required): The project's numeric ID.setpoint_id(int, required): The setpoint ID.
get_setpoint_status— 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— 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— 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— 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— Get all saved plot views for a project.project_id(int, required): The project's numeric ID.
create_plot_view— 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— Delete a plot view.project_id(int, required): The project's numeric ID.plot_view_id(int, required): The plot view ID.
get_logbooks— Get all logbooks in a project.project_id(int, required): The project's numeric ID.
create_logbook— 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— Get a specific logbook.project_id(int, required): The project's numeric ID.logbook_id(int, required): The logbook ID.
delete_logbook— Delete a logbook.project_id(int, required): The project's numeric ID.logbook_id(int, required): The logbook ID.
create_logbook_entry— 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— 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— 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— Add a comment to a project.project_id(int, required): The project's numeric ID.text(string, required): Comment text.
delete_project_comment— Delete a project comment.project_id(int, required): The project's numeric ID.comment_id(int, required): The comment ID.
get_datapoint— 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— 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— Delete a datapoint.project_id(int, required): The project's numeric ID.datapoint_id(string, required): The datapoint identifier.
get_datapoint_timeseries— 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— 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— Get all personal favorite datapoints.project_id(int, required): The project's numeric ID.
set_favorite_datapoint— 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— 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— Get all labels assigned to a datapoint.project_id(int, required): The project's numeric ID.datapoint_id(string, required): The datapoint identifier.
create_threshold_alert— 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— 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— Enable an alert.alert_id(int, required): The alert ID.
disable_alert— Disable an alert.alert_id(int, required): The alert ID.
delete_alert— Delete an alert.alert_id(int, required): The alert ID.
get_project_tasks— 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— 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— Get details of a task.task_id(int, required): The task ID.
update_task— Update a task.task_id(int, required): The task ID.task_data(string, required): JSON string with fields to update.
delete_task— Delete a task.task_id(int, required): The task ID.
assign_task— Assign a task to a user.task_id(int, required): The task ID.user_id(int, required): The user ID to assign.
unassign_task— 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— Add a comment to a task.task_id(int, required): The task ID.text(string, required): Comment text.
delete_task_comment— Delete a comment from a task.task_id(int, required): The task ID.comment_id(int, required): The comment ID.
get_components— Get all available component definitions.get_component_attribute_definitions— Get all attribute definitions for a component type.component_id(int, required): The component definition ID.
get_component_pin_definitions— Get all pins and their attributes for a component type.component_id(int, required): The component definition ID.
get_analytics_functions— Get all available analysis functions.get_analytics_function— Get details of a specific analysis function.function_id(string, required): The analysis function identifier.
get_analytics_instances— 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— 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— 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— 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— Delete an analytics instance.instance_id(int, required): The instance ID.project_id(int, required): The project's numeric ID.
enable_analytics_instance— Enable an analytics instance.instance_id(int, required): The instance ID.project_id(int, required): The project's numeric ID.
disable_analytics_instance— Disable an analytics instance.instance_id(int, required): The instance ID.project_id(int, required): The project's numeric ID.
trigger_analytics_instance— 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— 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— 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— Get aggregated KPI results across a project.project_id(int, required): The project's numeric ID.
get_analytics_components_kpi— Get aggregated KPI results per component.project_id(int, required): The project's numeric ID.
get_analytics_kpi_overview— Get a high-level KPI overview for a project.project_id(int, required): The project's numeric ID.
get_analytics_status— Get the analytics status overview for a project.project_id(int, required): The project's numeric ID.
get_technical_monitoring— 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— 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— 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— Get compliance data for a project.project_id(int, required): The project's numeric ID.
get_component_results— 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.
get_controls_apps— Get all available controls apps.get_controls_app— Get details of a specific controls app.app_id(string, required): The controls app identifier.
get_controls_instances— 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— 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— 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— 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— Delete a controls instance.instance_id(int, required): The instance ID.project_id(int, required): The project's numeric ID.
enable_controls_instance— Enable a controls instance.instance_id(int, required): The instance ID.project_id(int, required): The project's numeric ID.
disable_controls_instance— Disable a controls instance.instance_id(int, required): The instance ID.project_id(int, required): The project's numeric ID.
get_controls_instance_status— Get the status of a controls instance.instance_id(int, required): The instance ID.project_id(int, required): The project's numeric ID.
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:
Username/Password (recommended): Set
AEDIFION_USERNAMEandAEDIFION_PASSWORD. The server automatically obtains and refreshes bearer tokens viaPOST /v2/user/token.Pre-obtained token: Set
AEDIFION_TOKENwith 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
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
# 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-aedifionTesting
pytest -vLinting
ruff check src/ tests/
ruff format --check src/ tests/Testing with MCP Inspector
npx @modelcontextprotocol/inspector mcp-server-aedifionArchitecture
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— Async HTTP client built onhttpx. Handles Basic Auth -> bearer token exchange, automatic token refresh on 401, and raises structuredAedifionErrorexceptions with status codes and API error details.server.py— MCP server built withFastMCP. 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 for development guidelines.
License
MIT — see LICENSE.
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/bbruhn91/mcp-server-aedifion'
If you have feedback or need assistance with the MCP directory API, please join our Discord server