Static compliance-controls checker for UK Online Safety Act & ICO Children's Code. CLI + MCP.
Model Context Protocol (MCP) Server: io.github.nugehs/bouncer
The io.github.nugehs/bouncer MCP server provides a static compliance-controls checker for the UK Online Safety Act and the ICO Childrenβs Code. It supports a CLI + MCP workflow to verify required regulation controls in code, using static analysis.
π οΈ Key Features
Static compliance-controls checker
Targets UK Online Safety Act and ICO Childrenβs Code
Provides both CLI and MCP access
π Use Cases
Checking that implemented controls align with the Online Safety Act requirements
Verifying code against ICO Childrenβs Code controls
Supporting policy-as-code style reviews for compliance needs
β‘ Developer Benefits
Static-analysis approach for compliance verification
MCP integration alongside a CLI workflow
Node ecosystem package identified as @nugehs/bouncer (topics include mcp-server and static-analysis)
β οΈ Limitations
Static compliance-controls checking is limited to verification available via static code analysis (no behavior/runtime compliance validation is described)
bouncer verifies that the controls a
regulation requires actually exist in your code β UK Online Safety Act, ICO
Children's Code (AADC), and Nigeria (NDPC, FCCPC, FIRS) β expressed as
deterministic rule packs. It runs in CI,
exits non-zero when a required control is missing, and needs no LLM.
It checks IDs at the door so non-compliant code doesn't get in.
bouncer is an engineering aid, not legal advice. A green report means the
coded controls a rule looks for were found β it is not a substitute for a
compliance / DPO review.
Why
Regulators now expect demonstrable controls: age assurance, high-privacy
defaults for children, report/block affordances on user-generated content, a DPIA,
a risk assessment. Those are concrete things that either exist in a codebase or
don't. bouncer turns a regulation into a set of static checks over your repo, the
same way tieline turns an API
contract into drift checks β the engine knows nothing about the law; the
rule packs do.
bouncer vs semgrep / policy-as-code
Scanners like semgrep, CodeQL, or Snyk answer "is there bad code here?" β they
hunt for vulnerabilities and dangerous patterns that shouldn't exist. bouncer
answers the opposite question: "does the code the regulation requires actually
exist?" β age assurance on sign-up, report/block on UGC surfaces, high-privacy
defaults for children. A repo can be vulnerability-free and still fail every one
of those obligations. Policy-as-code tools (OPA/Rego, Conftest) gate configs and
infrastructure against policy; bouncer gates application source against
regulatory rule packs, with file:line evidence for every control and an honest
unknown when a surface can't be located. In short: semgrep finds
vulnerabilities; bouncer proves required controls exist. They complement each
other β run both.
Or clone and run with plain Node (zero runtime dependencies, Node β₯ 18).
Usage
bash
bouncer init [path] # write a starter bouncer.config.json
bouncer check # run packs, print report, exit 1 on a missing control
bouncer check --pack uk-aadc # restrict to one pack
bouncer check --status fail # show only the failures
bouncer report --out report.html # self-contained HTML audit report
bouncer list # every rule the configured packs apply
bouncer explain <ruleId> # what a rule requires + how it is checked
bouncer packs # rule packs shipped with bouncer
bouncer doctor # sanity-check config, adapter, packs
bouncer mcp # start the MCP server (stdio)
Verdicts
Verdict
Meaning
pass
the required control was found (evidence: file:line)
fail
the surface exists, but no evidence of the control was found
unknown
the surface could not be located in this repo β can't determine, not a pass
unknown is deliberate: bouncer never reports a green pass for a surface it could
not find. Missing surface β honest "can't determine".
adapter β how regulation surfaces (sign-up, profile, chat, livestreamβ¦) map
onto files for your stack.
Adapters shipped today: next (App Router) and react-native. That's it β
if your stack isn't covered, an adapter is a single small file mapping surface
aliases to file globs (see src/lib/adapters/next.js). Adapter PRs are very
welcome β nuxt, sveltekit, remix, flutter, django are all natural
candidates.
packs β which rule packs to run. Built-ins: uk-osa, uk-aadc, ng-ndpc, ng-fccpc, ng-firs.
packDirs β extra directories of your own *.json packs.
ignore β rule ids to skip.
failOn β which buckets make check exit non-zero (default ["fail"]).
Rule packs
A pack is JSON. Each rule maps a legal standard to a static assertion over a
surface:
json
{"id":"aadc.geolocation-default-off","standard":"Standard 10 β Geolocation","severity":"high","surface":"profile","intent":"Geolocation must default to off for children.","fix":"Default any location-sharing setting to off.","assert":{"find":"(geo|location)[^\\n;,]{0,30}(default|initial)[^\\n;,]{0,15}(false|off)","in":["profile","any"],"expect":"present"}}
in accepts a surface alias (resolved by the adapter), an array of aliases/globs,
or a raw glob. expect: "absent" flips the meaning β a match is a violation
(used for nudge patterns, self-declared age checkboxes, etc.).
ng-fccpc β consumer protection (FCCPC): blanket "no refund / all sales
final" clauses flagged as void β and high-precision, so a tiered or
conditional refund policy doesn't trip it β plus refund-policy present, no drip
pricing, explicit terms acceptance, terms of service present.
ng-firs β tax (FIRS): 7.5% VAT rate, VAT on commission, WHT on payouts,
VAT tax invoice.
Some obligations are process, not code β NDPC registration, signed cross-border
DPAs, the WHT remittance itself. Those rules surface as gaps to track (add
them to ignore with a note), not things a static scan can prove.
MCP
bouncer is also an MCP server (stdio), so an agent can pull the same deterministic
results:
Tool
Purpose
compliance_check
run packs, return per-control verdicts + evidence
list_rules
list rules the configured packs apply
explain_rule
a rule's standard, intent, fix, and how it is checked
Fails the build when a required control goes missing β e.g. someone removes an
age-gate or a report button from a UGC surface.
Tests
bash
npm test# node --test β zero dependencies, nothing to install
The suite runs on Node's built-in test runner against throwaway fixture repos:
glob/brace expansion, every assertion probe (find, allOf/anyOf/not,
allInFile + within windows, expect: "absent"), the pass/fail/unknown
verdict semantics, and pack loading. CI runs it on Node 18, 20, and 22.
License
MIT
Part of the toolchain
bouncer is one of four tools that form a deterministic trust layer for AI-assisted development. Each answers a question people keep handing to an LLM β with static analysis instead.
repoctx β context: what does this change actually touch?
tieline β contracts: did the front end and back end quietly stop agreeing?
bouncer (this tool) β compliance: could you defend this to Ofcom?
aiglare β governance: where can the model do something you can't undo?