Skip to main content
Glama
tarun-km

hydris-diagnostic-mcp

by tarun-km

hydris-mcp-integration

Hydris Pulse Bridge track, Work Item 1: the Diagnostic MCP server skeleton that will live at lite/diagnostic_mcp/ inside the Lite monorepo. It discharges BRIDGE-2 (per-call factory authorization), BRIDGE-5 (per-call audit logging) and NFR-4 (security), and structurally enforces BRIDGE-1 (read-only toolset).

See docs/scope.md for exactly what is and isn't built here, and docs/decisions.md for the open-item decisions (revocation latency, audit-sink-failure behaviour, the non-leaking error shape, the toolset version scheme) this skeleton took a position on, pending Nematullah's ratification.

Architecture

  • Two identities, kept separate (diagnostic_mcp/auth/): a service-principal JWT (read-only scopes, verified independently) and a per-call user-context JWT. The service token never widens access.

  • One pipeline for every call (diagnostic_mcp/registry/pipeline.py): authenticate both identities, validate arguments, check the user's live factory grant (no caching), dispatch, audit-log the outcome - success, rejected, or error - every time.

  • Registration-time read-only gate (diagnostic_mcp/registry/tool_registry.py): a tool without classification="read_only" or without a required factory_id argument is rejected when it's registered, not when it's called.

  • FastMCP for schema advertisement, one override for dispatch (diagnostic_mcp/server.py): tools/list comes from FastMCP as usual; tools/call is intercepted once, at the low-level server, so every tool

    • present or future - goes through the same pipeline with no per-tool boilerplate.

  • One demonstration tool, get_plant_overview (diagnostic_mcp/tools/plant_overview.py), backed by an in-memory stub of Lite's read-service layer, seeded with the exact fixtures the source docs name (u-ops-alpha granted fx-mbr-01; u-ops-beta granted fx-beta-01).

Quickstart

python -m venv .venv
.venv/Scripts/pip install -e ".[dev]"      # .venv/bin/pip on macOS/Linux
cp .env.example .env                        # then edit the two secrets

Run the server:

set -a; source .env; set +a                 # or export the vars another way
python -m diagnostic_mcp.server

It listens on streamable-http at http://127.0.0.1:8765/mcp by default.

Verify it end-to-end

pytest -v            # includes a real streamable-HTTP client/server round trip
ruff check .
mypy diagnostic_mcp tests
python scripts/check_no_write_imports.py

To call the running server manually with the official MCP client, mint a service token and a user-context token against the same secrets the server is running with:

from diagnostic_mcp.auth.service_principal import issue_service_token
from diagnostic_mcp.auth.user_context import issue_user_context_token

service_token = issue_service_token("<LITE_MCP_SERVICE_TOKEN_SECRET>")
user_token = issue_user_context_token("<LITE_MCP_USER_CONTEXT_SECRET>", "u-ops-alpha", "org-alpha")
print(f"Authorization: Bearer {service_token}")
print(f"X-Pulse-User-Context: {user_token}")

Then call get_plant_overview with factory_id=fx-mbr-01 (granted - succeeds) or factory_id=fx-beta-01 (not granted - denied, and both attempts land in audit.jsonl).

Work Item 1 definition of done

Item

Status

MCP server registered in-process, streamable-HTTP reachable

Done

Tool registry with read-only classification, rejecting non-conforming registration at startup

Done

Service principal issued with read-only scopes, scope inventory written down against the 15-tool minimum set

Done - diagnostic_mcp/auth/service_principal.py::MINIMUM_READ_SCOPES

Per-call user context header parsed, grants resolved, call rejected before the service token is used

Done

Non-leaking authorization error shape agreed and implemented

Done - see O3 in docs/decisions.md

Revocation latency chosen and documented

Done - see O1 in docs/decisions.md

Audit sink writing all six mandated fields, on success, failure and rejection

Done

Pulse session id propagated and recorded, for TC-BRIDGE-5.3 parity

Done - X-Pulse-Session-Id header

Audit-sink-failure behaviour decided with Nematullah and implemented

Proposed, pending ratification - see O2

No-write CI check live in the Lite repository

Stand-in only - see docs/scope.md

Secrets resolving from the managed store, TLS enforced on the listener

Secrets: done (env-var seam). TLS: infra concern, see docs/scope.md

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/tarun-km/hydris-mcp-integration'

If you have feedback or need assistance with the MCP directory API, please join our Discord server