0d2cbdb423
Genericize forge-detection code: gitea→forge/generic_forge, GITEA_ACTOR→FORGE_ACTOR. Drop .gitea byte-identity test assertions (keep GitHub-side + contract conformance). Add test_no_forge_mentions.py guard test (REQ-230). Delete completed migration docs (NOVA_MIGRATION.md, NOVA_AWS_MIGRATION.md). Move NO_HUMANS_THESIS.md to .ciagent/ (internal artifact). Strip ciagent-internal provenance from synced docs (REQ-/D-/P-/CAP- IDs, milestone headers, .ciagent/PROJECT.md citations). Trim README.md (reusable deploy section, local key rotation paragraph). Fix version-tag drift (@v1.13→@v1.19, acdl/→nova/). ---ci--- project: acdl phase: 1 milestone: v1.20 status: execute requirements: [REQ-230, REQ-231, REQ-232] ---/ci---
95 lines
3.6 KiB
Markdown
95 lines
3.6 KiB
Markdown
# Nova Atelier MCP Server
|
|
|
|
> exposes Atelier engineering principles to the citizen developer's AI
|
|
> agent. Plugin-registry architecture; stdio transport;
|
|
> vendored Atelier for audit reproducibility.
|
|
|
|
## What This Is
|
|
|
|
The server exposes 4 tools that let a citizen developer's AI coding agent
|
|
look up production-grade engineering principles and validate code against
|
|
them — agentic validation that goes **beyond deterministic scanners**
|
|
(Wiz, Checkmarx, Mend) by catching correctness, clarity, simplicity, and
|
|
observability gaps.
|
|
|
|
## Tools
|
|
|
|
| Tool | Description |
|
|
|---|---|
|
|
| `atelier.lookup_principle(domain, principle_id)` | Look up a principle by domain + P-rule ID (e.g., `security`, `P4`). Returns the principle text + the core C-rule it derives from. |
|
|
| `atelier.list_domains()` | List the 19 Atelier domains with P-rule counts + Nova-relevance. |
|
|
| `atelier.matrix_lookup(domain)` | Look up the domain→core principle mapping for a given domain. |
|
|
| `atelier.validate_against_principles(snippet, domains?)` | Validate a code/diff snippet against the Atelier agent-checklist. Returns pass/fail per check item with the principle citation. |
|
|
|
|
## Architecture — Plugin Registry
|
|
|
|
```
|
|
mcp/atelier/
|
|
├── server.py # entrypoint: loads plugins, starts server
|
|
├── plugins/
|
|
│ ├── __init__.py
|
|
│ ├── principles.py # lookup_principle, list_domains, matrix_lookup
|
|
│ └── validation.py # validate_against_principles
|
|
├── vendor/ # pinned Atelier snapshot
|
|
│ ├── VERSION.md # pinned tag + upgrade instructions
|
|
│ ├── core/first-principles.md
|
|
│ ├── domains/security/first-principles.md
|
|
│ ├── review/agent-checklist.md
|
|
│ └── matrix/principles-matrix.md
|
|
└── README.md # this file
|
|
```
|
|
|
|
Each plugin module exposes `register(mcp) -> None` and calls `@mcp.tool()`
|
|
for its tools. `server.py` scans `plugins/` and calls `register` on each.
|
|
**Future capabilities drop in as a new plugin file — no `server.py` edits.**
|
|
|
|
## Running
|
|
|
|
### With the MCP Python SDK installed
|
|
|
|
```bash
|
|
pip install "mcp[cli]"
|
|
python3 -m mcp.atelier.server
|
|
```
|
|
|
|
The server runs over stdio. An MCP client (e.g., the citizen developer's
|
|
AI coding agent) spawns it as a subprocess and calls tools via JSON-RPC.
|
|
|
|
### Without the SDK (fallback / test mode)
|
|
|
|
The server degrades to a plain-Python tool registry. Tools are callable
|
|
directly — this is how tests run without the SDK installed:
|
|
|
|
```python
|
|
from mcp.atelier.server import NovaAtelierServer
|
|
s = NovaAtelierServer()
|
|
s.load_plugins()
|
|
result = s.call_tool("atelier_lookup_principle", {"domain": "security", "principle_id": "P4"})
|
|
```
|
|
|
|
## Vendoring
|
|
|
|
Atelier is vendored under `vendor/` at a pinned tag (`v0.3.6`, see
|
|
`vendor/VERSION.md`). An agentic validation result is only reproducible if
|
|
the principles that produced it are pinned. Live-fetch breaks replayability
|
|
(Atelier `main` drifts). To upgrade:
|
|
|
|
```bash
|
|
bash scripts/update_atelier_vendor.sh <new-tag>
|
|
```
|
|
|
|
## Extensibility
|
|
|
|
To add a new tool (e.g., a cost-estimation tool, a policy-as-code
|
|
evaluator): create `plugins/<name>.py`, expose `register(mcp)`, and call
|
|
`@mcp.tool()` on your function. The server picks it up automatically. No
|
|
`server.py` edit. This is the extensibility insurance for future
|
|
capabilities.
|
|
|
|
## Transport
|
|
|
|
- **Now:** stdio (local agent consumption — the citizen developer's AI
|
|
agent spawns the server as a subprocess).
|
|
- **Future:** Streamable HTTP (the MCP SDK supports it on the same
|
|
`MCPServer` object; adding it is a transport-only change in `server.py`,
|
|
not a rewrite). |