Skip to main content

dhis2w-mcp-bridge

A FastMCP server that exposes the entire d2w CLI as one MCP tool, dhis2_cli.

Where dhis2w-mcp registers ~304 typed tools (≈50-65k tokens of schema loaded into the model's context up front), this server registers a single tool that shells out to the local d2w binary. A small, context-limited local model discovers the command surface progressively with --help and runs commands with --json — and nothing leaves the host.

Why this exists

For sensitive data that must stay on-box, you run a local model (LM Studio, Ollama, llama.cpp). Such models can't spare ~53k tokens for tool schemas, and many degrade when choosing among hundreds of tools. One tool + on-demand --help fits an 8k-context model and keeps the full DHIS2 surface reachable. Same code as the CLI — the bridge just runs it.

Use dhis2w-mcp (the full typed server) for hosts that do progressive tool disclosure themselves (e.g. Claude Code handles all 304 tools fine). Use this bridge for small local models.

The tool

dhis2_cli(args: list[str], profile: str | None = None) -> CliResult
CliResult = { exit_code: int, stdout: str, stderr: str }

The model is expected to discover, then act:

dhis2_cli(["--help"])                                  # list command groups
dhis2_cli(["metadata", "--help"])                      # drill into a group
dhis2_cli(["metadata", "list", "dataElements",
           "--filter", "name:ilike:malaria"])          # run a command

Contract: --json is injected automatically, so on success (exit_code == 0) stdout is JSON. --help/--version exit 0 with human text. Any non-zero exit is a failure and the message is on stderr (never JSON). profile is injected as -p <profile>.

Install & run

The bridge depends on dhis2w-cli, so installing it provides the d2w binary.

# From a workspace checkout (development)
uv run dhis2w-mcp-bridge

# From PyPI
uv tool install dhis2w-mcp-bridge
dhis2w-mcp-bridge

Configure a client (LM Studio shown; any MCP host works)

~/.lmstudio/mcp.json:

{
  "mcpServers": {
    "dhis2": {
      "command": "uv",
      "args": ["run", "--directory", "/ABS/PATH/TO/dhis2w-utils", "dhis2w-mcp-bridge"],
      "env": {
        "DHIS2_PROFILE": "local_basic",
        "DHIS2_MCP_READONLY": "1"
      }
    }
  }
}

The server speaks MCP over stdio and reads its DHIS2 connection from a profile (.dhis2/profiles.toml / ~/.config/dhis2/profiles.toml) or env vars (DHIS2_URL + DHIS2_PAT / DHIS2_USERNAME+DHIS2_PASSWORD), exactly like the CLI.

Environment variables

Variable Default Effect
DHIS2_MCP_READONLY unset When truthy (1/true/yes/on), only read commands and --help are allowed; writes are refused (exit 126).
DHIS2_CLI_BIN auto Path to the d2w executable. Auto-discovered next to the running interpreter, then on PATH.
DHIS2_MCP_CLI_TIMEOUT 120 Per-command timeout in seconds (exit 124 on timeout).
DHIS2_PROFILE profile default Selects the DHIS2 profile, passed through to the CLI.

Exit-code conventions added by the bridge: 124 timeout, 126 refused by read-only mode, 127 CLI not found. Otherwise the result carries the CLI's own exit code (0 success / JSON, 1 domain error, 2 usage error).

Read-only mode

DHIS2_MCP_READONLY=1 is the safe default for handing a local model a query-only surface. It is fail-closed: only commands on an allowlist of read-only command paths (and --help) are permitted; everything else is refused before any subprocess runs. The allowlist is generated by introspecting the Typer command tree and verified against the live tree by the test suite, so it cannot silently drift, and ambiguous verbs default to denied.

This is convenience, not the security boundary — the authoritative control is the DHIS2 authorities of the profile's credentials. For a hard guarantee, point the profile at a read-scoped PAT or user.

How it works

build_server() creates a FastMCP instance and registers the single dhis2_cli tool (cli_bridge.register). The tool runs d2w --json [-p <profile>] <args> via asyncio.create_subprocess_exec (exec form — no shell, no injection), bounded by a timeout, and returns a typed CliResult. There is no version resolution or plugin discovery: the CLI subprocess auto-detects the DHIS2 version itself on connect.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dhis2w_mcp_bridge-1.8.2.tar.gz (11.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dhis2w_mcp_bridge-1.8.2-py3-none-any.whl (13.9 kB view details)

Uploaded Python 3

File details

Details for the file dhis2w_mcp_bridge-1.8.2.tar.gz.

File metadata

  • Download URL: dhis2w_mcp_bridge-1.8.2.tar.gz
  • Upload date:
  • Size: 11.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for dhis2w_mcp_bridge-1.8.2.tar.gz
Algorithm Hash digest
SHA256 7d6c06a776017e8b70201ff1363faf9329bae46f8083fa89e439f151fb1f9617
MD5 d76c02f6fb30be48c7ae9bdf22a5078e
BLAKE2b-256 b425bac4a0802380559e0a6ced007e1b1e4eb402ff21d2a44002b10f1581d919

See more details on using hashes here.

Provenance

The following attestation bundles were made for dhis2w_mcp_bridge-1.8.2.tar.gz:

Publisher: pypi-publish.yml on winterop-com/dhis2w-utils

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dhis2w_mcp_bridge-1.8.2-py3-none-any.whl.

File metadata

File hashes

Hashes for dhis2w_mcp_bridge-1.8.2-py3-none-any.whl
Algorithm Hash digest
SHA256 f835c9c3371b396d002146f8cd9179f029def9220e192e241dd58a02dcd13ace
MD5 558c873d84ae6a0b8e9fb30c3ce6b518
BLAKE2b-256 18368d06155bf7acd4bd001659c4214ebd559c4ac245e2a5a6e222638245d826

See more details on using hashes here.

Provenance

The following attestation bundles were made for dhis2w_mcp_bridge-1.8.2-py3-none-any.whl:

Publisher: pypi-publish.yml on winterop-com/dhis2w-utils

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

1.13.4

2 files

1.13.3

2 files

1.13.2

2 files

1.13.1

2 files

1.13.0

2 files

1.12.0

2 files

1.11.0

2 files

1.10.0

2 files

1.9.0

2 files

1.8.3

2 files

This release

1.8.2 This release

2 files

1.8.1

2 files

1.8.0

2 files

1.7.0

2 files

1.6.0

2 files

1.5.0

2 files

1.3.0

2 files

1.2.0

2 files

1.1.0

2 files

1.0.0

2 files

0.99.0

2 files

0.23.0

2 files

0.22.0

2 files

0.21.0

2 files

0.20.0

2 files

0.19.0

2 files

0.18.0

2 files

0.17.0

2 files

0.16.0

2 files

0.15.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page