api-spec-cli 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -17,47 +17,67 @@ npx api-spec-cli <command>
17
17
 
18
18
  ## How It Works
19
19
 
20
- The CLI follows a progressive discovery pattern. You never dump an entire API spec at once instead you narrow down to what you need.
20
+ Every command is stateless you specify the spec source on each call. Two paths:
21
21
 
22
- ### Step 1: Load the spec
22
+ | Path | When to use |
23
+ |---|---|
24
+ | `--spec <name>` | Registered spec — auto-fetches and caches on first use |
25
+ | Inline flags | Ad-hoc — no registration, fetched each call |
26
+
27
+ ### Register once, use everywhere
23
28
 
24
29
  ```bash
25
- # OpenAPI
26
- spec load https://petstore3.swagger.io/api/v3/openapi.json
27
- spec load ./openapi.yaml
30
+ spec add petstore --openapi https://petstore3.swagger.io/api/v3/openapi.json \
31
+ --base-url https://petstore3.swagger.io/api/v3 \
32
+ --description "Petstore example"
33
+
34
+ spec add hashnode --graphql https://gql.hashnode.com --auth YOUR_TOKEN
28
35
 
29
- # GraphQL (auto-introspects)
30
- spec load https://gql.hashnode.com
36
+ spec add agno --mcp-http https://docs.agno.com/mcp --description "Agno docs"
37
+
38
+ spec add fs --mcp-stdio "npx -y @modelcontextprotocol/server-filesystem /tmp"
39
+ ```
31
40
 
32
- # MCPstdio transport (spawn a local server)
33
- spec load --mcp-stdio "npx -y @modelcontextprotocol/server-filesystem /tmp"
41
+ Registration is instant does not connect. Connection happens on first `list`/`show`/`call` and the result is cached at `~/spec-cli-config/cache/<name>.json`.
34
42
 
35
- # MCP SSE transport
36
- spec load --mcp-sse http://localhost:3000/sse
43
+ ### Or use inline (no registration)
37
44
 
38
- # MCP — Streamable HTTP transport
39
- spec load --mcp-http https://docs.agno.com/mcp
45
+ ```bash
46
+ spec list --openapi https://petstore3.swagger.io/api/v3/openapi.json
47
+ spec list --graphql https://gql.hashnode.com
48
+ spec list --mcp-http https://docs.agno.com/mcp
49
+ spec list --mcp-sse http://localhost:3000/sse
50
+ spec list --mcp-stdio "npx -y @modelcontextprotocol/server-filesystem /tmp"
40
51
  ```
41
52
 
42
- Output tells you what was loaded:
43
- ```json
44
- { "ok": true, "type": "mcp", "transport": "streamable-http", "toolCount": 1 }
53
+ Inline fetches every call, nothing cached.
54
+
55
+ ---
56
+
57
+ ## Discovery
58
+
59
+ ### List all specs in the registry
60
+
61
+ ```bash
62
+ spec specs # Compact: name, type, enabled
63
+ spec specs --compact false # Full: includes source, config
45
64
  ```
46
65
 
47
- ### Step 2: Find what you need
66
+ ### List operations / tools
48
67
 
49
68
  `list` is compact by default — just IDs, no schemas. Use `--filter`, `--tag`, `--limit` to narrow down.
50
69
 
51
70
  ```bash
52
- spec list # All operations/tools (compact IDs only)
53
- spec list --filter publish # Search by keyword
54
- spec list --tag pets # OpenAPI: filter by tag
55
- spec list --tag mutation # GraphQL: filter by kind (query/mutation/subscription)
56
- spec list --limit 10 # First 10 only
57
- spec list --limit 10 --offset 10 # Next 10
71
+ spec list --spec agno # Registered spec (uses cache)
72
+ spec list --spec petstore --filter pet # Search by keyword
73
+ spec list --spec petstore --tag pets # OpenAPI: filter by tag
74
+ spec list --spec hashnode --tag mutation # GraphQL: filter by kind
75
+ spec list --spec petstore --limit 10 # First 10 only
76
+ spec list --spec petstore --limit 10 --offset 10 # Next 10
77
+ spec list --mcp-http https://docs.agno.com/mcp # Inline: no registration needed
58
78
  ```
59
79
 
60
- Compact output (token-efficient):
80
+ Compact output:
61
81
  ```json
