Skip to main content

Epistemic discipline and anti-patterns

The MCP server returns structured data; the LLM generates content from it. Putting the two together creates a temptation: presenting LLM inferences as if they were manual facts. For the output to earn the trust of auditors, legal counsel and security champions, every statement must be labellable. And a manual-grounded label says where the requirement comes from, not that the code meets it: verifying the implementation requires tests and review.

The 4 epistemic labels​

LabelDefinitionGreen light for the user
manual-groundedRetrieved via MCP — cite chapterId or ID (CTRL-*, <CAT>-NNN, MT-*, ART-*)"The manual says: AUT-001 (MFA mandatory). <texto verbatim ou parafraseado fielmente>."
observedDirectly visible in the repository / codebase"In file src/auth/login.ts:42, I observe: <…>."
inferredA logical conclusion drawn from grounded + observed — mark it explicitly"Inference: given that AUT-001 requires MFA, and the code only validates the password, the second factor is missing."
not verifiedNot confirmed"Not verified: <…>. Human inspection / test / log is recommended."

Golden rule​

When in doubt, prefer not verified to presenting something as fact.

Marking as not verified lets the user act; wrongly marking as manual-grounded creates false positives that cost review effort and credibility.


Where to apply each label​

manual-grounded​

Allowed only when:

  • Returned by an MCP tool (consult_*, get_*, query_*, resolve_*, prepare_*)
  • The cited ID exists in the output of the call
  • The text reflects what the output says (neither amplifies nor reduces it)

❌ Do not mark as grounded:

  • Results of search_sbd_toe_manual that were not read (only seen as a snippet) — those are a lead, not evidence
  • Cross-tool synthesis (e.g. "AUT-001 + LOG-003 imply X") — that is inferred

observed​

Allowed only when:

  • The file/line was read (not inferred from the file name)
  • The observation is literally verifiable

❌ Do not mark as observed:

  • "The system probably does X" — without having read the code
  • Behaviour expected because of the framework — that is inferred

inferred​

Always mark explicitly when:

  • manual-grounded + observed are combined to reach a conclusion
  • General security knowledge is applied to a specific context
  • A link without mitigation_confidence: "derived" is extended to another situation

Recommended form: "Inference: <conclusão>. Based on: <grounded ID> + <observação>."

not verified​

Use generously. Cases:

  • The tool returned an empty list (controls: [], threats: [], assignments: [])
  • The risk level was not confirmed by the user
  • The result needs a test / scan / log that has not run yet
  • The question touches content later than the served snapshot (see sbd://toe/version)

MCP-specific confidence flags​

Some tools return their own confidence fields. Translate them into labels:

MCP fieldTranslation
mitigation_confidence: "derived"manual-grounded (structural link)
link without mitigation_confidence: "derived"inferred — flag explicitly
completeness_report.m_recall < 1.0signal partial coverage — what is missing is not verified
coverage.hasMore: true / coverage_gapsa paginated / with declared gaps result — continue via nextOffset; the server is coverage-preserving (nothing silently truncated), but "page 1" ≠ "everything"
rule_trace without CONCERNS_FILTER_* when concerns were passeda sign of a problem — it may be returning more than was filtered for

General anti-patterns​

1. Inventing IDs​

❌ "Control CTRL-09-99 covers this." ✅ Verify via query_sbd_toe_entities({query: "CTRL-09-99"}) before citing. If it does not exist, say: "No applicable control found in the manual for this case — flag for human review."

2. Declaring regulatory compliance​

❌ "This code is compliant with NIS2 Art. 21." ✅ "The manual's NIS2 cross-check maps Art. 21 ↔ chapters N and M. Not a declaration of compliance — it requires an assessment by legal counsel + operational evidence."

3. Treating code as evidence​

❌ "I implemented the lockout, so the control is covered." ✅ "Proposed implementation. Expected evidence: a test in test/auth/lockout.spec.ts + log entry auth.lockout.activated with schema X."

4. Merging manual-grounded with inferred​

❌ "The manual says that rate limiting + monitoring prevent credential stuffing." ✅ "Manual-grounded: the output links MT-NNN (credential stuffing) to CTRL-<domain>-<slug>-<hash> with mitigation_confidence: derived. Inference (mine): applied together they cover the threat — marked as an inference, not as a fact from the manual."

5. Skipping the needs_clarification / needs_decomposition gate​

❌ Calling prepare_sbd_toe_codegen_context again with the same payload to "try again". ✅ Stop, talk with the user, call again only after new inputs.

6. Showing an inferred link as a certainty​

❌ "CTRL-… mitigates MT-NNN." — presented as a certainty, without mitigation_confidence: "derived". ✅ "CTRL-… mitigates MT-NNN — an inferred link (without mitigation_confidence: derived); validate with a test / human review."

7. Assuming the snapshot coverage without confirming it​

❌ Answering about a normative cross-check (or any page) assuming that the MCP serves it — or that it does not. ✅ Read sbd://toe/version (manual, KG, ontology) and, when in doubt, validate with inspect_sbd_toe_retrieval whether the document appears among the top-ranked records. The published normative cross-checks — CRA / DORA / NIS2 / GDPR / AI Act / ENISA-CSA — are indexed in the served snapshot; content later than the snapshot lives only in the web manual until the next publication (see content lag).

8. Confusing (ontological) concerns with STRIDE domains​

❌ concerns: ["spoofing", "tampering"] ✅ concerns: ["auth", "integrity"] — the ontological vocabulary is closed and maps to STRIDE domains indirectly.

9. Skipping setup_sbd_toe_agent at the start of the session​

❌ Starting to call tools without initialising. ✅ First message of the security session: setup_sbd_toe_agent(riskLevel, projectRole) — it loads the per-chapter demand and the role rules. In clients that do not expose prompts (such as Claude Desktop), start with sbd://toe/quick-start and the declaration in select_sbd_toe_requirements.

10. Regenerating the skill at the start of every session​

❌ Calling generate_sbd_toe_skill() every time. ✅ Generate once, save it at the canonical path (.claude/skills/sbd-toe.md, etc.), regenerate only after an upgrade of the MCP.

11. Confusing "consuming MCP" with "exposing an MCP server" (distinct security scope)​

This mini-site covers the use of the MCP server SbD-ToE — consumption. When the organisation starts to expose its own MCP server (not consume one), it enters an additional security scope that is not covered by this mini-site nor by the SbD-ToE manual in general.

❌ Assuming that reading this mini-site covers the security of an MCP server to be published by the organisation. ✅ For exposed MCP servers, consult the OWASP MCP Top 10 (2025) — a dedicated catalogue that covers prompt injection in an MCP context, tool poisoning, excessive permissions, inadequate authentication/authorisation, insecure transport, input validation, output handling, insufficient monitoring and insecure defaults. The relevant SbD-ToE controls (ARC-015, REQ-AGN-001..004, OPS-011..014, Policy 38, Policy 39) apply directly — the OWASP MCP Top 10 works as a specific coverage checklist, complementary to the threat modelling of Ch. 03 §playbook-agentic.


Rigour checklist before submitting any output​

  1. Does every statement carry one of the 4 labels?
  2. Do all cited IDs exist in MCP outputs from the session?
  3. Are links without mitigation_confidence: derived marked as inferred?
  4. Was m_recall < 1.0 flagged?
  5. Is there no declaration of compliance?
  6. Was code not presented as evidence?
  7. For regulatory questions — was the snapshot coverage confirmed in sbd://toe/version (and the web manual consulted for later content)?

If any check fails → review before delivering.

Next steps​