Detect (DE) · Supply chain
Supply chain at the client side layer
deterministic · Outside the model's reasoning
If this concern is breached, how do we know?
What this cell does
MCP allowlist violation events; tool-description hash mismatch alerting; lockfile diff in CI logs centralized; pre-commit dependency scan results.
Artifacts (3)
ci-lockfile-diff.ymlview on GitHub# ABOUTME: Workflow step shipping truncated lockfile diff to SIEM on every PR. Add to lockfile-integrity.yml.
# ABOUTME: Diff is truncated to first 200 lines so a huge PR does not flood the SIEM payload; full diff is in CI artifacts.
- name: Ship lockfile diff to SIEM
if: always() && github.event_name == 'pull_request'
env:
SIEM_TOKEN: ${{ secrets.SIEM_TOKEN }}
SIEM_URL: ${{ vars.SIEM_URL }}
run: |
DIFF=$(git diff origin/${{ github.base_ref }} -- \
package-lock.json requirements.txt requirements*.txt \
Pipfile.lock poetry.lock go.sum Cargo.lock 2>/dev/null \
| head -200)
if [[ -n "$DIFF" ]]; then
DIFF_JSON=$(printf '%s' "$DIFF" | jq -R -s .)
curl -sS -X POST "$SIEM_URL/agent-sentinel-ci/_doc" \
-H "Authorization: Bearer $SIEM_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"event\": \"lockfile_diff\",
\"repo\": \"${{ github.repository }}\",
\"pr\": ${{ github.event.pull_request.number }},
\"actor\": \"${{ github.actor }}\",
\"diff\": $DIFF_JSON,
\"ts\": \"$(date -Iseconds)\"
}"
fi
mcp-launch-emit.shview on GitHub#!/usr/bin/env bash
# ABOUTME: Snippet that the mcp-launch wrapper sources to emit a structured per-connection event with status and hash.
# ABOUTME: Source from controls/supply-chain/client-side/mcp-launch immediately after the hash check.
emit_mcp_connect() {
# Args:
# $1 = server name
# $2 = status (ok | hash_mismatch | not_in_allowlist | signature_failed)
# $3 = actual sha256 (or "" if not computed)
local name="$1" status="$2" sha="${3:-}"
local event
event="$(jq -n \
--arg server "$name" \
--arg status "$status" \
--arg sha "$sha" \
--arg ts "$(date -Iseconds)" \
'{event: "mcp_connect", server: $server, status: $status, hash: $sha, ts: $ts}')"
logger -t agent-sentinel -p user.info "$event"
}
# Usage in mcp-launch:
#
# . /etc/agents/hooks/mcp-launch-emit.sh
#
# if [[ -z "$EXPECTED_SHA" || ... ]]; then
# emit_mcp_connect "$SERVER_NAME" "not_in_allowlist" ""
# exit 2
# fi
# if [[ "$ACTUAL_SHA" != "$EXPECTED_SHA" ]]; then
# emit_mcp_connect "$SERVER_NAME" "hash_mismatch" "$ACTUAL_SHA"
# exit 2
# fi
# emit_mcp_connect "$SERVER_NAME" "ok" "$ACTUAL_SHA"
tool-desc-mismatch-emit.pyview on GitHub# ABOUTME: Patch fragment for mcp-verify-tools.py that emits a structured event when the tool-description hash mismatches.
# ABOUTME: This is the rug-pull alert. Add the import + call inside the existing mismatch branch.
import json
import syslog
def _emit_tool_desc_mismatch(server_name: str, expected_hash: str, actual_hash: str) -> None:
"""Emit a structured rug-pull event to local syslog tagged agent-sentinel.
Call this from `mcp-verify-tools.py` inside the `if expected and actual != expected:`
branch, before `sys.exit(2)`.
"""
syslog.openlog("agent-sentinel")
syslog.syslog(
syslog.LOG_WARNING,
json.dumps(
{
"event": "mcp_tool_desc_mismatch",
"server": server_name,
"expected_hash": expected_hash,
"actual_hash": actual_hash,
}
),
)
# Patch fragment to apply in mcp-verify-tools.py:
#
# if expected and actual != expected:
# _emit_tool_desc_mismatch(server_name, expected, actual)
# print(f"BLOCKED: {server_name} tool descriptions changed", file=sys.stderr)
# ...
Cell notes
Sentinels, Supply chain / Client-side
Control. mcp-launch wrapper logs every connection attempt with status (ok | hash_mismatch | not_in_allowlist). Tool-description hash mismatch alerts on rug-pull. Lockfile diff in CI shipped to SIEM. Pre-commit dependency scan results centralized.
Strength. Deterministic when emit happens. Failure modes: MCP wrapper logs only successful connections (failures and rejections are the interesting events); lockfile diff log includes the entire diff for huge PRs (truncate to first 200 lines); tool-description hash mismatch suppressed on legitimate update (the mismatch is the alert; reapproval is a separate workflow).
Tooling
- - The mcp-launch wrapper from
../../../controls/supply-chain/client-side/mcp-launch. - - The mcp-verify-tools.py script from
../../../controls/supply-chain/client-side/mcp-verify-tools.py. - - The lockfile-integrity workflow from
../../../controls/supply-chain/server-side/lockfile-integrity.yml.
Files in this directory
- -
mcp-launch-emit.sh, append-only snippet that the mcp-launch wrapper sources to emit a structured per-connection event including status and hash. - -
tool-desc-mismatch-emit.py, patch fragment formcp-verify-tools.pythat emits a structured event on hash mismatch (the rug-pull alert). - -
ci-lockfile-diff.yml, workflow extension that ships the truncated lockfile diff to SIEM on every PR that touches a lockfile.
Verification
# 1. MCP allowlist violation logged
mcp-launch unknown-server || true
journalctl -t agent-sentinel --since "1 minute ago" | grep mcp_connect
# expected: status: not_in_allowlist event
# 2. Tool-description mismatch logged
# Modify a tool description in a running MCP server's source; restart.
journalctl -t agent-sentinel | grep mcp_tool_desc_mismatch
# 3. Lockfile diff in SIEM
# Open a PR with a lockfile change; check SIEM for the lockfile_diff event.
Common mistakes
- - MCP wrapper logs only successful connections. The interesting events are failures and rejections.
- - Lockfile diff log includes the entire diff for huge PRs. Truncate to first 200 lines.
- - Tool-description hash mismatch suppressed on legitimate update. The mismatch is the alert; reapproval is a separate workflow.
Citation
NIST CSF 2.0 DE.CM-09, ID.RA-09. OWASP MCP08, MCP09.
Primary failure modes
Documented, not hypothetical. A control whose bypass is undocumented is worse than no control, because somebody trusted it.
- MCP wrapper logs only successful connections (failures are interesting events)
- lockfile diff log includes full diff for huge PRs (truncate)
- tool-description hash mismatch suppressed on legitimate update
Crosswalk
| NIST CSF 2 0 | DE.CM-09, ID.RA-09 |
|---|---|
| OWASP MCP | MCP08, MCP09 |
Cite this cell:
https://agenticcovenants.com/detect/supply-chain/client-side/