Skip to content

CM-62578: Expose Cycode API v4 through CLI commands#435

Open
MaorDavidzon wants to merge 11 commits intomainfrom
CM-62578/expose-api-v4-cli-and-mcp
Open

CM-62578: Expose Cycode API v4 through CLI commands#435
MaorDavidzon wants to merge 11 commits intomainfrom
CM-62578/expose-api-v4-cli-and-mcp

Conversation

@MaorDavidzon
Copy link
Copy Markdown
Contributor

@MaorDavidzon MaorDavidzon commented Apr 12, 2026

Summary

  • Expose Cycode API v4 as CLI commands, dynamically generated from the OpenAPI spec
  • OpenAPI spec fetched from app.cycode.com and cached locally for 24h
  • All new commands marked as [EXPERIMENT]
  • Uses the CLI's standard auth client (same as scan/report commands)

Examples

Projects

cycode projects list --page-size 10 --query "Frontend"
cycode projects view 29303
cycode projects collisions --project-id 123
cycode projects collisions-count --project-id 123
cycode projects assets --project-id 123

Violations

cycode violations list --severity Critical --status Open --page-size 5
cycode violations list --category SAST --sort-by "-risk_score"
cycode violations view <violationId>
cycode violations count --severity High --category SecretDetection
cycode violations scan <scanId>

Workflows

cycode workflows list --query "classification"
cycode workflows view <workflowId>
cycode workflows count
cycode workflows jobs <workflowId>
cycode workflows jobs-count <workflowId>
cycode workflow-jobs list
cycode workflow-jobs view <jobId>

Members

cycode members list --page-size 5
cycode members view <memberId>
cycode members roles
cycode members me

Compliance

cycode frameworks list
cycode frameworks view <frameworkId>
cycode controls list --framework-id 1
cycode controls view <controlId>
cycode stats framework <frameworkId>
cycode stats posture

Audit logs

cycode audit-logs list --from 2024-01-01 --to 2024-12-31 --action Modified
cycode audit-logs view <id>

Scans & statistics

cycode scans list --page-size 5
cycode scans view <scanId>
cycode scans statistics --from 2024-01-01
cycode cli-scan-statistics scan-count --from 2024-01-01
cycode cli-scan-statistics top-cli-users --from 2024-01-01

Other resources

cycode labels list
cycode brokers list
cycode tokens tenant
cycode reports list
cycode secret-value-exclusions exclusions

Discovery

cycode --help                        # all 46 command groups
cycode violations --help             # subcommands for violations
cycode violations list --help        # all filter flags for listing violations

Architecture

  • OpenAPI spec fetched from app.cycode.com/v4/api-docs/cycode-api-swagger.json with a 3s timeout
  • If fetch times out, a background thread continues so the cache is warm for the next run
  • Cached runs have zero network overhead
  • Command names derived from URL path structure (not English summary parsing)
    • list for collections, view for single resources
    • Sub-paths become command names: /violations/countcount
  • Path parameters are URL-encoded to prevent path traversal
  • Auth uses CycodeTokenBasedClient (same as all other CLI commands)

Test plan

  • cycode projects list --page-size 2 returns project data
  • cycode violations list --severity Critical --status Open returns filtered violations
  • cycode projects view <ID> returns single project (path param)
  • cycode violations count --severity High returns count
  • cycode workflows list returns workflows
  • cycode members roles returns roles
  • cycode --help shows API command groups with [EXPERIMENT] label
  • All 645 existing tests pass
  • Graceful fallback when not authenticated (no API commands, no crash)
  • Spec caching works (second run has no fetch)
  • 3s timeout prevents blocking on slow networks

Jira: CM-62578

🤖 Generated with Claude Code

Integrate the standalone cycode-mcp server into the CLI, adding both
CLI commands and MCP tools for the Cycode API v4.

- Dynamic CLI commands generated from OpenAPI spec (cached 24h)
- 138 read-only API tools added to MCP server (143 total with scan tools)
- Typed CLI flags for all query parameters
- Switched from mcp to fastmcp>=2.14.0 for from_openapi() support
- All new commands marked as [EXPERIMENT]

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
MaorDavidzon and others added 6 commits April 12, 2026 14:13
Integrate the standalone cycode-mcp server into the CLI, adding both
CLI commands and MCP tools for the Cycode API v4.

- Dynamic CLI commands generated from OpenAPI spec (cached 24h)
- 138 read-only API tools added to MCP server (143 total with scan tools)
- Typed CLI flags for all query parameters
- Switched from mcp to fastmcp 2.14.6 for from_openapi() support
- All new commands marked as [EXPERIMENT]

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ehq/cycode-cli into CM-62578/expose-api-v4-cli-and-mcp

