Skip to main content
Glama

MCP Shadow

Experimental project for a Docker homelab. Not production-ready.

MCP Shadow is a read-only Model Context Protocol server. It gives an MCP client or agent tools to discover labelled Docker services, query their status and resource usage, read bounded logs, and request differential reports. Optional local Ollama analysis adds advice alongside objective observations. It does not implement an autonomous agent or establish reliable incident causes.

Trust boundary: the included MCP HTTP endpoint has no authentication. The Host and Origin checks protect against DNS rebinding. Compose publishes the port on localhost by default. Labels filter access in the application; they do not restrict direct Docker proxy access to individual containers. Logs, raw snapshots, baselines and reports can contain sensitive data, even after redaction. Use a trusted host/network and an authenticated gateway for remote access.

First query with synthetic data

Requirements: Linux Docker Engine with access to its local Unix socket, Docker Compose v2, a shell, and network access to fetch the pinned images and packages. You do not need Python on the host, an MCP desktop app, Ollama, or a model. Run from a clean copy of this directory:

bash scripts/run_integration.sh --demo

The script uses .env.example with ANALYSIS_PROVIDER=disabled. It starts a labelled log fixture, the server and its Docker proxy in a temporary project with its own internal network and state volume. Discovery is filtered to that project. The official MCP Python SDK client connects over Streamable HTTP, queries the fixture's state and memory, and observes 40 distinct generated error events across report pages. It verifies pending report replay and acknowledges the pages. The script removes the temporary containers, network and volume on exit.

The client prints a JSON summary like this. memory_percent depends on the host and container, and objective_severity depends on the signals observed during the query. A successful run observes 40 events and returns a null model advisory.

{
  "client": "official MCP Python SDK",
  "tools": 11,
  "service": "log-fixture",
  "state": "running",
  "running": true,
  "memory_percent": 0.01,
  "synthetic": true,
  "observed_error_events": 40,
  "objective_severity": "medium",
  "model_severity_advisory": null,
  "delivery_replay_verified": true,
  "checkpoint_acknowledged": true
}

See the demo walkthrough for the MCP calls and the separate full integration check, which covers restart, disk full, log rotation, proxy outage and graceful degradation when Ollama is configured and unavailable.

Related MCP server: Docker Explorer

Why this exists

A homelab operator can ask an MCP client for observations across selected services without giving that client Docker command execution tools. The project explores MCP tool contracts, separation of observations from model advice, bounded log processing and recoverable report delivery. It demonstrates software engineering around tools an agent can consume; no scheduler, planning loop or autonomous remediation is included.

Install for your own homelab

  1. Copy .env.example to .env. For observation without a model, set ANALYSIS_PROVIDER=disabled. Review the paths and keep the port on localhost.

  2. Prepare the default network and bind directories on Linux:

    docker network create homelab-monitoring
    mkdir -p state disk-probe
    sudo chown 10001:10001 state

    Reuse an existing network if appropriate. The state directory must be writable by container UID 10001. Put disk-probe on the filesystem to measure; it is mounted read-only. Adjust commands if you changed the example paths/network.

  3. Start a named project and check readiness:

    docker compose -p shadow-lab up -d --build
    curl --fail http://127.0.0.1:8010/ready
  4. Use an MCP client with Streamable HTTP at http://127.0.0.1:8010/mcp. For a reproducible query using the supplied client on a Python 3.14 host:

    python3.14 -m venv .venv
    .venv/bin/python -m pip install --require-hashes --only-binary=:all: -r requirements-hashed.txt
    .venv/bin/python scripts/mcp_demo.py --url http://127.0.0.1:8010/mcp \
      --project shadow-lab --service mcp-shadow

    This lists MCP tools and queries the server container's objective state and memory usage. A container client on the shared network can use http://mcp-shadow:8000/mcp; use unique service aliases/networks if multiple stacks share that network. Removing fixed container names avoids host-global name conflicts, but shared-network DNS aliases still require care.

Streamable HTTP at /mcp accepts localhost, 127.0.0.1 and [::1] as Host values without a port, with :8000, or with the published MCP_PORT (8010 by default). It also accepts mcp-shadow:8000 for Compose clients. The default Origin values are those same authorities prefixed by http://. Native clients, including the official Python SDK client, can omit Origin.

