Canonical rules file for this repository (project-specific requirements only). Last updated: February 2026
- Project Overview
- File Headers and Licensing
- Coding Style
- Object-Oriented Design Requirements
- Low-Code / High-Config Design Pattern
- Docker-First Development
- Async Programming Requirements
- Security-First Design
- Unit and Architecture Testing Requirements
- Documentation Standards
- Git Workflow
- Single-Method Architecture (No Fallbacks)
- Context Compaction Preflight (Strict)
- Forbidden Actions
- Quick Reference
The MCP C++ SDK is a C++20 implementation of the Model Context Protocol with client, server, transport, and auth components.
<repo-root>/
├── include/ # Public SDK headers
│ └── mcp/
├── src/ # Implementation code
│ ├── mcp/
│ └── logging/
├── tests/ # GoogleTest suites (required)
│ └── http/
├── docs/ # API and architecture docs
├── scripts/ # Build/test helper scripts
├── Dockerfile
├── Dockerfile.demo
├── CMakeLists.txt
└── BUILD+TEST.MD
- C++20 - primary implementation language
- CMake - build system
- GoogleTest - test framework
- Docker - required build/test execution environment
All C++, header, CMake, shell, YAML, and Markdown files MUST include SPDX/license header blocks matching repository style.
// SPDX-License-Identifier: MIT
// Copyright (c) 2025 Vinny Parla
// File: src/mcp/SomeFile.cpp
// Purpose: Brief description<!--
==========================================================================================================
SPDX-License-Identifier: MIT
Copyright (c) 2025 Vinny Parla
File: docs/some-file.md
Purpose: Brief description
==========================================================================================================
-->The File: path MUST be repository-relative, not absolute.
| Element | Convention | Example |
|---|---|---|
| Classes/structs | PascalCase | JsonRpcMessageRouter |
| Public methods | PascalCase | Connect(), Initialize() |
| Local vars/params | camelCase | sessionId, transportFactory |
| Constants/macros | UPPER_SNAKE_CASE | MAX_MESSAGE_SIZE |
| Files | PascalCase or snake_case (existing style) | Client.cpp, test_client_cache.cpp |
- Follow existing style in neighboring files; do not mix incompatible naming styles in one file.
- Keep includes minimal and correctly layered (
include/mcpcontract first, internal impl second). - Avoid hidden global state.
- Prefer RAII and explicit ownership over raw lifecycle management.
Before adding new code, check existing shared abstractions and extend them first:
- Reuse public interfaces under
include/mcp/instead of adding parallel APIs. - Reuse transport/auth base abstractions before creating protocol-specific forks.
- If a behavior is needed in 2+ modules, move it to shared/core components.
Forbidden:
- Copy/pasting transport framing logic across implementations.
- Re-implementing auth parsing independently in multiple files.
- Creating one-off client/server behavior that bypasses common validation pathways.
Runtime behavior should be driven by configuration, protocol metadata, and capabilities instead of hardcoded special cases.
- Capability negotiation and metadata must drive behavior where applicable.
- Prefer declarative validation/config over branching on one-off literals.
- Keep hardcoded environment/service assumptions out of protocol paths.
All development, build, and test execution MUST run inside Docker.
- Build with Docker (
Dockerfile/Dockerfile.demo). - Run all tests inside Docker containers.
- Use WSL-based Docker flow on Windows.
Every operational command in docs must be provided in this order:
- Linux/macOS (Bash)
- Windows (PowerShell via WSL)
The SDK is async-heavy and must remain non-blocking in critical paths.
- Use
std::future/std::asyncand callback patterns consistently with existing APIs. - Honor cancellation semantics where exposed.
- Avoid blocking operations on transport event paths.
- Protect shared state with correct synchronization discipline.
- Blocking waits in notification handlers.
- Detached background work without lifecycle control.
- Cross-thread data mutation without synchronization.
- Validate all inbound JSON-RPC and transport payloads.
- Do not trust client-supplied metadata without validation.
- Keep auth/token handling centralized and redact sensitive logs.
- Fail closed on malformed, ambiguous, or unauthorized requests.
- All behavior changes require tests.
- Existing tests must remain green.
- Regression tests are required for bug fixes.
All code must comply with architecture test constraints:
- Layer boundaries: public API headers, core logic, transport implementations, and auth modules remain separated.
- Shared-first enforcement: no duplicate implementation of shared concerns.
- Validation path enforcement: protocol handling must pass through canonical validators.
Before any new protocol-parity or feature-phase implementation proceeds:
tests/test_architecture_enforcement.cppMUST exist and be compiled into the GoogleTest target.- Architecture enforcement tests MUST run and pass in Docker before running broader suites.
- If architecture enforcement fails, feature work is blocked until violations are fixed.
- Changes that remove or bypass architecture enforcement are forbidden.
A change is not merge-ready unless:
- Unit tests pass in Docker.
- Architecture/contract tests pass.
- No layering or duplication violations are introduced.
- Keep docs consistent with actual commands and file paths.
- No references to local absolute paths in committed docs.
- Keep README and BUILD+TEST guidance synchronized with CI behavior.
<type>: <short description>
Types:
featfixdocstestrefactorchore
- Build and test in Docker.
- Add/update tests.
- Verify docs if behavior changed.
Use one canonical method per concern. Do not add silent fallback paths.
- Try one parser then silently fallback to another implementation.
- Support legacy + new schema in parallel indefinitely.
- Quietly bypass required config with hardcoded defaults.
- Fail loudly on missing required dependencies/config.
- Migrate call sites to canonical pathways.
- Remove legacy branches once canonical path exists.
Before any summarization, context-window compaction, handoff note generation, or automation-generated session compression, a strict preflight check MUST run.
Compaction without preflight is forbidden.
Preflight MUST build a criticalContextManifest containing all non-negotiable items:
- Hard requirements and prohibitions (
MUST,MUST NOT, release blockers) - Security and compliance constraints
- Open decisions, unresolved risks, and explicit assumptions
- Canonical identifiers and references:
- repository, branch, commit hash
- file paths and required environment variable names
- transport mode/runtime mode selections
- Validation and acceptance criteria:
- required Docker builds/tests and pass/fail gates
- Active user-requested constraints for the current session
Compaction may proceed ONLY if all gates pass:
- Coverage Gate (100%) - every manifest item exists in compacted output
- Integrity Gate (0 drift) - values and constraints are unchanged
- Contradiction Gate - no compacted statement conflicts with canonical rules or current user constraints
- Traceability Gate - compacted output preserves pointers to source files/sections used for critical decisions
- Confidence Gate - low-confidence semantic matches require human confirmation
If any gate fails:
- Reject compaction
- Retain full context
- Emit a preflight failure report listing:
- missing items
- changed values
- contradictions found
- Block downstream execution/merge until preflight passes
- Any workflow step that compacts/summarizes context MUST run
preflight_context_checkfirst - Protected branches MUST reject changes when preflight artifacts are missing or failing
- Bypass flags for preflight are forbidden in CI and production automation
Each compaction run MUST persist machine-readable artifacts:
preflight-manifest.jsonpreflight-result.jsoncompaction-diff-report.md
Required fields in preflight-result.json:
coveragePercentintegrityStatuscontradictionCountconfidenceStatusapprovedBy(automation or human reviewer identity)
- Running tests outside Docker.
- Bypassing architecture test constraints for convenience.
- Duplicating shared core logic in feature modules.
- Introducing blocking async anti-patterns.
- Committing secrets or credentials.
- Merging untested code.
# Linux/macOS (Bash)
docker buildx build -f Dockerfile.demo --target test --progress=plain --pull --load -t mcp-cpp-test .
docker run --rm mcp-cpp-test ctest --test-dir build --output-on-failure
# Windows (PowerShell via WSL)
wsl -d Ubuntu -- bash -lc "cd /mnt/c/<path-to-repo>/mcp-cpp && docker buildx build -f Dockerfile.demo --target test --progress=plain --pull --load -t mcp-cpp-test ."
wsl -d Ubuntu -- bash -lc "cd /mnt/c/<path-to-repo>/mcp-cpp && docker run --rm mcp-cpp-test ctest --test-dir build --output-on-failure"| Date | Version | Changes |
|---|---|---|
| 2026-02 | 1.0 | Initial AGENTS.md for mcp-cpp, adapted from key governance elements |
| 2026-02 | 1.1 | Expanded context compaction preflight policy with blocking gates and fail-closed enforcement |
| 2026-02 | 1.2 | Added explicit architecture-enforcement-first gate requirements for phased implementation |