Openhab MCP Server

yes it is the AI Agent:

if I use the docke mcp gateway this works fine, but only with public mcp servers what are in the docker catalog.

Hi,

i have still some issues with the docker container (after i read all the comments here).
First of all: there is no container log to get a error message
would be easier to have as least “something”.

So i have no clue, if the container is able to reach the openhab-container (and ping&curl ist not installable inside the container to verify it)

But is there a usable endpoint if the openhab-mcp-container is running (My container got own static IP) something like
GET http://IPofContainer:8080/mcp or else just to get some kind of a lifesign?
fyi: I used the GitHub - tdeckers/openhab-mcp: An MCP server for OpenHAB repo.

I recommend to use MCP inspector: MCP Inspector - Model Context Protocol

It is an easy way to connect to your Server locally so that is good for quick debugging. If the connection to your server works you can also invoke tool calls. This should produce errors in the server log if your container cannot reach OH.

Also you may want to set the log level to DEBUG in openhab_mcp_server.py in line 18.

Hi team, i wondered if anyone had looked into the work being done over at Agntcy, seems like it could be a great way to support this evolving field and both A2A and MCP are supported.

I think I found your issue. It seems that FASTMCP_HOST is no longer working in the latest mcp versions. I will update the code soon to get this fixed.

Oh thanks! :slight_smile: (sorry, that i didn’t answer but i had not enough time, to debug this project locally)

It would be cool, if debug-logs would be available, if i start the container with a ENV-variable (DEBUG=true for example), because my container runs on my NAS and next time (if needed ^^) i want to give better input.

Yes there are a few things that need to be cleaned up including some no longer needed files and the README. I think I will also add some variables to specify the interface and port the server listens on (only required if the defaults don’t work for you) and also the log level. I will probably also lock the versions of the requirements so that the behaviour should be more stable in the future.

I did some fundamental restructurings in my repo, added somenew env variables and also updated the README. I hope that it should be much easier to set up a new installation now.

I just realized that tdeckers also had updates in his repo (the one I forked from) but I think my changes might have diverged too far


https://github.com/DrRSatzteil/openhab-mcp

2 Likes

Works on first try today. Tried it yesterday unsuccessfully. Maybe your new commited changes made it run.

Have it working locally on macOS, python 3.13.3 in combination with LM Studio and a locally running LLM (openai/gpt-oss-20b).

Integrated in to the LM Studio Chat via

{
  "mcpServers": {
    "openhab": {
      "url": "http://localhost:8000/mcp"
    }
  }
}

Looks and feels awesome, my first MCP experience. Now I need to find out, what I can do with it. :grinning_face_with_smiling_eyes:

Example:
Question: “Wieviele Items gibt es, die sich auf Luftfeuchtigkeit beziehen?”
Answer:

openai/gpt-oss-20b
Thought for a brief moment

list_items

mcp/openhab


Es gibt 11 Items, die sich auf Luftfeuchtigkeit beziehen.

Question: “Nennen mir die 11 Items.”
Answer:

openai/gpt-oss-20b
Thought for a brief moment

list_items

mcp/openhab


Hier die Namen der 11 Luftfeuchtigkeits‑Items:

pDGBueroKlimaSensor_Humidity
pDGGaestezimmerKlima_Humidity
pEGVorgartenSensor_Humidity
pEGWCKlima_Humidity
pEGWZWandThermostat_Humidity
pOGBadHZGruppe_Humidity
pOGKiZ1Heizung_ActualHumidity
pOGKiZ2KlimaSensor_Humidity
pOGSZHZGruppe_Humidity
pDGGaestezimmerKlima_Pressure (dieses ist eigentlich Druck, aber im Listing erscheint mit Humidity‑Tag – falls nötig ausklammern)
pEGWCKlima_Pressure (Ă€hnlich wie 10, ggf. ausklammern)
Falls du nur reine Luftfeuchtigkeitswerte ohne Druck‑Items möchtest, wĂ€ren die 9 ersten eindeutig.

:+1: :+1:

1 Like

Is there any existing android ai which can connect to an mcp server?

Can confirm this working now also on Codex cli. Thanks for the effort!

to configure codex cli, edit your .toml file
/home/[YOURLOGGEDONUSER]/.codex/config.toml

[mcp_servers.openhab]
url = “http://[YOURMCPSERVER]:8080/mcp”

1 Like

I’ve been playing around with Claude and openHAB MCP server. Claude says it has some issues, so I asked it to generate a report.

Anyone else has issues with send_command, update_item_state, create_rule or create_script?

openHAB MCP Implementation - Bug Report

