feat: add agnoctl, the unified Agno CLI (connect, tokens, create, infra)#8743
Closed
ashpreetbedi wants to merge 5 commits into
Closed
feat: add agnoctl, the unified Agno CLI (connect, tokens, create, infra)#8743ashpreetbedi wants to merge 5 commits into
ashpreetbedi wants to merge 5 commits into
Conversation
… modes Router dependencies never run for mounted sub-apps, so the MCP app served at /mcp was completely unauthenticated in security-key mode, and service account tokens were never checked there either. Add a dedicated middleware to the MCP sub-app when JWT mode is not active, mirroring the REST rules from agno.os.auth.get_authentication_dependency: accept the OS_SECURITY_KEY (constant-time compare) or a valid agno_pat service account token (with principal and scopes attached to request.state for attribution), stay open when auth is fully disabled, and map verifier statuses to the same 401/429/503 responses as REST. JWT mode is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Extends the unauthenticated /info endpoint with:
- mcp: {enabled, path} reporting MCP server availability (path /mcp when enabled)
- auth_mode: the effectively enforced authentication mode (none / security_key / jwt)
auth_mode mirrors the precedence in get_authentication_dependency: JWT
(authorization=True or JWT env config) takes precedence over the OS
security key. This lets external tools (agno connect CLI) discover the
OS configuration without probing or 401-detail sniffing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New distribution libs/agno_cli (PyPI: agnoctl, module: agno_cli, command: agno). Talks plain HTTP to a running AgentOS; never imports the agno framework. - agno connect: discover the AgentOS (structured /info fields with probe fallback), mint one service account per coding agent, write MCP configs for Claude Code (claude mcp add, .mcp.json fallback), Codex (config.toml section-scoped edit), and Cursor (mcp.json merge), then verify each connection with a real MCP initialize + tools/list handshake. Idempotent: working entries are skipped, broken ones rotated; --rotate/--skip-existing for non-interactive control. - agno tokens create/list/revoke: thin wrappers over /service-accounts. - agno status: discovered OS, auth mode, MCP URL, per-client config state. - Agent-operator contract: --json on every command, deterministic exit codes (0 ok, 1 failure, 2 partial), no prompts in JSON mode, tokens never logged. - Plugin seam: agno_cli.plugins entry-point group mounts external Typer apps. - 54 tests against an in-memory fake AgentOS (httpx.MockTransport) and tmp client config dirs; ruff and mypy clean; wired into scripts/format.sh and scripts/validate.sh. Design doc: specs/agno/features/agno-cli/ (uvx agno connect lands via a follow-up two-line change in libs/agno once agnoctl is on PyPI). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…al review One CLI: port the used surface of the legacy ag infra CLI so agno-infra can drop its console scripts without a capability gap. - agno create NAME [-t agentos-docker|agentos-aws|agentos-railway] [-u URL]: shallow-clone the template, strip git history, copy example secrets. No registry file: commands operate on the working directory. - agno infra up/down/restart: the docker compose path (same detection names and command lines as the legacy CLI, plus --file/--volumes/--dry-run/--json). The legacy per-resource Docker/AWS engine is deliberately not ported; it plugs in later via the agno_cli.plugins entry-point group. Review fixes (23 findings from a 29-agent adversarially verified review): - Codex TOML rewrite no longer swallows [[array-of-tables]] sections or trailing comments; refuses to modify unparseable configs. - JSON config writers refuse to clobber corrupt files and malformed mcpServers shapes; chmod 600 whenever a token is written. - Claude Code: read follows real scope precedence (local > project > user); user-scope file fallback targets ~/.claude.json instead of a VCS-shared .mcp.json; subprocess calls get timeouts and no inherited stdin. - connect: per-client isolation catches all exceptions (keeps the --json single-document contract); --skip-existing never touches entries pointing at a different AgentOS; post-write read-back verifies the entry the client will actually use (catches shadowing and dropped headers); --privileged passthrough; partial success exits 3 (2 stays click's usage-error code). - Context-correct 409 hints; hardened response parsing; verify_mcp honors its never-raises contract. 78 tests; ruff and mypy clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The compose lifecycle is the hero path, and the compose file runs the whole project (AgentOS included), so the infra noun under-described it. Root verbs match the two-tier dev story (agno dev for in-process reload later, agno up for container parity) and keep the quickstart to four commands: agno create my-os && cd my-os && agno up && agno connect. The infra command group is removed; a future infra 2.0 plugin can mount agno deploy (or reclaim an infra group) via the agno_cli.plugins seam. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
a17044a to
f55bb07
Compare
This was referenced Jul 4, 2026
Closed
This was referenced Jul 4, 2026
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
One command from a running AgentOS to connected coding agents:
This PR adds
agnoctl— a new distribution atlibs/agno_cli(moduleagno_cli, commandagno) — plus the two server-side changes it needs. It is stacked onfeat/service-accounts(the tokens it mints are theagno_pat_*service accounts from that branch) and is destined forfeat/v2.7.Design doc:
specs/agno/features/agno-cli/(private specs repo).The CLI (
libs/agno_cli, PyPI nameagnoctl)agno connect— discovers the AgentOS (structured/infofields, probe fallback for older servers; tries:7777then:8000), mints one service account per client (claude-code,codex,cursor;--namefor one shared account), writes each client's MCP config (Claude Code viaclaude mcp addwith file fallback; Codex via section-scoped~/.codex/config.tomledit; Cursor viamcp.jsonmerge), then reads the config back and verifies the entry the client will actually use with a real MCPinitialize+tools/listhandshake. Idempotent: working entries are skipped, broken ones rotated (--rotate/--skip-existingfor non-interactive control). Tokens are never printed or logged.agno tokens create/list/revoke— thin wrappers overPOST/GET/DELETE /service-accounts.createprints the plaintext exactly once.agno create NAME [-t agentos-docker|agentos-aws|agentos-railway] [-u URL]— template scaffolding (shallow clone, history stripped, example secrets copied), ported fromag infra create. The~/.config/ag/config.jsonregistry is deliberately dropped; commands are cwd-based.agno up/down/restart— the docker compose path of the legacyag infraCLI (same file detection and command lines), promoted to root verbs, with--file,--volumes,--dry-run,--json. The legacy per-resource Docker/AWS engine is deliberately not ported (its production path is under redesign); it can return via theagno_cli.pluginsentry-point group, which lets any installed distribution mount subcommands.agno status— discovered OS, auth mode, MCP URL, per-client connection state.CLI contract (built to be driven by coding agents as well as humans):
--jsonon every command, deterministic exit codes (0 ok / 1 failure / 2 usage / 3 partial), no prompts in--jsonmode, truthful outcomes (nothing is reported connected that did not verify).Dependencies: httpx, rich, typer (+ tomli on Python < 3.11) — no dependency on the
agnoframework, so the package stays uvx-fast.uvx agno connect(via the coreagnopackage) becomes literal with a follow-up two-line change inlibs/agno/pyproject.tomlonceagnoctlis published; until then:uvx agnoctl connect.Server-side changes (
libs/agno)GET /infodiscovery fields:mcp: {enabled, path}andauth_mode: "none" | "security_key" | "jwt"(reflecting effective enforcement precedence), so tools can discover capabilities without probing or parsing 401 messages./inforemains unauthenticated./mcpauth in non-JWT modes: the MCP sub-app previously performed no bearer validation when JWT authorization was off (theOS_SECURITY_KEYcheck is a router dependency, which does not apply to mounted sub-apps). A dedicated middleware now accepts the security key (constant-time compare) or a valid service-account token on/mcp, mirroring REST semantics; open dev instances stay open; JWT mode is unchanged.Type of change
/mcpunauthenticated-in-security-key-mode gap)Checklist
./scripts/format.shand./scripts/validate.sh)libs/agno_cli/README.md)Duplicate and AI-Generated PR Check
Additional Notes
Verification
libs/agnounit tests pass; 26 service-accounts integration tests pass (including new end-to-end MCP-over-service-account cases: mint via REST, call/mcp, revoke, rejected).agno connect --json→ 3 accounts minted, 3 configs written, all 8 tools of the MCP surface-v2 contract verified per client; re-run reportsalready-connectedwith zero new accounts;agno tokens revoke claude-code→ the revoked token is rejected (401) on the next MCP call while other clients keep working.agno createverified against the realagentos-docker-template(which already ships AGENTS.md/CLAUDE.md), andagno up --dry-runresolves itscompose.yaml.[[array-of-tables]]sections, corrupt-config clobbering, inverted Claude Code scope precedence, and per-client error isolation for the--jsoncontract.Known/pre-existing
validate.shshows 6 mypy errors in unrelatedlibs/agnotools files (httpx type-stub issues: jina, zoom, desi_vocal, clickup, calcom, azure_openai); these reproduce identically on the base branch.Release sequencing (to avoid a window with two CLIs)
agnoctlto PyPI.agno-infrarelease drops itsag/agnoconsole scripts (its used surface — create + compose up/down — is fully covered here).agnorelease addsagnoctlas a dependency plus[project.scripts] agno = "agno_cli.main:app", makinguvx agno connectlive (both mechanisms validated against current uv).🤖 Generated with Claude Code