npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

openapi-to-cli

v0.1.22

Published

CLI that turns OpenAPI/Swagger-described HTTP APIs into executable commands (ocli) with profiles and cached specs

Downloads

673

Readme

OpenAPI to CLI (ocli)

openapi-to-cli (short ocli) is a TypeScript CLI that turns any HTTP API described by an OpenAPI, Swagger, or OpenRPC spec into a set of CLI commands — at runtime, without code generation.

npm install -g openapi-to-cli

ocli profiles add github \
  --api-base-url https://api.github.com \
  --openapi-spec https://api.github.com/openapi.json \
  --api-bearer-token "$GITHUB_TOKEN"

ocli commands --query "create pull request" --limit 3
ocli repos_owner_repo_pulls_post --owner octocat --repo hello --title "Fix bug" --head feature --base main

Where CLI fits: Tools, MCP, Skills, and CLI

Tools, MCP, skills, and CLI are not competing approaches — they solve different problems at different layers:

| Layer | What | Best for | |-------|------|----------| | Built-in tools | Standard agent toolset | Critical capabilities that must always be in context (file read/write, shell, browser) | | MCP | Remote tool servers | APIs that need centralized auth, enterprise SSO, shared state, persistent connections, or can't be in standard delivery | | Skills | On-demand instructions | Context isolation, teaching agents when and how to use a tool — loaded only when needed | | CLI | Runtime execution | Long action chains, automation, shell pipelines — agent already knows what to do |

ocli lives at the runtime layer. When an agent needs to call a REST API — search for the right endpoint, check its parameters, execute the call — CLI does this with minimal context overhead and zero infrastructure.

MCP is the right choice when you need centralized auth, persistent connections, or shared state. CLI is the right choice when you need a lightweight, portable way to call HTTP APIs from any agent with shell access.

Quick start

# Install
npm install -g openapi-to-cli

# Add an API profile
ocli profiles add myapi \
  --api-base-url https://api.example.com \
  --openapi-spec https://api.example.com/openapi.json \
  --api-bearer-token "$TOKEN" \
  --include-endpoints "get:/messages,post:/messages" \
  --command-prefix "myapi_" \
  --custom-headers '{"X-Tenant":"acme"}'

# Set as active profile
ocli use myapi

# Discover commands
ocli commands --query "send message" --limit 5

# Check parameters
ocli myapi_messages_post --help

# Execute
ocli myapi_messages_post --text "Hello world"

# Or target a different profile for a single call (no 'use' required)
ocli myapi_messages_post --profile other --text "Hello world"
ocli commands -p other --query "send message"

--profile (short -p) overrides the profile selected by ocli use for this invocation only. It works for both dynamic API commands and ocli commands. Place it anywhere after the command name. When omitted, the profile set via ocli use is used (falling back to default).

OpenRPC and JSON-RPC APIs

ocli also accepts OpenRPC JSON or YAML documents through the existing --openapi-spec option. It creates one command for each documented RPC method and exposes named RPC parameters as command flags.

ocli profiles add widgets \
  --api-base-url https://api.example.com/rpc \
  --openapi-spec ./openrpc.json \
  --api-bearer-token "$TOKEN"

ocli use widgets
ocli getWidget --widgetId widget-7

OpenRPC commands always send an HTTP POST request with Content-Type: application/json. ocli builds the JSON-RPC 2.0 envelope automatically:

{
  "jsonrpc": "2.0",
  "method": "getWidget",
  "params": {
    "widgetId": "widget-7"
  },
  "id": 1
}

The profile's --api-base-url remains the request target. If it is empty, ocli falls back to the first server URL in the OpenRPC document.

Authentication and custom headers

A profile stores up to three credentials, set with ocli profiles add (or ocli onboard):

  • --api-bearer-token <token> sends Authorization: Bearer <token>
  • --api-basic-auth <user:password> sends Authorization: Basic <base64>; when both are set, Basic wins
  • --custom-headers '{"X-Tenant":"acme"}' adds any extra headers

