Eclipse Ditto MCP Server
A Model Context Protocol (MCP) server for Eclipse Ditto — the open-source (EPL-2.0) digital twin framework. It exposes Ditto's HTTP API as MCP tools so an AI agent can manage devices ("things"), their attributes/features, policies, connections, and cluster admin — the full Ditto HTTP API surface.
Since Bosch IoT Things and other commercial IoT platforms are built on Ditto's open protocol, this server also works against those deployments — nothing in the code is vendor-specific.
Built with FastMCP.
Tools
Things
| Tool | Description |
|---|---|
list_things(namespaces, filter, fields, limit) |
Search/list things. filter is a Ditto RQL expression, e.g. eq(attributes/location,"lab-1"). |
count_things(namespaces, filter) |
Count things matching a filter without fetching them. |
get_things(thing_ids, fields) |
Bulk-fetch multiple things by ID in one request. |
get_thing(thing_id, fields) |
Fetch the full digital twin for one thing. |
put_thing(thing_id, thing, overwrite=False) |
Create a thing, or replace one with overwrite=True. |
patch_thing(thing_id, patch) |
Partially update a thing via RFC-7396 JSON Merge Patch. |
delete_thing(thing_id, confirm=False) |
Delete a thing. Irreversible. |
get_thing_policy_id / set_thing_policy_id |
Read/repoint the policy controlling a thing. |
get_thing_definition / set_thing_definition / delete_thing_definition |
Manage a thing's WoT/model definition. |
whoami() |
Return the identity Ditto authenticated this connector as — useful to sanity-check credentials. |
Attributes & Features
| Tool | Description |
|---|---|
get_thing_attributes(thing_id, path=None) |
Get all attributes, or one by JSON pointer path. |
set_thing_attributes(thing_id, value, path=None, overwrite=False) |
Set the whole attributes object, or one attribute. |
delete_thing_attributes(thing_id, path=None, confirm=False) |
Delete attributes (whole object or one path). |
get_thing_features(thing_id) |
Get all features (sensor/actuator state). |
get_feature / put_feature / delete_feature |
Read/create-replace/delete one whole feature. |
get_feature_properties / set_feature_properties / delete_feature_properties |
Read/write/delete feature properties or desiredProperties, whole or by path. |
get_feature_definition / set_feature_definition / delete_feature_definition |
Manage a feature's definition. |
Messages
| Tool | Description |
|---|---|
send_message(thing_id, subject, payload, feature_id=None, direction="inbox", timeout=10) |
Send a live message to/from a thing or feature (e.g. invoke a device operation). |
claim_thing(thing_id, payload=None, timeout=10) |
Send a claim message to gain access to a thing. |
Policies
| Tool | Description |
|---|---|
get_policy / put_policy / delete_policy |
Read/create-replace/delete a policy. |
get_policy_entries(policy_id, label=None) |
Read all entries, or one by label. |
set_policy_entry / delete_policy_entry |
Create-replace/delete one policy entry. |
Connectivity & DevOps (require DITTO_DEVOPS_USERNAME/DITTO_DEVOPS_PASSWORD)
Ditto's Connections API and DevOps API (log levels, cluster config, piggyback commands) sit behind a separate "devops" Basic-auth realm on the gateway, independent of the policy-based auth used for things/policies.
| Tool | Description |
|---|---|
list_connections / get_connection |
List/fetch connection configs. |
create_connection(connection, dry_run=False) |
Create a connection (ID generated by Ditto). |
update_connection(connection_id, connection) |
Update an existing connection (404 if it doesn't exist). |
delete_connection(connection_id, confirm=False) |
Delete a connection. |
get_connection_status / get_connection_metrics / get_connection_logs |
Inspect a connection's live state. |
send_connection_command(connection_id, command) |
Open/close/reset-metrics/enable-logs/reset-logs. |
get_logging_config / set_logging_config |
Read/set cluster log levels. |
get_devops_config(path) |
Read cluster-wide runtime config. |
send_devops_piggyback(command, service_name=None, instance_index=None) |
Low-level admin command — Ditto's most powerful, least-guarded API. Use with care. |
Live events
| Tool | Description |
|---|---|
poll_thing_changes(thing_ids, namespaces, filter, fields, duration_seconds=10, max_events=50) |
Open a short-lived SSE connection and collect live thing-change events. A request/response approximation of Ditto's persistent change feed — see caveat below. |
Safety conventions
- Create vs. replace: every
put_*/set_*/create_*tool defaults tooverwrite=False, using Ditto'sIf-None-Match: *header so create-only is race-free (not a check-then-set). Passoverwrite=Trueto replace existing data. - Deletes are confirm-gated: every
delete_*tool requiresconfirm=True. There is no bulk/cascading delete. - Not covered (deliberately): WoT Web-of-Things descriptor endpoints (
/.well-known/wot,/devops/wot/*), and fine-grained policy sub-resources (subjects/{id},resources/{path},imports, token-integration actions) — whole-entryset_policy_entry/get_policy_entriescovers the common case. Add these later if you need them.
Configuration
| Env var | Required | Description |
|---|---|---|
DITTO_BASE_URL |
Yes | Base URL of the Ditto HTTP API, e.g. http://localhost:8080 or your gateway's public URL. |
DITTO_USERNAME / DITTO_PASSWORD |
No | Basic auth for the Things/Policies/Messages/Search API. Typical for self-hosted Ditto (nginx demo setup uses ditto/ditto). |
DITTO_BEARER_TOKEN |
No | Bearer token, used instead of Basic auth for the same API. Typical for OAuth2-fronted deployments (e.g. Bosch IoT Things). |
DITTO_DEVOPS_USERNAME / DITTO_DEVOPS_PASSWORD |
No | Basic auth for the separate DevOps/Connections realm (self-hosted default: devops/foobar). Required only for the Connectivity and DevOps tools. |
If both DITTO_BEARER_TOKEN and Basic auth credentials are set, the bearer token takes precedence. If neither is set, requests are sent unauthenticated (only works if your Ditto instance allows anonymous/pre-authenticated access).
Running locally
uv sync
export DITTO_BASE_URL=http://localhost:8080
export DITTO_USERNAME=ditto
export DITTO_PASSWORD=ditto
export DITTO_DEVOPS_USERNAME=devops # only needed for connectivity/devops tools
export DITTO_DEVOPS_PASSWORD=foobar
uv run dittomcpserver.py
See mcp.json for ready-to-use client configs (stdio and Docker).
Testing against a real Ditto instance
This repo's design principles call for testing against a real instance rather than mocks. docker-compose.yml (adapted from Ditto's official example, trimmed to the services this connector needs) spins up a full local Ditto stack — MongoDB, the Ditto microservices, and an nginx front door with Basic auth.
docker compose up -d # start Ditto on http://localhost:8080 (user: ditto / pass: ditto; devops: devops / foobar)
uv run pytest -v # tests/conftest.py also starts/stops the stack automatically
docker compose down # stop it manually if you started it yourself
The 47 tests cover every tool group (things, attributes/features, messages, policies, connectivity, devops, live events) against this real stack, including delete/confirm gating and create/overwrite gating.
A note on the live-events approximation
poll_thing_changes opens Ditto's SSE change feed for a bounded window instead of holding a persistent subscription (which doesn't map cleanly onto a single MCP tool call). Ditto's SSE stream sends periodic empty data: keepalive lines even when nothing has changed — the tool checks its deadline on every line received, including keepalives, so it reliably returns within duration_seconds regardless of how chatty or quiet the stream is.
License notes
docker-compose.yml and the files under docker/ are adapted from the Eclipse Ditto project (EPL-2.0) and are used here only to spin up a local test instance — they are not part of the MCP server itself.
Metadata
Release files for eclipse-ditto-mcp-server 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| eclipse_ditto_mcp_server-0.1.1.tar.gz | 102.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| eclipse_ditto_mcp_server-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 115.9 kB
Release files / eclipse_ditto_mcp_server-0.1.1.tar.gz
| Download URL | eclipse_ditto_mcp_server-0.1.1.tar.gz |
|---|---|
| Size | 102.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3c05cb734c5b97b4d1b7a2794d43e5635e0f292b025f910b113c255fd8ba1550
|
|
BLAKE2b-256 checksum How to use checksums |
a8a8df7f721bbb0fefc45565b56df2ce9034cc8debd8bdd02b172dbda9062ad3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / eclipse_ditto_mcp_server-0.1.1-py3-none-any.whl
| Download URL | eclipse_ditto_mcp_server-0.1.1-py3-none-any.whl |
|---|---|
| Size | 13.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a9cc9b33bd914b5601bd8d14d5af850e63f11ef316b26423d0946a4e77e03b4d
|
|
BLAKE2b-256 checksum How to use checksums |
fe42966ec06704fa4b2fe6c9fd415be6b3eb29ecbe6981efe79c737c9a5a2ff7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for eclipse-ditto-mcp-server 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.