Cockpit MCP server

Post at — Oct 12, 2026

Cockpit MCP server

The cockpit-mcp project builds an MCP server on top of Cockpit (https://github.com/cockpit-project/cockpit) so that an agent can drive a Linux host the same careful way a human would use Cockpit.

Motivation

Cockpit offers a nice way to interact with and administer your Linux system in the web browser. Especially for parts of the system you don’t know by heart because you do not deal with them, Cockpit is also useful for experienced users. Another aspect of Cockpit is that someone designed and selected the necessary and most sensible options for an operation, while a standard command line tool offers all options. For example, if you want to format a disk, gpt is preselected and no exotic options for the creation of file systems, like inode size, are accessible. This is, in my opinion, exactly what I want for an MCP server, as LLMs get sidetracked by exotic options and tend to set them. Also, since the base training data contained a lot of old documentation, an LLM might choose an MBR with ext3 if tasked with creating a filesystem.

Implementation

Connecting to an external Cockpit server is fairly easy, as this is done via WebSocket, which is accessible with standard tools, and so one can fairly easily get the list of packages in Cockpit, like the file system or user management packages. But unfortunately the easy part ends here, as the Cockpit server only delivers a set of empty index.html pages (one per package) plus their minified JavaScript bundles, which build the actual interface at runtime.

Special recipes

My first idea was to parse these JavaScript pages for the “button” elements, as they will most likely be labeled correctly and so lead to an action. For example, the “reboot” button will have the right label and effectively reboot the machine. One could then parse all these buttons into searchable MCP actions so that the LLM can trigger a reboot. Unfortunately, in this case the “reboot” button leads to another dialog where the reboot must be confirmed. This kind of sequence is also used for other actions. The solution for this is to take an agent, read the Cockpit source tree, and write special recipes for all these actions so that if one of these buttons is found, some special action is needed. This is not an ideal solution as you need the real Cockpit source code to create all needed recipes, so this solution was discarded.

Parse package JavaScript bundle

As an alternative you could go the other way around and start not at the trigger of the action, but check at the point where the actions start, which is cockpit’s spawn API. Every action that changes the host ultimately comes down to calling cockpit.spawn(argv, options) over the bridge, passing the exact command and its arguments. In unminified source that reads like

cockpit.spawn(["mkfs.xfs", label, device], { superuser: "require" })

but the page bundle is a minified release build, so the human-readable identifiers are gone. What the parser sees is more like

cockpit.spawn(["mkfs.xfs", a, b], { superuser: "require" })

For the first we could simply construct an MCP server which an LLM could use; the latter (which we get in reality) exposes the underlying command but leaves a and b as unknown holes that have to be linked back to dialog fields. To fix this, the code can be parsed with an AST or tree-sitter (available in Python) to connect the input values to the right input fields, which carry the right caption. That approach works, but as the spawn commands often expose their underlying commands and the input values only carry a caption, the LLMs get sidetracked again or can’t find the right input values.

Conclusion

Although the basic idea was nice, it didn’t work out quite well. A real solution would be that the Cockpit authors add the MCP functions alongside when creating the Cockpit package and then expose them correctly.

Final thoughts

Before the rise of LLMs this project would have failed quite early, as one would have needed to think more clearly on the basic idea and how to extract the data. With the help of LLMs this project is in a working state but still not really useful, as Cockpit doesn’t have the correct API for this.