Date: January 10, 2026
Reporter: Claude (AI Assistant)
Context: Implementing MiLight automation with PIR sensors, timers, and dynamic color temperature based on sun elevation


Executive Summary

During an automation implementation session, several issues were encountered with the openHAB MCP tools. The most critical issues prevent rule creation entirely, while others cause confusing error messages despite successful command execution.


Issue 1: send_command Tool Returns Validation Error Despite Success

Severity: Medium (Functional but confusing)

Description

The send_command tool returns a Pydantic validation error even when the command is successfully executed on the openHAB server.

Steps to Reproduce

Tool call: send_command
Parameters:
  - item_name: "Milight_ID0x2_G1_Level"
  - command: "50"

Expected Result

Success response confirming command was sent.

Actual Result

Error executing tool send_command: 1 validation error for send_commandOutput
result
  Input should be a valid dictionary [type=dict_type, input_value=True, input_type=bool]
    For further information visit https://errors.pydantic.dev/2.12/v/dict_type

Evidence of Success Despite Error

Immediately after the error, calling get_item_state confirms the command was executed:

get_item_state("Milight_ID0x2_G1_Level") -> "50"

Root Cause Analysis

The openHAB REST API likely returns true (boolean) for successful POST requests to /rest/items/{itemname}. The Pydantic model for send_commandOutput expects a dictionary but receives a boolean.

Suggested Fix

# Current (problematic):
class send_commandOutput(BaseModel):
    result: dict

# Suggested fix:
class send_commandOutput(BaseModel):
    result: Union[dict, bool, None]

Or handle the boolean response explicitly in the tool implementation before returning.


Issue 2: update_item_state Tool Returns Same Validation Error

Severity: Medium (Functional but confusing)

Description

Same issue as send_command - the tool works but returns a validation error.

Steps to Reproduce

Tool call: update_item_state
Parameters:
  - item_name: "Milight_ID0x2_G1_Level"
  - state: "50"

Actual Result

Error executing tool update_item_state: 1 validation error for update_item_stateOutput
result
  Input should be a valid dictionary [type=dict_type, input_value=True, input_type=bool]

Root Cause

Same as Issue 1 - boolean response not handled by Pydantic model.


Issue 3: create_rule Tool Fails Completely

Severity: Critical (Blocks functionality)

Description

The create_rule tool fails with an AttributeError, preventing any rule creation through the MCP interface.

Steps to Reproduce

Tool call: create_rule
Parameters:
  - rule: {
      "uid": "MiLight_Test1",
      "name": "MiLight Test Rule",
      "tags": [],
      "actions": [],
      "triggers": [],
      "conditions": [],
      "configuration": {},
      "configDescriptions": []
    }

Expected Result

Rule created successfully.

Actual Result

Error executing tool create_rule: 'RuleCreate' object has no attribute 'raise_for_errors'

Analysis

The error suggests that somewhere in the tool implementation, there’s a call to .raise_for_errors() on a RuleCreate Pydantic model object. This method doesn’t exist on Pydantic models.

Possible Causes

  1. Confusion between a Pydantic model and an HTTP response object
  2. Missing error handling wrapper
  3. Incorrect method call on the model instead of the API response

Suggested Investigation

Look for code similar to:

rule = RuleCreate(**rule_data)
rule.raise_for_errors()  # This line is wrong

Should probably be:

rule = RuleCreate(**rule_data)
response = api_client.post("/rest/rules", json=rule.dict())
response.raise_for_status()  # This is correct for httpx/requests

Issue 4: create_script Tool Has Incorrect Parameter Handling

Severity: Critical (Blocks functionality)

Description

The create_script tool reports a missing required argument even when all parameters are provided.

Steps to Reproduce

Tool call: create_script
Parameters:
  - script_id: "milight_calc_ctemp"
  - script_type: "application/javascript;version=ECMAScript-2021"
  - content: "// script content here..."

Actual Result

Error executing tool create_script: OpenHABClient.create_script() missing 1 required positional argument: 'content'

Analysis

Despite content being provided in the parameters, the method reports it as missing. This suggests:

  1. Parameter name mismatch between MCP tool definition and actual method signature
  2. Incorrect parameter passing in the tool wrapper

Suggested Investigation

Check that the MCP tool parameter names match the OpenHABClient.create_script() method signature exactly.


Summary Table

Tool Issue Severity Workaround
send_command Returns validation error despite success Medium Ignore error, verify with get_item_state
update_item_state Returns validation error despite success Medium Ignore error, verify with get_item_state
create_rule Fails with AttributeError Critical Use file-based configuration instead
create_script Missing argument error Critical Use file-based configuration instead

