Skip to main content
Glama
prayagpadwal

compliance-evidence-mcp

by prayagpadwal

compliance-evidence-mcp

An MCP server that lets AI agents query security control evidence for SOC 2 and ISO 27001 audit readiness — with the authorization boundary enforced in the server, not in the prompt.

Agents are increasingly pointed at compliance data: which controls are missing evidence, what's expired, what's still open from the last audit. That data is not uniformly readable. An external auditor, an internal analyst, and an autonomous reporting agent should each see a different slice of it, and the difference has to be enforced somewhere that a model cannot talk its way past.

All data in this repository is synthetic. The control references are real SOC 2 and ISO 27001 identifiers, which are public; every owner, evidence artifact, and audit finding attached to them is invented for demonstration and describes no real organization, system, or vulnerability.

The design decision

There is no run_sql tool.

Most database-backed MCP servers expose query execution and let the model compose SQL. That moves the authorization decision into the model's judgement, where it can be neither constrained nor audited — and where a prompt injection in a document, a ticket, or a scraped page can reach it.

This server exposes seven intent-shaped tools instead. Because the server knows what each call means, it can compose the caller's authorization predicates into the SQL before execution:

Layer

Enforcement

Scope

Deny-by-default. A missing grant raises, so a refusal is distinguishable from an empty result.

Row (classification)

classification_level <= principal.clearance, in the WHERE clause.

Row (business unit)

Evidence inherits its business unit transitively from the control it supports.

Column

Free-text notes and finding detail are masked below CONFIDENTIAL.

Aggregate

Coverage rollups join under the predicate, so counts never include invisible rows.

Existence

Out-of-scope and nonexistent IDs both return null — the tool can't be used to probe for restricted IDs.

Filtering after the query returns is not equivalent, and aggregates are where that usually goes wrong: a rollup computed over all rows and then trimmed still tells the caller how many rows they weren't allowed to see.

Related MCP server: @actalumen/mcp-server

What it looks like

$ python demo.py

1. list_controls()  -- rows visible
  agent-coverage-bot   clearance=INTERNAL      9 controls   units=corp-it,gpu-cloud,platform
  analyst-platform     clearance=INTERNAL      8 controls   units=corp-it,platform
  auditor-external     clearance=CONFIDENTIAL  5 controls   units=platform
  security-lead        clearance=RESTRICTED   13 controls   units=corp-it,gpu-cloud,platform,security

2. list_findings(status='open')  -- scope + masking
  agent-coverage-bot   DENIED  (no findings:read grant)
  analyst-platform     DENIED  (no findings:read grant)
  auditor-external     DENIED  (no findings:read grant)
  security-lead        5 open findings, 0 with detail masked

3. get_evidence_gaps()  -- aggregates respect the boundary
  agent-coverage-bot   4 gaps: A.5.23, A1.2, CC6.2, CC6.6
  analyst-platform     3 gaps: A1.2, CC6.2, CC6.6
  auditor-external     2 gaps: A1.2, CC6.6
  security-lead        4 gaps: A.5.23, A1.2, CC6.6, CC7.3

Same query, four identities. The interesting row is CC6.2: analyst-platform reports it as an evidence gap, security-lead does not. The control is covered — but by evidence classified above the analyst's clearance. The aggregate degrades to "uncovered" rather than confirming that evidence exists. That is the behaviour you want; it is also the one that post-filtering silently gets wrong.

Tools

Tool

Required scope

whoami()

list_controls(framework, business_unit)

controls:read

get_control(control_id)

controls:read

list_evidence(control_id, kind)

evidence:read

get_control_coverage(framework, as_of)

coverage:read

get_evidence_gaps(framework, as_of)

coverage:read

list_findings(status, severity)

findings:read

get_access_log(limit)

findings:read

whoami() is unscoped by design: an agent should be able to discover what it is allowed to see, so it can interpret an empty result correctly instead of concluding that no findings exist.

Identity

Principals are resolved in principals.py — deliberately outside the warehouse. In production resolve() maps the OAuth subject presented by the MCP client to a principal; it is never read from a table the agent can also query, and never taken from a tool argument the model could influence. Resolution fails closed: an unset identity defaults to the least-privileged principal.

For local runs, select an identity with an environment variable:

COMPLIANCE_MCP_PRINCIPAL=security-lead python -m compliance_mcp.server

Audit trail

Every invocation is appended to access_log with principal, arguments, decision, and row count. Denials are logged too — in an assurance context, the record of what an agent was refused is itself evidence, and it is the first thing you want when reconstructing an incident.

Running it

pip install -e .
python demo.py          # the walkthrough above
pytest -q               # 17 authorization tests

Wire it into Claude Code:

// .mcp.json
{
  "mcpServers": {
    "compliance-evidence": {
      "command": "python",
      "args": ["-m", "compliance_mcp.server"],
      "env": { "COMPLIANCE_MCP_PRINCIPAL": "analyst-platform" }
    }
  }
}

Tests

tests/test_authorization.py is the substance of this repo. It asserts that a principal cannot reach data outside its grant by row, by column, by business unit, or through aggregates — plus that resolution fails closed, that out-of-scope lookups are indistinguishable from missing ones, and that no raw-SQL passthrough has been added.

Scope and honesty

This is a reference implementation, not a product. DuckDB with a seeded fixture stands in for the warehouse so it runs anywhere with no credentials; the repository layer issues plain parameterized SQL, so Snowflake or Databricks is a connector swap. The fixture controls are real SOC 2 TSC and ISO 27001 Annex A references; the findings are invented.

What it is meant to demonstrate is the pattern: agent-accessible data surfaces need an authorization boundary that lives in code, is enforced in the query, and leaves an audit trail.

Built with Python 3.10+ and the official MCP Python SDK (2.x).

A
license - permissive license
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • F
    license
    A
    quality
    F
    maintenance
    Provides policy-based access control, incident tracking, and compliance monitoring to govern AI agent behavior. It enables organizations to enforce security rules and maintain audit trails by validating agent actions against trust levels and pattern-based policies.
    6
    1
  • A
    license
    Not graded
    quality
    F
    maintenance
    Provides AI assistants with read-only access to Secureframe's compliance data, enabling querying of security controls, tests, users, vendors, and more across frameworks like SOC 2 and ISO 27001.
    8
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables authorized compliance verification and security auditing through natural language, bridging AI assistants with industry-standard security tools for enterprise audits.
    24

View all related MCP servers

Related MCP Connectors

  • Shared, permission-aware company context for AI agents, with provenance, approvals and audit.

  • Pay-per-call cybersecurity for AI agents: vuln scans, threat intel, compliance, code security.

  • Pre-action allow/deny for AI agents. 24 statutes, 13 jurisdictions: EU AI Act, GDPR, DPDP.

View all MCP Connectors

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/prayagpadwal/compliance-evidence-mcp'

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