62
82
  {
63
83
  "type": "mcp",
@@ -69,99 +89,135 @@ Compact output (token-efficient):
69
89
  }
70
90
  ```
71
91
 
72
- Use `--compact false` for full details (including `inputSchema` for MCP tools).
92
+ Use `--compact false` for full details including `inputSchema` for MCP tools.
73
93
 
74
- ### Step 3: Inspect one operation or tool
94
+ ### Inspect one operation or tool
75
95
 
76
- `show` gives you everything you need to make a call — params, body schema, response, and related types — in one call.
96
+ `show` gives you everything to make a call — params, body schema, response schemas, related types — in one call.
77
97
 
78
98
  ```bash
79
- spec show publishPost # GraphQL: by operation name
80
- spec show getPetById # OpenAPI: by operationId
81
- spec show /pet/{petId} # OpenAPI: by path
82
- spec show "GET /pet/{petId}" # OpenAPI: by method + path
83
- spec show search_agno # MCP: by tool name
99
+ spec show --spec petstore getPetById # OpenAPI: by operationId
100
+ spec show --spec petstore /pet/{petId} # OpenAPI: by path
101
+ spec show --spec petstore "GET /pet/{petId}" # OpenAPI: by method + path
102
+ spec show --spec hashnode publishPost # GraphQL: by operation name
103
+ spec show --spec agno search_agno # MCP: by tool name
84
104
  ```
85
105
 
86
106
  MCP output includes the full `inputSchema` so you know exactly what arguments to pass.
87
107
 
88
- ### Step 4: Drill into types (OpenAPI/GraphQL only)
108
+ ### Drill into types (OpenAPI/GraphQL only)
89
109
 
90
110
  ```bash
91
- spec types # List all schema/type names
92
- spec types Pet # Inspect one schema
93
- spec types PublishPostInput # Inspect a GraphQL input type
111
+ spec types --spec petstore # List all schema names
112
+ spec types --spec petstore Pet # Inspect one schema
113
+ spec types --spec hashnode PublishPostInput # GraphQL input type
94
114
  ```
95
115
 
96
- ### Step 5: Call the API
116
+ ---
117
+
118
+ ## Calling APIs
97
119
 
98
120
  ```bash
99
- # Set base URL and auth first (persisted across calls — OpenAPI/GraphQL)
100
- spec config set baseUrl https://petstore3.swagger.io/api/v3
101
- spec config set auth YOUR_TOKEN
121
+ # OpenAPI
122
+ spec call --spec petstore getPetById --var petId=1
123
+ spec call --spec petstore findPetsByStatus --query status=available
124
+ spec call --spec petstore addPet --data '{"name":"Rex","photoUrls":[]}'
102
125
 
103
- # OpenAPI calls
104
- spec call getPetById --var petId=1
105
- spec call findPetsByStatus --query status=available
106
- spec call addPet --data '{"name":"Rex","photoUrls":[]}'
126
+ # GraphQL (auto-generates query from schema)
127
+ spec call --spec hashnode me
128
+ spec call --spec hashnode publication --var host=blog.hashnode.dev
107
129
 
108
- # GraphQL calls (auto-generates query from schema)
109
- spec call me
110
- spec call publication --var host=blog.hashnode.dev
130
+ # MCP
131
+ spec call --spec agno search_agno --var query="how to create an agent"
132
+ spec call --spec agno search_agno --data '{"query":"agents"}'
111
133
 
112
- # MCP calls — use --var for individual args or --data for the full JSON object
113
- spec call search_agno --var query="how to create an agent"
114
- spec call read_file --data '{"path":"/tmp/hello.txt"}'
134
+ # Inline (no registration)
135
+ spec call --openapi https://petstore3.swagger.io/api/v3/openapi.json \
136
+ getPetById --var petId=1 --base-url https://petstore3.swagger.io/api/v3
115
137
  ```
116
138
 
139
+ ### Per-call overrides
140
+
141
+ Flags passed at call time win over registry entry config, which wins over `.spec-cli/config.json`.
142
+
143
+ ```bash
144
+ spec call --spec agno search_agno --var query="foo" --header X-Tenant=acme
145
+ spec call --spec petstore getPetById --var petId=1 --auth staging-token
146
+ spec list --spec petstore --base-url https://staging.api.example.com
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Registry Management
152
+
153
+ ```bash
154
+ spec remove <name> # Delete entry and remove cache
155
+ spec enable <name> # Re-enable a disabled spec
156
+ spec disable <name> # Disable without removing
157
+ spec refresh <name> # Force re-fetch and update cache
158
+ ```
159
+
160
+ ---
161
+
162
+ ## spec add options
163
+
164
+ ```bash
165
+ spec add <name> --openapi <url-or-file> [--base-url <url>] [--auth <token>] [--header k=v]
166
+ spec add <name> --graphql <url> [--auth <token>] [--header k=v]
167
+ spec add <name> --mcp-http <url> [--header k=v]
168
+ spec add <name> --mcp-sse <url> [--header k=v]
169
+ spec add <name> --mcp-stdio "<cmd args>" [--env KEY=VAL]
170
+ [--description <text>] (all types)
171
+ ```
172
+
173
+ Headers are sent on every request. For stdio MCP, use `--env` to pass environment variables to the subprocess.
174
+
175
+ ---
176
+
117
177
  ## Config