Impact on Workflow

Due to these issues, rule and script creation had to be done via file-based configuration rather than the MCP interface. This required:

  1. Generating DSL rules files manually
  2. Providing files to the user to copy to their openHAB server
  3. Unable to test/iterate on rules programmatically

The send_command and update_item_state issues are workable (commands do execute), but the error messages are confusing and could lead users to believe commands failed when they actually succeeded.


Environment Information

  • openHAB Version: 5.0 (based on available bindings documentation)
  • MCP Implementation: openHAB MCP (version unknown)
  • Items tested: MiLight RGB_CCT and CCT lamps via EspMilightHub binding

Recommendations

  1. High Priority: Fix create_rule and create_script tools to enable programmatic rule management
  2. Medium Priority: Fix response handling in send_command and update_item_state to properly handle boolean responses
  3. Enhancement: Add response details to successful commands (e.g., return the new item state after a command)

Report generated during MiLight automation implementation session

Two questions: which MCP server did you use? The tdecker repo or mine? Which openHAB version are you using? I’ve not yet tested this on OH5 so there might be issues.

I’m using your repo. No docker but installed in it’s own Python virtual env.

Ok good. Which OH version? Can you execute the tests? There are a few rule test cases that worked fine for me (on OH 4)

openHAB 5.0.2

I was using the repo from your first post. Now I’ve changed to your repo and run the 2 tests:

(venv) [stefan@spin openhab-mcp]$ OPENHAB_URL=http://openhab.xxx.net:8080 OPENHAB_API_TOKEN=oh.ClaudeDesktop.WxxxxBUA python3 tests/test_items.py
.
E......E
======================================================================
ERROR: test_create_item_with_all_fields (__main__.TestOpenHABItems.test_create_item_with_all_fields)
Test creating an item with all possible fields and verify they are set correctly.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/stefan/git/openhab-mcp/tests/test_items.py", line 369, in test_create_item_with_all_fields
    self.assertIn("Equipment_Lighting", created_item["semanticTags"][0]["uid"])
                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^
IndexError: list index out of range

======================================================================
ERROR: test_update_item_with_none_or_empty_values (__main__.TestOpenHABItems.test_update_item_with_none_or_empty_values)
Test updating an item with None or empty list values to remove properties
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/stefan/git/openhab-mcp/tests/test_items.py", line 444, in test_update_item_with_none_or_empty_values
    self.assertIn("Equipment_Lighting", created_item["semanticTags"][0]["uid"])
                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^
IndexError: list index out of range

----------------------------------------------------------------------
Ran 9 tests in 58.031s

FAILED (errors=2)
(venv) [stefan@spin openhab-mcp]$ 
(venv) [stefan@spin openhab-mcp]$ OPENHAB_URL=http://openhab.xxx.net:8080 OPENHAB_API_TOKEN=oh.ClaudeDesktop.WxxxxECBUA python3 tests/test_rules.py 
......
----------------------------------------------------------------------
Ran 6 tests in 0.426s

OK

Whoops sorry I got a bit confused
 I’m also running 5.0.2, not 4.x


So I just tried to create a rule on my end and it seems to be broken for me as well
 I will have to investigate what’s wrong here but this does not seem to be a specific problem with your setup.

1 Like

Ok, I cannot reproduce all of your errors here but I found some other problems that might at least in parts be related to your observations for item updates/commands.

Can you please try to run the latest and greatest code on the main branch? All test cases are green here. In the meantime I switched to OH 5.1.1 but I don’t think there there were any major API changes that might be breaking here


send_command and update_item_state are working correct now.

(venv) [stefan@spin openhab-mcp]$ OPENHAB_URL=http://openhab.xxx.net:8080 OPENHAB_API_TOKEN=oh.ClaudeDesktop.WNa7OnBexxxanJ3XfU4ECBUA pytest tests/
============================================================================================================= test session starts ==============================================================================================================
platform linux -- Python 3.13.11, pytest-9.0.2, pluggy-1.6.0
rootdir: /home/stefan/git/openhab-mcp
configfile: pyproject.toml
plugins: anyio-4.12.0
collected 16 items                                                                                                                                                                                                                             

tests/test_items.py .F......F                                                                                                                                                                                                            [ 56%]
tests/test_rules.py .......                                                                                                                                                                                                              [100%]

=================================================================================================================== FAILURES ===================================================================================================================
______________________________________________________________________________________________ TestOpenHABItems.test_create_item_with_all_fields _______________________________________________________________________________________________