ocli attaches these headers to every API request and to the download of the OpenAPI spec itself, so a spec served behind the same auth as the API (for example /openapi.json answering 401 to anonymous requests) loads with ocli profiles add. The headers are sent only to the two origins named in the profile, the --openapi-spec URL and the --api-base-url. External $ref documents on those origins receive them too, at any nesting depth; $ref documents on any other host are fetched anonymously, so a spec cannot forward your credentials to a third-party host. Specs loaded from a local file path involve no request.

When the spec download is rejected with 401 or 403, ocli reports the failing URL and the status and points at the three flags above:

$ ocli profiles add myapi --api-base-url https://api.example.com --openapi-spec https://api.example.com/openapi.json
Failed to fetch OpenAPI document https://api.example.com/openapi.json: HTTP 401. Check --api-basic-auth, --api-bearer-token, or --custom-headers of profile myapi.

The spec is downloaded once and cached under .ocli/specs/<profile>.json. Later invocations read the cache and do not contact the spec URL. Re-run ocli profiles add with the same profile name to refresh it.

Strict flag validation

ocli refuses to run a command with a flag the spec does not define, instead of dropping it from the request:

$ ocli people_vanId_get --vanId 12345678 --expand addresses
Unknown option: --expand (did you mean --$expand?). Run 'ocli people_vanId_get --help' to see available options.
$ echo $?
1

The same applies to built-in commands: ocli commands --qeury pull exits with Unknown argument: qeury.

One exception is kept on purpose. When an operation accepts a body (POST, PUT, PATCH, DELETE) and the spec describes no request body, undeclared flags are still forwarded as JSON body fields — that is the only way to call endpoints whose payload is not documented. As soon as the spec declares body properties or formData parameters, those names become the full list of accepted flags.

Or use npx without global install:

npx openapi-to-cli onboard \
  --api-base-url https://api.example.com \
  --openapi-spec https://api.example.com/openapi.json

Broader spec support

ocli now handles a wider range of real-world API descriptions:

  • OAS 3 requestBody for JSON payloads
  • Swagger 2 body and formData parameters
  • path-level parameters inherited by operations
  • local $ref references for parameters and request bodies
  • header and cookie parameters in generated commands
  • OpenRPC methods with named parameters, including local schema references

In practice this improves compatibility with APIs that define inputs outside simple path/query parameters, especially for POST, PUT, and PATCH operations.

Better request generation

ocli now uses more request metadata from the specification when building real HTTP calls:

  • query and path parameter serialization from OpenAPI / Swagger metadata
  • support for array and object-style query parameters such as deepObject, pipeDelimited, and Swagger 2 collection formats
  • operation-level and path-level server overrides when the spec defines different targets for different endpoints

In practice this improves compatibility with APIs that rely on non-trivial parameter encoding or per-operation server definitions.

Multi-file specs and richer help

ocli now works better with larger, more structured API descriptions:

  • external $ref resolution across multiple local or remote OpenAPI / Swagger documents
  • support for multi-document specs that split paths, parameters, and request bodies into separate files
  • richer --help output with schema hints such as enum, default, nullable, and oneOf
  • better handling of composed schemas that use allOf for shared request object structure

In practice this improves compatibility with modular specs and makes generated commands easier to use without opening the original OpenAPI document.

Command search

# BM25 natural language search
ocli commands --query "upload files" --limit 5

# Regex pattern matching
ocli commands --regex "users.*post" --limit 10

# List all commands
ocli commands

The BM25 engine ranks commands by relevance across name, method, path, description, and parameter names. Tested on APIs with 845+ endpoints (GitHub API).

Using with AI agents

OpenClaw skill

Install the ocli-api skill from ClawHub:

clawhub install ocli-api

Or manually copy skills/ocli-api/SKILL.md to ~/.openclaw/skills/ocli-api/SKILL.md.

Claude Code skill

Copy the example skill to your project:

cp examples/skill-ocli-api.md .claude/skills/api.md

Agent workflow

  1. ocli commands --query "upload file" — discover the right command
  2. ocli files_content_post --help — check parameters
  3. ocli files_content_post --file ./data.csv — execute

Benchmark

Four strategies compared on Swagger Petstore (19 endpoints), with scaling projections to GitHub API (845 endpoints). All search strategies use the same BM25 engine.

  TOOL DEFINITION OVERHEAD (sent with every API request)

  MCP Naive          █████████████████████████  2,945 tok  (19 tools)
  MCP+Search Full    ███                          355 tok  (2 tools)
  MCP+Search Compact ████                         437 tok  (3 tools)
  CLI (ocli)         █                            158 tok  (1 tool)

  TOTAL TOKENS PER TASK (realistic multi-turn agent flow)

  MCP Naive          █████████████████████████  3,015 tok  (1 turn)
  MCP+Search Full    ██████████████████         2,185 tok  (2 turns)
  MCP+Search Compact █████████████████          2,066 tok  (3 turns)
  CLI (ocli)         ████████                     925 tok  (3 turns)

  SCALING: OVERHEAD PER TURN vs ENDPOINT COUNT

  Endpoints   MCP Naive      MCP+S Compact    CLI (ocli)
  19            2,945 tok         437 tok        158 tok   ← Petstore
  845         130,106 tok         437 tok        158 tok   ← GitHub API

Run the benchmark yourself: npx ts-node benchmarks/benchmark.ts

Note: MCP+Search Compact (search → get_schema → call) is the fairest comparison to CLI (search → --help → execute) — same number of turns, same BM25 engine. The difference is tool definition overhead (437 vs 158 tok/turn) and schema format (JSON vs text).

Comparison

| Feature | ocli | mcp2cli | openapi-cli-generator | CLI-Anything | |---------|:----:|:------:|:---------------------:|:-------------:| | Runtime interpretation (no codegen) | ✅ | ✅ | ❌ | ❌ | | Works without LLM | ✅ | ✅ | ✅ | ❌ | | Zero-setup install (npx/uvx) | ✅ | ✅ | ❌ | ❌ | | Multiple API profiles | ✅ | ✅ (bake mode) | ❌ | ❌ | | BM25 command search | ✅ | ❌ (substring only) | ❌ | ❌ | | Regex command search | ✅ | ❌ | ❌ | ❌ | | Per-profile endpoint filtering | ✅ | ✅ | ❌ | ❌ | | OpenAPI/Swagger (JSON + YAML) | ✅ | ✅ | ✅ | ❌ | | OpenRPC (JSON + YAML) | ✅ | ? | ? | ? | | MCP server support | ❌ | ✅ (HTTP/SSE/stdio) | ❌ | ❌ | | GraphQL support | ❌ | ✅ (introspection) | ❌ | ❌ | | Spec caching | ✅ | ✅ (1h TTL) | ❌ | ❌ | | Custom HTTP headers | ✅ | ✅ | ❌ | ❌ | | Command name prefix | ✅ | ❌ | ❌ | ❌ | | Basic / Bearer auth | ✅ | ✅ | ✅ | ❌ | | OAuth2 | ❌ | ✅ (PKCE) | ✅ | ✅ | | Response filtering (jq/JMESPath) | ❌ | ✅ (jq) | ✅ (JMESPath) | ❌ | | Token-optimized output (TOON) | ❌ | ✅ | ❌ | ❌ | | JSON structured output | ❌ | ✅ | ✅ | ✅ | | Active project | ✅ | ✅ | ❌ (deprecated) | ✅ |

Similar projects

  • mcp2cli — Python CLI that converts MCP servers, OpenAPI specs, and GraphQL endpoints into CLI commands at runtime. Supports OAuth, TOON output format, and daemon sessions.
  • openapi-cli-generator — generates a CLI from an OpenAPI 3 specification using code generation.
  • anything-llm-cli — CLI for interacting with AnythingLLM, can consume HTTP APIs and tools.
  • openapi-commander — Node.js command-line tool generator based on OpenAPI definitions.
  • OpenAPI Generator — general-purpose OpenAPI code generator that can also generate CLI clients.
  • openapi2cli — Python tool that builds CLI interfaces for OpenAPI 3 APIs.

License

This project is licensed under the MIT License, see the LICENSE file in the repository root for details.