118
178
 
119
- Persistent config stored in `.spec-cli/config.json`. Set once, used for all calls.
179
+ Persistent config stored in `.spec-cli/config.json` (lowest priority overridden by registry entry config and call-time flags).
120
180
 
121
181
  ```bash
122
182
  spec config set baseUrl https://api.example.com
123
183
  spec config set auth my-token # Auto-adds "Bearer " prefix
124
- spec config set auth "Basic dXNlcjpwYXNz" # Or explicit auth header
125
- spec config set headers.X-API-Key abc123 # Custom headers (dot notation)
126
- spec config get # Show all config
127
- spec config unset auth # Remove a key
184
+ spec config set auth "Basic dXNlcjpwYXNz" # Or explicit scheme
185
+ spec config set headers.X-API-Key abc123 # Custom header (dot notation)
186
+ spec config get
187
+ spec config unset auth
128
188
  ```
129
189
 
130
190
  ## Validate
131
191
 
132
- Check an OpenAPI spec for errors before using it:
133
-
134
192
  ```bash
135
193
  spec validate https://api.example.com/openapi.json
194
+ spec validate ./openapi.yaml
136
195
  ```
137
196
 
138
197
  Reports broken `$ref` references, missing required fields, duplicate operationIds, invalid schema types, and more.
139
198
 
140
199
  ## Output Format
141
200
 
142
- JSON by default. Use `--format text` or `--format yaml` for alternatives:
201
+ JSON by default. Errors go to stderr as `{"error": "message"}` with a non-zero exit code.
143
202
 
144
203
  ```bash
145
- spec list --format text
146
- spec show getPetById --format yaml
204
+ spec list --spec petstore --format text
205
+ spec show --spec petstore getPetById --format yaml
206
+ spec list --spec petstore --format=json # equals syntax also works
147
207
  ```
148
208
 
149
- Errors always go to stderr as JSON: `{"error": "message"}` with non-zero exit code.
150
-
151
209
  ## Token Efficiency
152
210
 
153
- The CLI is designed to minimize context window usage for AI agents:
154
-
155
- - `list` returns only IDs by default (not full schemas)
156
- - `show` resolves schemas compactly nested refs show as names, not deep explosions
157
- - `types` lets you inspect one type at a time instead of loading all schemas
158
- - `--limit` and `--offset` paginate large APIs
211
+ - `list` returns only IDs by default no schemas
212
+ - `show` resolves `$ref` compactly — nested refs show as names, not explosions
213
+ - `types` lets you inspect one schema at a time
214
+ - `--limit` / `--offset` paginate large APIs
159
215
  - `--filter` and `--tag` narrow results before output
160
216
 
161
217
  ## Storage
162
218
 
163
- All state lives in `.spec-cli/` in the working directory:
164
- - `spec.json` — loaded spec cache
165
- - `config.json` base URL, auth, headers
166
-
167
- Add `.spec-cli/` to your `.gitignore`.
219
+ | Path | Purpose |
220
+ |---|---|
221
+ | `~/spec-cli-config/registry.json` | Global named registry |
222
+ | `~/spec-cli-config/cache/<name>.json` | Cached spec per registered entry |
223
+ | `.spec-cli/config.json` | Project-local config (baseUrl, auth, headers) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-spec-cli",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "Agent-friendly CLI for exploring and calling OpenAPI and GraphQL APIs",
5
5
  "type": "module",
