Audit sinks for security events. The logging sink writes structured JSON events to stderr via tools.logging (never stdout — that stream is reserved for the protocol; see ADR-031). The in-memory sink supports tests.
Audit sinks for security events. The logging sink writes structured JSON events to stderr via tools.logging (never stdout — that stream is reserved for the protocol; see ADR-031). The in-memory sink supports tests.
JSON <-> Clojure data codec for the JSON-RPC boundary. Lives in shell so cheshire (an I/O-adjacent dependency) stays out of the functional core.
JSON <-> Clojure data codec for the JSON-RPC boundary. Lives in shell so cheshire (an I/O-adjacent dependency) stays out of the functional core.
Reads the process environment and resolves the active MCP security context. The pure decision lives in boundary.mcp.core.security; this shell wrapper only supplies the environment (the I/O).
Reads the process environment and resolves the active MCP security context. The pure decision lives in boundary.mcp.core.security; this shell wrapper only supplies the environment (the I/O).
Shell-level request dispatch. Pure protocol methods delegate to boundary.mcp.core.handlers; resources/read is handled here because it needs I/O (snapshot reflection, JSON serialization), the security gate, and the guardrail payload on denial.
deps is {:registry :security :audit :system-source :ai-provider}.
Shell-level request dispatch. Pure protocol methods delegate to
boundary.mcp.core.handlers; resources/read is handled here because it needs
I/O (snapshot reflection, JSON serialization), the security gate, and the
guardrail payload on denial.
`deps` is {:registry :security :audit :system-source :ai-provider}.Default evaluator for the Tier 2 eval tool. Reads and evaluates Clojure
forms in the server's own JVM, capturing the value and stdout.
This is RCE by design: the security gate restricts :execute to the :full
context (local dev), so this is never reachable in prod/CI. The evaluator is
injected as the :evaluator dep so it is swappable — an nREPL-bridge
evaluator can target the project's live REPL instead of the server JVM
(mirroring the SystemSource nREPL plan).
Default evaluator for the Tier 2 `eval` tool. Reads and evaluates Clojure forms in the server's own JVM, capturing the value and stdout. This is RCE by design: the security gate restricts :execute to the :full context (local dev), so this is never reachable in prod/CI. The evaluator is injected as the `:evaluator` dep so it is swappable — an nREPL-bridge evaluator can target the *project's* live REPL instead of the server JVM (mirroring the SystemSource nREPL plan).
Resolves guardrail payloads against the shared BND error catalog (boundary.devtools.error-codes — the single source of truth). The catalog lookup loads a resource (I/O), so it lives in the shell; payload assembly stays pure in boundary.mcp.core.guardrail.
Resolves guardrail payloads against the shared BND error catalog (boundary.devtools.error-codes — the single source of truth). The catalog lookup loads a resource (I/O), so it lives in the shell; payload assembly stays pure in boundary.mcp.core.guardrail.
Default migrator for the Tier 2 run-migration tool. Shells out to the
project's own :migrate alias in the current working directory.
Why shell out (like the test-runner): migrations need the project's full
classpath and config (datasource, env), not the MCP server's. Injected as the
:migrator dep, so it is swappable and stubbable in tests.
Default migrator for the Tier 2 `run-migration` tool. Shells out to the project's own `:migrate` alias in the current working directory. Why shell out (like the test-runner): migrations need the *project's* full classpath and config (datasource, env), not the MCP server's. Injected as the `:migrator` dep, so it is swappable and stubbable in tests.
Entry point. Resolves the security context from the environment, seeds the registry with the reflective resources, boots the stdio MCP server, and audits startup. Run with: clojure -M:run
Tool handlers added in BOU-100/101 must call
boundary.mcp.core.security/authorize against the context and record the
decision via the audit log before performing any mutation.
Entry point. Resolves the security context from the environment, seeds the registry with the reflective resources, boots the stdio MCP server, and audits startup. Run with: clojure -M:run Tool handlers added in BOU-100/101 must call `boundary.mcp.core.security/authorize` against the context and record the decision via the audit log before performing any mutation.
Newline-delimited JSON-RPC over stdin/stdout (MCP stdio transport). stdout carries protocol messages only; all logging goes to stderr so it never corrupts the message stream.
Newline-delimited JSON-RPC over stdin/stdout (MCP stdio transport). stdout carries protocol messages only; all logging goes to stderr so it never corrupts the message stream.
SystemSource adapters (BOU-99 / ADR-033). The in-process adapter reflects the project by reading its files and (later) the live Integrant system; the static adapter serves a fixed snapshot for tests. All I/O lives here so the core resource producers stay pure.
SystemSource adapters (BOU-99 / ADR-033). The in-process adapter reflects the project by reading its files and (later) the live Integrant system; the static adapter serves a fixed snapshot for tests. All I/O lives here so the core resource producers stay pure.
Default test-runner for the Tier 1 verify loop. Shells out to the project's own Kaocha runner in the current working directory and parses the result.
Why shell out rather than run in-process: Kaocha exposes no stable
programmatic API, and the affected tests must run in the project's full
classpath (H2, the module under test, fixtures) — not the MCP server's. The
runner is injected into the tool deps as :test-runner, so this is swappable
(and stubbed in unit tests).
The structured parse is best-effort over Kaocha's textual output; the raw output tail is always included so the agent has the real failure text even when a failure shape isn't recognized.
Default test-runner for the Tier 1 verify loop. Shells out to the project's own Kaocha runner in the current working directory and parses the result. Why shell out rather than run in-process: Kaocha exposes no stable programmatic API, and the affected tests must run in the *project's* full classpath (H2, the module under test, fixtures) — not the MCP server's. The runner is injected into the tool deps as `:test-runner`, so this is swappable (and stubbed in unit tests). The structured parse is best-effort over Kaocha's textual output; the raw output tail is always included so the agent has the real failure text even when a failure shape isn't recognized.
Executors for the MCP tools. All real work (running clj-kondo, Malli validation, project reflection, AI calls, scaffolding + the verify loop) lives here; the core stays a pure catalog. Each executor takes (args deps) and returns result data; throwing is fine — the dispatch maps it to an isError result.
Tier 0 (BOU-100): read/analyze. Tier 1 (BOU-101): generate — scaffold/write to disk (reversible via git) then run the closed verify loop (boundary.mcp.shell.verify).
Executors for the MCP tools. All real work (running clj-kondo, Malli validation, project reflection, AI calls, scaffolding + the verify loop) lives here; the core stays a pure catalog. Each executor takes (args deps) and returns result data; throwing is fine — the dispatch maps it to an isError result. Tier 0 (BOU-100): read/analyze. Tier 1 (BOU-101): generate — scaffold/write to disk (reversible via git) then run the closed verify loop (boundary.mcp.shell.verify).
Shell side of the Tier 1 closed verify loop (BOU-101). Runs the steps that touch the filesystem / subprocesses against the files a generate tool just wrote, and hands the raw results to boundary.mcp.core.verify for the pure report assembly.
Steps:
core-source-paths discovery.:test-runner
(a fn of the module name). The runner is injected, not hardcoded,
because there is no stable programmatic Kaocha API and the tests
must run in the project's classpath, not the MCP server's; the
default shell-out runner lives in boundary.mcp.shell.test-runner.
Absent runner → an honest :unavailable step (never a silent pass).Malli validation of the generate request happens in the scaffolder service
before any file is written; its failures arrive as :errors on the generate
result and are surfaced by the core report, so there is no separate Malli
step here.
Shell side of the Tier 1 closed verify loop (BOU-101). Runs the steps that
touch the filesystem / subprocesses against the files a generate tool just
wrote, and hands the raw results to boundary.mcp.core.verify for the pure
report assembly.
Steps:
* kondo — clj-kondo over the written .clj files (static; in-process).
* fcis — boundary.tools.check-fcis/check-file over written core/ files,
so FC/IS (BND-806) violations are caught per-file regardless of
the monorepo's `core-source-paths` discovery.
* tests — the project's affected tests, via an injected `:test-runner`
(a fn of the module name). The runner is injected, not hardcoded,
because there is no stable programmatic Kaocha API and the tests
must run in the *project's* classpath, not the MCP server's; the
default shell-out runner lives in boundary.mcp.shell.test-runner.
Absent runner → an honest :unavailable step (never a silent pass).
Malli validation of the generate *request* happens in the scaffolder service
before any file is written; its failures arrive as `:errors` on the generate
result and are surfaced by the core report, so there is no separate Malli
step here.cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |