Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ uv run pytest # full suite
uv run pytest tests/test_<module>.py -v # one module
```

Run `uv run pytest --collect-only -q | tail -1` for the live test count (last refresh: 3,232 tests collected, 2026-06-04). New backend protocols add ~25 conformance + ~10 impl-specific tests. New features ship with tests. Migration-shaped PRs need parameterized fixture tests across the backend protocol — the conformance suite is what keeps the protocol honest.
Run `uv run pytest --collect-only -q | tail -1` for the live test count (last refresh: 3,307 tests collected, 2026-06-04). New backend protocols add ~25 conformance + ~10 impl-specific tests. New features ship with tests. Migration-shaped PRs need parameterized fixture tests across the backend protocol — the conformance suite is what keeps the protocol honest.

### Releases + SemVer

Expand Down Expand Up @@ -341,7 +341,7 @@ These are not forbidden forever — they're explicitly deferred with rationale.

## Status

**v0.13.0, alpha, PUBLIC.** Core runtime stable. Test suite: run `uv run pytest --collect-only -q | tail -1` for the live count (last refresh: 3,232 tests collected, 2026-06-04). Capability-gated skips fall into four buckets — ToolRegistry conformance (filesystem-shape + `supports_uninstall=False` variants), AgentProfile (skill-content + filesystem-shape on SQLite), cross-process Redis (require real Redis instead of fakeredis), and judge-conformance dispatch (LLM-only + PolicyJudge concurrent-evaluate). Full CI runs against `uv sync --extra dev --extra openai --extra validation --extra redis`. **Eleven backend protocols shipped**:
**v0.13.0, alpha, PUBLIC.** Core runtime stable. Test suite: run `uv run pytest --collect-only -q | tail -1` for the live count (last refresh: 3,307 tests collected, 2026-06-04). Capability-gated skips fall into four buckets — ToolRegistry conformance (filesystem-shape + `supports_uninstall=False` variants), AgentProfile (skill-content + filesystem-shape on SQLite), cross-process Redis (require real Redis instead of fakeredis), and judge-conformance dispatch (LLM-only + PolicyJudge concurrent-evaluate). Full CI runs against `uv sync --extra dev --extra openai --extra validation --extra redis`. **Eleven backend protocols shipped**:

- **MemoryBackend** (PR #57) — filesystem reference impl + conformance suite.
- **LLMBackend** (#87) — Anthropic + OpenAI + Moonshot reference impls, registered at framework import; conformance suite parametrizes across all three.
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ Start at [`docs/README.md`](docs/README.md) for the spec entry point. The locked
- [33 — PersonaBackend Protocol](docs/spec/33-persona-backend.md) — persona ownership, snapshot/restore, `persona.link.md` format
- [34 — CorpusBackend Protocol](docs/spec/34-corpus-backend.md) — wiki/raw corpus protocol; filesystem + SQLite (FTS5) reference impls; GB-scale indexed full-text search
- [35 — init wizard](docs/spec/35-init-wizard.md) — `atomic-agents init` on-ramp; template scaffolding + Add-to-it merge; CI-friendly `--from-template` (RFC)
- [36 — MCPServerRegistryBackend Protocol](docs/spec/36-mcp-server-registry-backend.md) — MCP server catalog + install/audit; `FilesystemMCPServerRegistryBackend` reference impl; `atomic-agents mcp-registry` CLI (DRAFT, PR 3 of 5)
- [36 — MCPServerRegistryBackend Protocol](docs/spec/36-mcp-server-registry-backend.md) — MCP server catalog + install/audit; `FilesystemMCPServerRegistryBackend` reference impl; `HTTPMCPServerRegistryBackend` reference impl with tier-1/2/3 capability negotiation; `atomic-agents mcp-registry` CLI (DRAFT, PR 4 of 5)

Each spec doc is locked when the implementation matches and tests pass. Spec changes that imply implementation changes get filed as GitHub issues. **Spec docs separate shipped behavior from explicit future / deferred boundaries** — sections that describe behavior not yet implemented are explicitly marked as such, not silently aspirational.

Expand All @@ -205,7 +205,7 @@ The framework is moving toward swappable backends layer by layer. The shape: a P
| `PolicyBackend` | ✅ Shipped | Filesystem reference impl (`policy.md` at project root); cost-cap MIN composition + tool / MCP / model surfaces enforced by default (PR 4 flag flip); unified `policy_decision` audit event family | [`spec/32`](docs/spec/32-policy-backend.md) |
| `PersonaBackend` | ✅ Shipped | Filesystem reference impl at `<scope_root>/.personas/<persona_id>/`; `persona.link.md` ownership trigger; snapshot trio nested under each persona's directory; `atomic-agents persona` CLI; AgentProfile composition with migration-window restore event | [`spec/33`](docs/spec/33-persona-backend.md) |
| `CorpusBackend` | ✅ Shipped | Filesystem + SQLite (FTS5) reference impls; per-agent `wiki/` + `raw/`; `render_index_summary(corpus)` Protocol method; closes the GB-scale wiki cliff via O(log N) indexed full-text query | [`spec/34`](docs/spec/34-corpus-backend.md) |
| `MCPServerRegistryBackend` | Planned | Catalog + install/audit for MCP servers (MCP equivalent of ToolRegistry) | [`#201`](https://github.com/dep0we/atomic-agents-stack/issues/201) |
| `MCPServerRegistryBackend` | 🟡 In progress (PR 4 of 5) | Filesystem + HTTP read-path reference impls; tier-1/2/3 capability negotiation; `atomic-agents mcp-registry` CLI; write paths (install/uninstall) ship at PR 5 | [`spec/36`](docs/spec/36-mcp-server-registry-backend.md) |

**v1 direction:** a home user runs filesystem-everything today. An organization runs the same agent definitions over Postgres / Redis / SQLite-Datadog / behind an HTTP service once the remaining protocol ships. v1.0 closes when MCPServerRegistry lands + its conformance suite pins the contract. See [`docs/architecture.md`](docs/architecture.md) for the mental model, [`docs/TENSIONS.md`](docs/TENSIONS.md) for architectural tensions this scaling story has to survive, and [`ROADMAP.md`](ROADMAP.md) for the full backlog beyond v1.0.

Expand Down Expand Up @@ -282,7 +282,7 @@ Same pattern for OpenAI (`atomic-agents-openai`) and Moonshot (`atomic-agents-mo
## Repository structure

- `atomic_agents/` — the Python package (runtime in `agent.py`; backend protocols in `memory/`, `_llm.py`, `_locks.py`, `_costs.py`, etc.; CLI in `cli.py`; preflight in `doctor.py`)
- `tests/` 3,232 tests collected, Python 3.11 + 3.12 matrix
- `tests/` 3,307 tests collected, Python 3.11 + 3.12 matrix
- `docs/` — [spec entry point](docs/README.md), [`architecture.md`](docs/architecture.md), [`spec/`](docs/spec/) (31 locked docs + 4 RFCs/DRAFTs), [`deployment/`](docs/deployment/) (8 operator runbooks), [`samples/caldwell/`](docs/samples/caldwell/) (complete worked example), [`GOVERNANCE.md`](docs/GOVERNANCE.md), [`TENSIONS.md`](docs/TENSIONS.md), [`methodology.md`](docs/methodology.md)
- `extras/` — operational templates (Claude Code skill wrappers, macOS LaunchAgent plists, cron examples)

Expand Down Expand Up @@ -313,4 +313,4 @@ Before opening a PR, read [`CLAUDE.md`](CLAUDE.md) (the project's design ethos a

## Status

**v0.13.0, alpha.** Core runtime stable. 3,232 tests collected on Python 3.11 / 3.12. Eleven of twelve backend protocols shipped (see the backend protocols table above); `MCPServerRegistryBackend` in progress (PR 3 of 5). The surface stabilizes at v1.0. Pre-1.0 — Minor releases may contain breaking changes (see [`docs/deployment/versioning.md`](docs/deployment/versioning.md)). Single-maintainer project; reference implementation anyone can use, fork, or extend.
**v0.13.0, alpha.** Core runtime stable. 3,307 tests collected on Python 3.11 / 3.12. Eleven of twelve backend protocols shipped (see the backend protocols table above); `MCPServerRegistryBackend` in progress (PR 4 of 5). The surface stabilizes at v1.0. Pre-1.0 — Minor releases may contain breaking changes (see [`docs/deployment/versioning.md`](docs/deployment/versioning.md)). Single-maintainer project; reference implementation anyone can use, fork, or extend.
42 changes: 42 additions & 0 deletions atomic_agents/mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,48 @@ class MCPServerSpec:
transport: str = "stdio"
description: str = ""

def to_dict(self) -> dict:
"""Serialize to a JSON-safe plain dict.

Note: ``env`` may contain resolved values (the ``$VAR_NAME``
references in source ``mcp.md`` are resolved to literal env-var
values at load time). Callers serializing to a shared log or audit
backend SHOULD treat the ``env`` field as sensitive. The raw text
on the profile (``mcp_md_raw``) is the safe-to-ship form.

Returns a fresh dict every call; callers may mutate freely.
"""
return {
"name": self.name,
"command": self.command,
"args": list(self.args),
"env": dict(self.env),
"transport": self.transport,
"description": self.description,
}

@classmethod
def from_dict(cls, d: dict) -> "MCPServerSpec":
"""Reconstruct an ``MCPServerSpec`` from a dict produced by ``to_dict()``.

Required keys (``name``, ``command``) raise ``KeyError`` if absent.
Optional keys (``args``, ``env``, ``transport``, ``description``) fall
back to field defaults. Extra keys in ``d`` are silently ignored for
forward-compatibility with future wire format extensions.

Applies copy-constructor discipline: ``args`` and ``env`` values are
copied out of ``d`` to prevent callers from accidentally sharing
mutable state with the dict passed in.
"""
return cls(
name=d["name"],
command=d["command"],
args=list(d.get("args", [])),
env=dict(d.get("env", {})),
transport=d.get("transport", "stdio"),
description=d.get("description", ""),
)


@dataclass
class MCPToolMeta:
Expand Down
19 changes: 18 additions & 1 deletion atomic_agents/mcp_registry/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,30 @@ def get_default_mcp_server_registry_backend(
if raw_backend_id == "filesystem":
return FilesystemMCPServerRegistryBackend(agent_root, read_paths)

elif raw_backend_id == "http":
# Lazy import: filesystem operators do not pay the httpx import cost.
from .http import make_http_mcp_server_registry_backend_from_url

url = os.environ.get(
"ATOMIC_AGENTS_MCP_SERVER_REGISTRY_BACKEND_URL", ""
).strip()
if not url:
raise BackendNotRegistered(
"ATOMIC_AGENTS_MCP_SERVER_REGISTRY_BACKEND=http requires "
"ATOMIC_AGENTS_MCP_SERVER_REGISTRY_BACKEND_URL to be set. "
"Expected format: https://<host>[:port]/?agent_scope=<name>"
)
return make_http_mcp_server_registry_backend_from_url(url)

# Unknown backend_id. Sanitize before echoing in the error message to
# prevent credential leaks when operators accidentally paste a URL into
# ATOMIC_AGENTS_MCP_SERVER_REGISTRY_BACKEND instead of the _URL variable.
known_ids = {"filesystem", "http"}
safe_backend_id = _redact_for_error_message(raw_backend_id)
raise BackendNotRegistered(
f"ATOMIC_AGENTS_MCP_SERVER_REGISTRY_BACKEND={safe_backend_id!r} is not a "
f"known backend. Available: {list_mcp_server_registry_backends()}. "
f"known backend. Known: {sorted(known_ids)}. "
f"Available registered: {list_mcp_server_registry_backends()}. "
f"Unset the env var to use the filesystem default."
)

Expand Down
Loading
Loading