6
6
  "bin": {
package/src/args.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // Supports: --flag value, --flag=value, and positional args
3
3
  // Repeatable flags (--query, --header, --var) are collected into arrays.
4
4
 
5
- const REPEATABLE = new Set(["query", "header", "var"]);
5
+ const REPEATABLE = new Set(["query", "header", "var", "env"]);
6
6
 
7
7
  export function parseArgs(args) {
8
8
  const flags = {};
package/src/cli.js CHANGED
@@ -1,77 +1,103 @@
1
- import { loadSpec } from "./commands/load.js";
2
1
  import { listOperations } from "./commands/list.js";
3
2
  import { showOperation } from "./commands/show.js";
4
3
  import { callOperation } from "./commands/call.js";
5
4
  import { configCmd } from "./commands/config.js";
6
5
  import { validateSpec } from "./commands/validate.js";
7
6
  import { typesCmd } from "./commands/types.js";
7
+ import { addCmd } from "./commands/add.js";
8
+ import { specsCmd, registryMutate } from "./commands/specs.js";
8
9
  import { out, err, setFormat } from "./output.js";
9
10
 
10
11
  const HELP = `spec-cli — Explore and call APIs from the command line.
11
12
  All output is JSON. Designed for AI agents but works for humans too.
12
13
 
13
- WORKFLOW (follow this order):
14
- 1. spec load <file-or-url> Load an OpenAPI or GraphQL spec
15
- spec load --mcp-stdio <cmd> Load an MCP server via stdio
16
- spec load --mcp-sse <url> Load an MCP server via SSE
17
- spec load --mcp-http <url> Load an MCP server via streamable HTTP
18
- 2. spec list Browse operations/tools (compact IDs)
19
- 3. spec show <operation> Get params, body, response for one op
20
- 4. spec call <operation> [options] Execute the request
14
+ Every command is stateless — specify the spec source on each call.
21
15
 
22
- Use spec types [name] to inspect a schema/type referenced by show.
23
- Use spec config to set baseUrl, auth, and headers before calling.
16
+ SPEC SOURCE (required on every list/show/call):
17
+ --spec <name> Use a registered spec (auto-fetches + caches)
18
+ --openapi <url-or-file> OpenAPI inline (no registration needed)
19
+ --graphql <url> GraphQL inline
20
+ --mcp-http <url> MCP streamable-HTTP inline
21
+ --mcp-sse <url> MCP SSE inline
22
+ --mcp-stdio "<cmd args>" MCP stdio inline
24
23
 
25
- DISCOVERY (narrowing down):
26
- spec list All operations (just IDs)
27
- spec list --filter user Search across all fields
28
- spec list --tag pets OpenAPI tag or GraphQL kind (query/mutation)
29
- spec list --limit 10 --offset 20 Paginate large APIs
24
+ REGISTRY (register once, use anywhere):
25
+ spec add <name> --openapi <url> Register an OpenAPI spec
26
+ spec add <name> --graphql <url> Register a GraphQL endpoint
27
+ spec add <name> --mcp-http <url> Register an MCP server (streamable-HTTP)
28
+ spec add <name> --mcp-sse <url> Register an MCP server (SSE)
29
+ spec add <name> --mcp-stdio "<cmd>" Register an MCP server (stdio)
30
+ Options: --description <text> --base-url <url> --auth <token>
31
+ --header k=v (repeatable) --env KEY=VAL (repeatable, stdio only)
32
+
33
+ spec specs List all registered specs
34
+ spec specs --compact false Show full entry config
35
+ spec remove <name> Delete from registry
36
+ spec enable <name> Enable a disabled spec
37
+ spec disable <name> Disable without removing
38
+ spec refresh <name> Force re-fetch and update cache
39
+
40
+ DISCOVER:
41
+ spec list --spec <name> All operations/tools (compact IDs)
42
+ spec list --spec <name> --filter user Search by keyword
43
+ spec list --spec <name> --tag pets OpenAPI tag or GraphQL kind
44
+ spec list --spec <name> --limit 10 Paginate
45
+ spec list --mcp-http <url> Inline: no registration needed
30
46
 
31
47
  INSPECT:
32
- spec show getPetById Match by operationId
33
- spec show /pet/{petId} Match by path
34
- spec show "GET /pet/{petId}" Match by method + path
35
- spec show publishPost GraphQL operation name
36
- spec show read_file MCP tool name
37
- spec types List all schema/type names
38
- spec types Pet Inspect one schema (compact, no $ref explosion)
39
-
40
- EXECUTE:
41
- spec call <op> --var petId=1 Path or GraphQL variables
42
- spec call <op> --query status=available Query string params
43
- spec call <op> --data '{"name":"Rex"}' JSON body / MCP tool arguments
44
- spec call <op> --data-file /tmp/query.json JSON body from file (avoids shell escaping)
45
- spec call <op> --header X-Custom=val Extra headers (OpenAPI/GraphQL)
46
- spec call <op> --method PUT Override HTTP method (OpenAPI)
47
-
48
- MCP EXAMPLES:
49
- spec load --mcp-stdio "npx -y @modelcontextprotocol/server-filesystem /tmp"
50
- spec load --mcp-sse http://localhost:3000/sse
51
- spec load --mcp-http https://example.com/mcp
52
- spec list
53
- spec show read_file
54
- spec call read_file --var path=/tmp/hello.txt
55
- spec call read_file --data '{"path":"/tmp/hello.txt"}'
56
-
57
- CONFIG (persisted in .spec-cli/config.json):
48
+ spec show --spec <name> <op> Operation details (params, body, responses)
49
+ spec show --spec <name> <tool> MCP tool input schema
50
+ spec types --spec <name> List all schema/type names (OpenAPI/GraphQL)
51
+ spec types --spec <name> <TypeName> Inspect one type
52
+
53
+ CALL:
54
+ spec call --spec <name> <op> --var petId=1 Path/GraphQL vars
55
+ spec call --spec <name> <op> --query status=available Query params
56
+ spec call --spec <name> <op> --data '{"name":"Rex"}' JSON body / MCP args
57
+ spec call --spec <name> <op> --data-file args.json Body from file
58
+ spec call --spec <name> <op> --header X-Custom=val Extra headers
59
+ spec call --spec <name> <op> --method PUT Override HTTP method
60
+
61
+ PER-CALL OVERRIDES (win over registry entry config):
62
+ --auth <token> Override auth for this call
63
+ --base-url <url> Override base URL for this call
64
+ --header k=v Merge/override headers for this call
65
+
66
+ CONFIG (persisted in .spec-cli/config.json — lowest priority):
58
67
  spec config set baseUrl https://api.example.com
59
- spec config set auth <token> Auto-adds Bearer prefix
60
- spec config set headers.X-API-Key <key> Dot notation for nested keys
61
- spec config get Show current config
62
- spec config unset auth Remove a key
68
+ spec config set auth <token>
69
+ spec config set headers.X-API-Key <key>
70
+ spec config get
71
+ spec config unset auth
63
72
 
64
73
  OTHER:
65
74
  spec validate <file-or-url> Check OpenAPI spec for errors
66
- --format json|text|yaml Output format (default: json)`;
75
+ --format json|text|yaml Output format (default: json)
76
+
77
+ EXAMPLES:
78
+ spec add agno --mcp-http https://docs.agno.com/mcp --description "Agno docs"
79
+ spec add petstore --openapi https://petstore3.swagger.io/api/v3/openapi.json \\
80
+ --base-url https://petstore3.swagger.io/api/v3
81
+ spec specs
82
+ spec list --spec agno
83
+ spec show --spec agno search_agno
84
+ spec call --spec agno search_agno --var query="agents"
85
+ spec call --spec agno search_agno --var query="foo" --header X-Tenant=acme
86
+ spec list --mcp-http https://docs.agno.com/mcp (inline, no registration)`;
67
87
 
68
88
  export async function run(args) {
69
- // Extract --format before routing
70
- const formatIdx = args.indexOf("--format");
71
- if (formatIdx !== -1) {
72
- setFormat(args[formatIdx + 1]);
73
- args = [...args.slice(0, formatIdx), ...args.slice(formatIdx + 2)];
89
+ // Extract --format before routing (supports both --format json and --format=json)
90
+ const newArgs = [];
91
+ for (let i = 0; i < args.length; i++) {
92
+ if (args[i] === "--format" && i + 1 < args.length) {
93
+ setFormat(args[++i]);
94
+ } else if (args[i].startsWith("--format=")) {
95
+ setFormat(args[i].slice(9));
96
+ } else {
97
+ newArgs.push(args[i]);
98
+ }
74
99
  }
100
+ args = newArgs;
75
101
 
76
102
  const cmd = args[0];
77
103
 
@@ -82,9 +108,6 @@ export async function run(args) {
82
108
 
83
109
  try {
84
110
  switch (cmd) {
85
- case "load":
86
- await loadSpec(args.slice(1));
87
- break;
88
111
  case "list":
89
112
  case "ls":
90
113
  await listOperations(args.slice(1));
@@ -106,6 +129,25 @@ export async function run(args) {
106
129
  case "cfg":
107
130
  await configCmd(args.slice(1));
108
131
  break;
132
+ case "add":
133
+ await addCmd(args.slice(1));
134
+ break;
135
+ case "specs":
136
+ case "registry":
137
+ await specsCmd(args.slice(1));
138
+ break;
139
+ case "remove":
140
+ await registryMutate("remove", args.slice(1));
141
+ break;
142
+ case "enable":
143
+ await registryMutate("enable", args.slice(1));
144
+ break;
145
+ case "disable":
146
+ await registryMutate("disable", args.slice(1));
147
+ break;
148
+ case "refresh":
149
+ await registryMutate("refresh", args.slice(1));
150
+ break;
109
151
  default:
110
152
  err(`Unknown command: ${cmd}. Run 'spec help' for usage.`);
111
153
  }
@@ -0,0 +1,67 @@
1
+ import { parseArgs, parseKV } from "../args.js";
2
+ import { getRegistry, saveRegistry } from "../registry.js";
3
+ import { out } from "../output.js";
4
+
5
+ export async function addCmd(args) {
6
+ const { flags, positional } = parseArgs(args);
7
+ const name = positional[0];
8
+ if (!name) throw new Error(
9
+ "Usage: spec add <name> --openapi <url> | --graphql <url> | --mcp-http <url> | --mcp-sse <url> | --mcp-stdio \"<cmd>\""
10
+ );
11
+ if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
12
+ throw new Error("Spec name must contain only letters, numbers, hyphens, and underscores.");
13
+ }
14
+
15
+ const registry = getRegistry();
16
+ if (registry.find((e) => e.name === name)) {
17
+ throw new Error(`Spec '${name}' already exists. Run 'spec remove ${name}' first.`);
18
+ }
19
+
20
+ const entry = { name, enabled: true };
21
+
22
+ if (flags.description) entry.description = flags.description;
23
+
24
+ if (flags.openapi) {
25
+ entry.type = "openapi";
26
+ entry.source = flags.openapi;
27
+ entry.config = {
28
+ baseUrl: flags["base-url"] || null,
29
+ auth: flags.auth || null,
30
+ headers: parseKV(flags.header),
31
+ };
32
+ } else if (flags.graphql) {
33
+ entry.type = "graphql";
34
+ entry.source = flags.graphql;
35
+ entry.config = {
36
+ auth: flags.auth || null,
37
+ headers: parseKV(flags.header),
38
+ };
39
+ } else if (flags["mcp-stdio"]) {
40
+ const raw = flags["mcp-stdio"];
41
+ const parts = (raw.trim() ? raw.match(/(?:[^\s"]+|"[^"]*")+/g) : null)?.map((p) => p.replace(/^"|"$/g, ""));
42
+ if (!parts?.length) throw new Error("--mcp-stdio requires a non-empty command string");
43
+ entry.type = "mcp";
44
+ entry.transport = "stdio";
45
+ entry.command = parts[0];
46
+ entry.args = parts.slice(1);
47
+ entry.config = { env: parseKV(flags.env) };
48
+ } else if (flags["mcp-sse"]) {
49
+ entry.type = "mcp";
50
+ entry.transport = "sse";
51
+ entry.url = flags["mcp-sse"];
52
+ entry.config = { headers: parseKV(flags.header) };
53
+ } else if (flags["mcp-http"]) {
54
+ entry.type = "mcp";
55
+ entry.transport = "streamable-http";
56
+ entry.url = flags["mcp-http"];
57
+ entry.config = { headers: parseKV(flags.header) };
58
+ } else {
59
+ throw new Error(
60
+ "Specify a source: --openapi <url>, --graphql <url>, --mcp-http <url>, --mcp-sse <url>, or --mcp-stdio \"<cmd>\""
61
+ );
62
+ }
63
+
64
+ registry.push(entry);
65
+ saveRegistry(registry);
66
+ out({ ok: true, name, type: entry.type, transport: entry.transport });
67
+ }