MP-301f · Module 2
Compliance Mapping & Audit Architecture
4 min read
A compliance map links every MCP resource to the regulatory controls it must satisfy. For each resource, the map specifies: which regulations apply (GDPR, HIPAA, SOC 2, PCI DSS), which controls are required (access logging, encryption, masking, retention), and how those controls are implemented in the MCP server. This is not documentation — it is an executable policy that the server enforces at runtime. When a resource is read, the server consults the compliance map and applies all required controls before returning data.
The audit architecture must produce evidence that controls are working. This means structured, immutable audit logs that capture: who accessed the resource (user identity), what was accessed (resource URI and classification), when it was accessed (timestamp), what controls were applied (masking, encryption, access checks), and what was returned (response size, not content). These logs feed into compliance reporting tools — automated SOC 2 evidence collection, GDPR data access reports, and HIPAA access audit trails.
Audit log architecture requires immutability — logs cannot be modified or deleted, even by administrators. Write to an append-only store: a dedicated logging service (Datadog, Splunk), a write-only database table with no DELETE or UPDATE grants, or an immutable cloud log stream (AWS CloudWatch Logs, GCP Cloud Logging). The log stream should be separate from the MCP server's infrastructure — if the server is compromised, the audit trail must survive.
interface AuditEntry {
timestamp: string;
userId: string;
action: "resource_read" | "resource_subscribe" | "resource_unsubscribe";
resourceUri: string;
classification: Classification;
controlsApplied: string[];
responseBytes: number;
sourceSystem: string;
sessionId: string;
// Never log actual data content — only metadata
}
class AuditLogger {
private buffer: AuditEntry[] = [];
private flushInterval = 5_000; // Flush every 5 seconds
constructor(private sink: AuditSink) {
setInterval(() => this.flush(), this.flushInterval);
}
log(entry: AuditEntry): void {
this.buffer.push(entry);
// Immediate flush for restricted data
if (entry.classification === "restricted") {
this.flush();
}
}
private async flush(): Promise<void> {
if (this.buffer.length === 0) return;
const batch = this.buffer.splice(0);
await this.sink.writeBatch(batch);
}
}
interface AuditSink {
writeBatch(entries: AuditEntry[]): Promise<void>;
}
// Compliance verification — run nightly
async function verifyCompliance(
resources: string[],
complianceMap: Map<string, string[]>
): Promise<{ passed: number; failed: string[] }> {
const failures: string[] = [];
for (const uri of resources) {
const controls = complianceMap.get(uri);
if (!controls) {
failures.push(`${uri}: no compliance mapping defined`);
continue;
}
// Verify each required control produces audit evidence
for (const control of controls) {
const hasEvidence = await checkAuditEvidence(uri, control);
if (!hasEvidence) {
failures.push(`${uri}: missing evidence for ${control}`);
}
}
}
return {
passed: resources.length - failures.length,
failed: failures,
};
}
- Build the compliance map For every MCP resource, document which regulations apply and which controls are required. Store this as a machine-readable config, not a Word document — the server must enforce it at runtime.
- Implement immutable audit logging Write audit entries to an append-only store separate from the MCP server. Include user, resource, classification, controls applied, and response size. Never log data content.
- Automate compliance verification Run a nightly check that every resource has a classification, every classification has a compliance mapping, and every control produces audit evidence. Alert on failures.