For a custom DNS name, reverse proxy or Compose alias, add exact authorities to MCP_ALLOWED_HOSTS (e.g. shadow-alias:8000,shadow.example) and, if the client sends Origin, add exact origins to MCP_ALLOWED_ORIGINS (e.g. https://console.example). Both variables add to the defaults. Include the port when the client sends it. Origin values require a scheme and authority only. Wildcards are unsupported. MCP_BIND_ADDRESS controls port publication and does not add a trusted name. See the Streamable HTTP security requirements.

To observe another service, add labels to its Compose definition and recreate that service yourself:

labels:
  io.shadowofintent.mcp.enabled: "true"
  io.shadowofintent.mcp.name: "Example web service"
  io.shadowofintent.mcp.description: "Synthetic example"
  io.shadowofintent.mcp.log-profile: "nginx"
  io.shadowofintent.mcp.expected-stopped: "false"

Only enabled is required. list_managed_services returns the actual container names for subsequent calls. Review ignore patterns in config/log-profiles.json; filtering noise can hide relevant lines. Ollama is optional: configure an existing trusted endpoint and installed model, then enable ANALYSIS_PROVIDER=ollama. No model download is automatic.

Interface and report delivery

Tools

Observations or behavior

get_server_status, get_storage_usage

Runtime/system summary and monitored filesystem

list_managed_services, list_containers

Labelled services and container names

inspect_container, get_container_stats, get_container_logs

Selected container details, metrics and bounded log prefix

analyze_container_logs, diagnose_container

Objective signals with optional, fallible model advice

generate_server_report, acknowledge_server_report

Differential reports and optional explicit confirmation

The server://inventory resource describes capabilities; /health is liveness, /ready checks Docker, writable state and the probe filesystem. Optional analysis failure does not make objective tools unready. CPU/memory visibility depends on the container environment; these are not guaranteed host-wide measurements.

For recoverable reports, request acknowledged_delivery=true, durably save/process and deduplicate by delivery.id, then acknowledge that ID. Repeat until you have acknowledged a report with baseline.complete_logs=true. baseline.pending_pages counts captured streams with more pages to deliver and can be zero even when capture failed.

When baseline.log_errors is nonzero, surface the failure, save and acknowledge the delivery as usual, and request the next acknowledged report to retry capture for the same interval. The acknowledgement can save partial progress while keeping the interval open. The synthetic demo waits one second between attempts and exits with an error after three consecutive capture failures. After restoring capture, resume with the next acknowledged report on the same server state. The interval keeps the original set of container identities. If a member is removed or replaced before the interval is committed, the report stays incomplete. The demo's in-memory storage is sufficient for its fixture. A real consumer must persist the processed data and delivery IDs across restarts.

All clients share one pending report. A slow consumer blocks further report intervals. The default immediate-save mode can lose a page if its response is lost.

Snapshots capture the whole retained interval before paging: initial latency and disk use grow with that interval. Defaults cap snapshots at 256 MiB per container per interval and 1 GiB across the snapshot directory, with 64 MiB best-effort free space. Baseline and outbox files need extra space. Snapshots with saved cursors survive Docker rotation. Records removed before/during capture cannot always be detected or recovered; choose retention longer than the report interval. Local filesystem locking and atomic replacement are required. See the delivery, storage and recovery contract for concurrency and limits.

Evidence, limitations and project status

The API, schemas and on-disk state are experimental and may change. There is no stable compatibility promise. See verified builds and platforms for exact versions, dependency maintenance and untested platforms.

The Docker proxy permits selected GET endpoints on the host socket, including metadata/log access for unlabelled containers by a direct proxy client. It is not published to the host, but compromise of a container on its network matters. The read-only socket mount alone does not enforce read-only Docker requests. MCP has no authentication or per-user authorization. Raw log reads are not a privacy filter; best-effort model/report redaction cannot identify every secret. Treat local state and every output as sensitive and review before sharing.

Literal evidence validation cannot certify causes, safe advice or resistance to prompt injection. Recorded synthetic results include substantial failures: the corrected three-operation regression passed 8/18 narrow automated checks; the later development run passed 10/12 on different cases. Those scores are not comparable or production quality estimates. Human quality ratings remain pending (10 retained responses, 2 unreviewable rejections). Complete that review without running a model. No independent review or real incident evaluation is claimed.

The documentation index links to the development and publication guides, design decisions and evaluation history. The scripts index lists the commands and their inputs.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    A Model Context Protocol server that provides tools for interacting with Docker images, containers, and registries, enabling AI assistants to search, analyze, and manage Docker resources through a standardized interface.
    1
    MIT
  • A
    license
    B
    quality
    B
    maintenance
    A Model Context Protocol server that provides seamless integration with Coroot observability platform, enabling monitoring of applications, analysis of performance metrics, examination of logs and traces, and management of infrastructure through Coroot's comprehensive API.
    61
    16
    MIT