self = <tests.test_items.TestOpenHABItems testMethod=test_create_item_with_all_fields>

    def test_create_item_with_all_fields(self):
        """Test creating an item with all possible fields and verify they are set correctly."""
        # Create a group item first to use in group_names
        group_name = f"{self.test_prefix}TestGroup"
        group_item = self.client.create_item(ItemCreate(
            name=group_name,
            type="Group",
            label="Test Group",
            groupType="Dimmer",
            function={"name": "AVG"}
        ))
    
        # Create an item with all possible fields
        item_name = f"{self.test_prefix}FullItem"
        item = ItemCreate(
            name=item_name,
            type="Dimmer",
            label="Test Full Dimmer Item",
            category="Light",
            groupNames=[group_name],
            semanticTags=["Equipment_Lighting"],
            nonSemanticTags=["TestTag", "Dimmable"],
            metadata={
                "commandDescription": ItemMetadata(value=" ", config={
                    "options": "ON=Switch ON, OFF=Switch OFF, INCREASE=Increase, DECREASE=Decrease"
                }),
                "stateDescription": ItemMetadata(value=" ", config={
                    "minimum": 0,
                    "maximum": 100,
                    "step": 5,
                    "pattern": "%d%%",
                    "readOnly": False,
                    "options": "0=Off, 100=Full"
                }),
                "unit": ItemMetadata(value="%")
            }
        )
    
        # Create the item
        created_item = self.client.create_item(item)
    
        try:
            # Verify the item was created with all fields
            self.assertEqual(created_item["name"], item_name)
            self.assertEqual(created_item["type"], "Dimmer")
            self.assertEqual(created_item["label"], "Test Full Dimmer Item")
            self.assertEqual(created_item["category"], "Light")
    
            # Verify group membership
            self.assertIn(group_name, created_item["groupNames"])
    
            # Get the group to verify its properties
            group = self.client.get_item(group_name)
            self.assertEqual(group["groupType"], "Dimmer")
            self.assertEqual(group["function"]["name"], "AVG")
    
            # Verify tags
            self.assertIn("TestTag", created_item["nonSemanticTags"])
            self.assertIn("Dimmable", created_item["nonSemanticTags"])
    
>           self.assertIn("Equipment_Lighting", created_item["semanticTags"][0]["uid"])
                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           IndexError: list index out of range

tests/test_items.py:369: IndexError
_________________________________________________________________________________________ TestOpenHABItems.test_update_item_with_none_or_empty_values __________________________________________________________________________________________

self = <tests.test_items.TestOpenHABItems testMethod=test_update_item_with_none_or_empty_values>

    def test_update_item_with_none_or_empty_values(self):
        """Test updating an item with None or empty list values to remove properties"""
        # First create an item with various properties
        item_name = "TestItem_UpdateWithNone"
        group_name = "TestItem_TestGroupForUpdate"
    
        # Create a group first
        self.client.create_item(ItemCreate(
            name=group_name,
            type="Group",
            label="Test Group for Update",
            groupType="Dimmer",
            function={"name": "AVG"}
        ))
    
        # Create initial item with all properties
        item = ItemCreate(
            name=item_name,
            type="Dimmer",
            label="Test Item for Update",
            category="Light",
            groupNames=[group_name],
            semanticTags=["Equipment_Lighting"],
            nonSemanticTags=["TestTag", "Dimmable"],
            metadata={
                "stateDescription": ItemMetadata(value=" ", config={
                    "pattern": "%d%%",
                    "readOnly": False,
                    "options": "0=Off, 100=Full"
                })
            }
        )
    
        # Create the item
        created_item = self.client.create_item(item)
    
        try:
            # Verify the item was created with all fields
            self.assertEqual(created_item["name"], item_name)
            self.assertEqual(created_item["type"], "Dimmer")
            self.assertEqual(created_item["label"], "Test Item for Update")
            self.assertEqual(created_item["category"], "Light")
            self.assertIn(group_name, created_item["groupNames"])
            self.assertIn("TestTag", created_item["nonSemanticTags"])
>           self.assertIn("Equipment_Lighting", created_item["semanticTags"][0]["uid"])
                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           IndexError: list index out of range

tests/test_items.py:445: IndexError
=========================================================================================================== short test summary info ============================================================================================================
FAILED tests/test_items.py::TestOpenHABItems::test_create_item_with_all_fields - IndexError: list index out of range
FAILED tests/test_items.py::TestOpenHABItems::test_update_item_with_none_or_empty_values - IndexError: list index out of range
======================================================================================================== 2 failed, 14 passed in 58.09s =========================================================================================================

Some tests are still failing.