# Conflicts:
#	poetry.lock
#	pyproject.toml
Revert MCP command to original, remove fastmcp/httpx deps,
remove async_auth_client. MCP server enhancement will be a
separate PR.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace custom _get_access_token with CycodeTokenBasedClient
  (same pattern as scan/report commands)
- URL-encode path parameters to prevent path traversal
- Remove redundant cached token fallback

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use auth client for spec fetch (retries, headers, SSL handling)
- Rename _resolve_credentials to public resolve_credentials
- Replace SystemExit(1) with click.Abort for proper framework cleanup
- Document monkey-patch of typer.main.get_group
- Remove unused requests import from openapi_spec

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Spec fetch during CLI startup now has a 3-second timeout to avoid
blocking the regular flow. If it times out, a background thread
continues fetching so the cache is warm for the next run. When
cached, there is no network call at all.

Also fixes ruff format issue.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@MaorDavidzon MaorDavidzon changed the title CM-62578: Expose Cycode API v4 through CLI commands and MCP server CM-62578: Expose Cycode API v4 through CLI commands Apr 12, 2026
MaorDavidzon and others added 4 commits April 12, 2026 17:49
Derive CLI command names from URL path structure instead of parsing
English summaries. Rules:
- Strip common prefix shared by endpoints in the tag
- Remove path param segments ({id})
- Nothing left: 'list' (collection) or 'view' (single resource)
- Otherwise: use remaining path segments as the name
- Fix redundancy: 'cycode groups groups' -> 'cycode groups list'
- Duplicates (deprecated endpoints) get -v2 suffix

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Atomic cache write (temp file + rename) prevents corrupt cache if
  process is killed mid-write
- Skip endpoints marked deprecated:true in OpenAPI spec
- Remove dead snake_case redundancy check
- Add 25 unit tests for pure functions (path naming, prefix detection,
  spec parsing, deprecated flag handling)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Alpine 3.21 repo rotated musl-dev from r9 to r11, breaking the
build with "unable to select packages". Other pinned packages
(gcc, libffi-dev, git) are still at the same revision.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@gotbadger gotbadger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should put all the commands under an api namespace so like cycode api violations right now its really cluttering up the main commands and means we can have naming collisions. This is similar to what github is doing for their CLI. Also if we do this it means when we run unrelated tasks we wont have pull the swagger file, we should try and do this as when CLI is run in CI/CD it will never be hitting cache.

Here is an example of where you get some annoying logging in a command due to the call for openAPI being made in the background.

poetry run cycode status                                                                                                       
[04/13/26 10:34:02] WARNING  [API Command] Could not load OpenAPI spec: Cycode credentials not found. Run `cycode auth` first, or set CYCODE_CLIENT_ID and CYCODE_CLIENT_SECRET environment variables.              api_command.py:128
Program: cycode
Version: 0.0.0
Os: Darwin
Arch: arm64
Python version: 3.13.7
Installation id: xxxx
App url: https://app.cycode.com
Api url: https://api.cycode.com
Is authenticated: False
User id: None
Tenant id: None
Supported modules:
  Secret scanning: False
  Sca scanning: False
  Iac scanning: False
  Sast scanning: False
  Ai large language model: False
....

Lastly we will need to add documentation to the Readme for these new commands. Having it under the api namespace will make this a bit easier I think in explaining generally what it does since its dynamic

@MaorDavidzon
Copy link
Copy Markdown
Contributor Author

Great feedback, thank you — all three points are valid.

You're right about the concrete issues:

  1. Top-level registration causes namespace collisions with curated commands (scan, auth, status, report)
  2. Spec is loaded on every invocation, including unrelated commands like cycode status — bad in CI where the cache is always cold
  3. The unauthenticated warning leaking into cycode status output is a real bug

On namespacing, going with platform instead of api:

I looked at how other CLIs handle this. gh api and glab api are raw URL passthroughs (gh api repos/owner/repo/issues) — what we built is structurally different: typed commands with proper args and --option flags generated from the spec. The closer analogs are aws <service>, gcloud <product>, az <group>, oci <service> — all of which put structured generated commands at the top level (because they bundle the spec).

Since we can't easily bundle the spec (it's tenant-aware and changes more frequently than CLI releases), namespacing is the right call. api telegraphs "raw escape hatch" the way gh api does, which doesn't match what these commands actually are. platform frames it as "the Cycode platform's full surface," reads naturally (cycode platform projects list), doesn't leak implementation detail (OpenAPI/spec/swagger), and ages better if we ever add POST/PUT.

Plan:

  • Move all generated commands under cycode platform <resource> <action>
  • Lazy-load the spec only when the user enters the platform group — no fetch on cycode scan, cycode status, etc.
  • Drop the startup warning entirely (only surface errors when the user is actually inside platform)
  • Add a README section explaining the platform namespace and how command discovery works

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants