api-spec-cli 0.2.3 → 0.2.4

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
@@ -1,282 +1,343 @@
1
- # api-spec-cli
2
-
3
- CLI for AI agents to explore and call OpenAPI, GraphQL, and MCP APIs. Output is JSON by default — compact, parseable, token-efficient.
4
-
5
- ## Install
6
-
7
- ```bash
8
- npm install -g api-spec-cli
9
- ```
10
-
11
- Works with Node.js 18+. No other dependencies.
12
-
13
- ```bash
14
- # Or run without installing
15
- npx api-spec-cli <command>
16
- ```
17
-
18
- ## How It Works
19
-
20
- Every command is stateless — you specify the spec source on each call. Two paths:
21
-
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
28
-
29
- ```bash
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
35
-
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
- ```
40
-
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`.
42
-
43
- ### Or use inline (no registration)
44
-
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"
51
- ```
52
-
53
- Inline fetches every call, nothing cached.
54
-
55
- ---
56
-
57
- ## Discovery
58
-
59
- ### Search across specs
60
-
61
- `grep` searches operation/tool names and descriptions across all registered specs.
62
-
63
- ```bash
64
- spec grep search # Substring match across all specs
65
- spec grep "get*" # Glob: anything starting with "get"
66
- spec grep "*list*" # Glob: anything containing "list"
67
- spec grep search --spec agno # Limit to one spec
68
- ```
69
-
70
- Matches on name and description. Case-insensitive. Plain text = substring, `*`/`?` = glob.
71
-
72
- ### List all specs in the registry
73
-
74
- ```bash
75
- spec specs # Compact: name, type, enabled
76
- spec specs --compact false # Full: includes source, config
77
- ```
78
-
79
- ### List operations / tools
80
-
81
- `list` is compact by default — just IDs, no schemas. Use `--filter`, `--tag`, `--limit` to narrow down.
82
-
83
- ```bash
84
- spec list --spec agno # Registered spec (uses cache)
85
- spec list --spec petstore --filter pet # Search by keyword
86
- spec list --spec petstore --tag pets # OpenAPI: filter by tag
87
- spec list --spec hashnode --tag mutation # GraphQL: filter by kind
88
- spec list --spec petstore --limit 10 # First 10 only
89
- spec list --spec petstore --limit 10 --offset 10 # Next 10
90
- spec list --mcp-http https://docs.agno.com/mcp # Inline: no registration needed
91
- ```
92
-
93
- Compact output:
94
- ```json
95
- {
96
- "type": "mcp",
97
- "total": 1,
98
- "showing": 1,
99
- "operations": [
100
- { "id": "search_agno", "description": "Search across the Agno knowledge base..." }
101
- ]
102
- }
103
- ```
104
-
105
- Use `--compact false` for full details including `inputSchema` for MCP tools.
106
-
107
- ### Inspect one operation or tool
108
-
109
- `show` gives you everything to make a call — params, body schema, response schemas, related types — in one call.
110
-
111
- ```bash
112
- spec show --spec petstore getPetById # OpenAPI: by operationId
113
- spec show --spec petstore /pet/{petId} # OpenAPI: by path
114
- spec show --spec petstore "GET /pet/{petId}" # OpenAPI: by method + path
115
- spec show --spec hashnode publishPost # GraphQL: by operation name
116
- spec show --spec agno search_agno # MCP: by tool name
117
- ```
118
-
119
- MCP output includes the full `inputSchema` so you know exactly what arguments to pass.
120
-
121
- ### Drill into types (OpenAPI/GraphQL only)
122
-
123
- ```bash
124
- spec types --spec petstore # List all schema names
125
- spec types --spec petstore Pet # Inspect one schema
126
- spec types --spec hashnode PublishPostInput # GraphQL input type
127
- ```
128
-
129
- ---
130
-
131
- ## Calling APIs
132
-
133
- ```bash
134
- # OpenAPI
135
- spec call --spec petstore getPetById --var petId=1
136
- spec call --spec petstore findPetsByStatus --query status=available
137
- spec call --spec petstore addPet --data '{"name":"Rex","photoUrls":[]}'
138
-
139
- # GraphQL (auto-generates query from schema)
140
- spec call --spec hashnode me
141
- spec call --spec hashnode publication --var host=blog.hashnode.dev
142
-
143
- # MCP
144
- spec call --spec agno search_agno --var query="how to create an agent"
145
- spec call --spec agno search_agno --data '{"query":"agents"}'
146
-
147
- # Read body from stdin (explicit --data -)
148
- echo '{"query":"agents"}' | spec call --spec agno search_agno --data -
149
- cat body.json | spec call --spec petstore addPet --data -
150
-
151
- # Inline (no registration)
152
- spec call --openapi https://petstore3.swagger.io/api/v3/openapi.json \
153
- getPetById --var petId=1 --base-url https://petstore3.swagger.io/api/v3
154
- ```
155
-
156
- ### Per-call overrides
157
-
158
- Flags passed at call time win over registry entry config, which wins over `.spec-cli/config.json`.
159
-
160
- ```bash
161
- spec call --spec agno search_agno --var query="foo" --header X-Tenant=acme
162
- spec call --spec petstore getPetById --var petId=1 --auth staging-token
163
- spec list --spec petstore --base-url https://staging.api.example.com
164
- ```
165
-
166
- ---
167
-
168
- ## Registry Management
169
-
170
- ```bash
171
- spec remove <name> # Delete entry and remove cache
172
- spec enable <name> # Re-enable a disabled spec
173
- spec disable <name> # Disable without removing
174
- spec refresh <name> # Force re-fetch and update cache
175
- ```
176
-
177
- ---
178
-
179
- ## spec add options
180
-
181
- ```bash
182
- spec add <name> --openapi <url-or-file> [--base-url <url>] [--auth <token>] [--header k=v]
183
- spec add <name> --graphql <url> [--auth <token>] [--header k=v]
184
- spec add <name> --mcp-http <url> [--auth <token>] [--header k=v]
185
- spec add <name> --mcp-sse <url> [--auth <token>] [--header k=v]
186
- spec add <name> --mcp-stdio "<cmd args>" [--env KEY=VAL] [--cwd <path>]
187
- [--description <text>] (all types)
188
- ```
189
-
190
- All options are repeatable where it makes sense (`--header`, `--env`). `--auth` adds `Authorization: Bearer <token>` unless the header is already set.
191
-
192
- Operation filtering works for all spec types — MCP, OpenAPI, and GraphQL:
193
-
194
- ```bash
195
- # MCP: allow only read/list tools
196
- spec add <name> --mcp-http <url> \
197
- --allow-tool "read_*" --allow-tool "list_*" \
198
- --disable-tool "delete_*"
199
-
200
- # OpenAPI: allow only GET operations (by operationId)
201
- spec add <name> --openapi <url> \
202
- --allow-tool "get*" --allow-tool "find*"
203
-
204
- # GraphQL: allow specific operations by exact name
205
- spec add <name> --graphql <url> \
206
- --allow-tool "me" --allow-tool "publication"
207
- ```
208
-
209
- `--allow-tool` keeps only matching operations. `--disable-tool` removes matching operations (applied after allow). Both are repeatable.
210
-
211
- **Matching rules:**
212
- - Plain text → **exact match** (case-insensitive): `"me"` matches only `me`
213
- - Glob patterns → anchored match: `"get*"` matches `getPetById`, `"*post*"` matches `createPost`
214
-
215
- Use `grep` for search (substring) — `--allow-tool` / `--disable-tool` for precise whitelists (exact or glob).
216
-
217
- ---
218
-
219
- ## Config
220
-
221
- Persistent config stored in `.spec-cli/config.json` (lowest priority overridden by registry entry config and call-time flags).
222
-
223
- ```bash
224
- spec config set baseUrl https://api.example.com
225
- spec config set auth my-token # Auto-adds "Bearer " prefix
226
- spec config set auth "Basic dXNlcjpwYXNz" # Or explicit scheme
227
- spec config set headers.X-API-Key abc123 # Custom header (dot notation)
228
- spec config get
229
- spec config unset auth
230
- ```
231
-
232
- ## Validate
233
-
234
- ```bash
235
- spec validate https://api.example.com/openapi.json
236
- spec validate ./openapi.yaml
237
- ```
238
-
239
- Reports broken `$ref` references, missing required fields, duplicate operationIds, invalid schema types, and more.
240
-
241
- ## Output Format
242
-
243
- JSON by default. Errors go to stderr as `{"error": "message"}` with a non-zero exit code.
244
-
245
- ```bash
246
- spec list --spec petstore --format text
247
- spec show --spec petstore getPetById --format yaml
248
- spec list --spec petstore --format=json # equals syntax also works
249
- ```
250
-
251
- ## Token Efficiency
252
-
253
- - `list` returns only IDs by default — no schemas
254
- - `show` resolves `$ref` compactly — nested refs show as names, not explosions
255
- - `types` lets you inspect one schema at a time
256
- - `--limit` / `--offset` paginate large APIs
257
- - `--filter` and `--tag` narrow results before output
258
-
259
- ## MCP Options
260
-
261
- ```bash
262
- # Retry on connection failure (useful for stdio servers that take time to start)
263
- MCP_MAX_RETRIES=3 # Attempts (default: 3)
264
- MCP_RETRY_DELAY=1000 # Base delay in ms, doubles each attempt, capped at 5s (default: 1000)
265
-
266
- # HTTP timeout for OpenAPI/GraphQL calls
267
- SPEC_HTTP_TIMEOUT=30000 # ms (default: 30000)
268
- ```
269
-
270
- Stdio env vars support `${VAR}` expansion from the host environment:
271
-
272
- ```bash
273
- spec add fs --mcp-stdio "npx -y server /tmp" --env "TOKEN=${MY_SECRET}"
274
- ```
275
-
276
- ## Storage
277
-
278
- | Path | Purpose |
279
- |---|---|
280
- | `~/spec-cli-config/registry.json` | Global named registry |
281
- | `~/spec-cli-config/cache/<name>.json` | Cached spec per registered entry |
282
- | `.spec-cli/config.json` | Project-local config (baseUrl, auth, headers) |
1
+ # api-spec-cli
2
+
3
+ CLI for AI agents to explore and call OpenAPI, GraphQL, and MCP APIs. Output is JSON by default — compact, parseable, token-efficient.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g api-spec-cli
9
+ ```
10
+
11
+ Works with Node.js 18+. No other dependencies.
12
+
13
+ ```bash
14
+ # Or run without installing
15
+ npx api-spec-cli <command>
16
+ ```
17
+
18
+ ## How It Works
19
+
20
+ Every command is stateless — you specify the spec source on each call. Two paths:
21
+
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
28
+
29
+ ```bash
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
35
+
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
+ ```
40
+
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`.
42
+
43
+ ### Or use inline (no registration)
44
+
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"
51
+ ```
52
+
53
+ Inline fetches every call, nothing cached.
54
+
55
+ ---
56
+
57
+ ## Discovery
58
+
59
+ ### Search across specs
60
+
61
+ `grep` searches operation/tool names and descriptions across all registered specs.
62
+
63
+ ```bash
64
+ spec grep search # Substring match across all specs
65
+ spec grep "get*" # Glob: anything starting with "get"
66
+ spec grep "*list*" # Glob: anything containing "list"
67
+ spec grep search --spec agno # Limit to one spec
68
+ ```
69
+
70
+ Matches on name and description. Case-insensitive. Plain text = substring, `*`/`?` = glob.
71
+
72
+ ### List all specs in the registry
73
+
74
+ ```bash
75
+ spec specs # Compact: name, type, enabled
76
+ spec specs --compact false # Full: includes source, config
77
+ ```
78
+
79
+ ### List operations / tools
80
+
81
+ `list` is compact by default — just IDs, no schemas. Use `--filter`, `--tag`, `--limit` to narrow down.
82
+
83
+ ```bash
84
+ spec list --spec agno # Registered spec (uses cache)
85
+ spec list --spec petstore --filter pet # Search by keyword
86
+ spec list --spec petstore --tag pets # OpenAPI: filter by tag
87
+ spec list --spec hashnode --tag mutation # GraphQL: filter by kind
88
+ spec list --spec petstore --limit 10 # First 10 only
89
+ spec list --spec petstore --limit 10 --offset 10 # Next 10
90
+ spec list --mcp-http https://docs.agno.com/mcp # Inline: no registration needed
91
+ ```
92
+
93
+ Compact output:
94
+ ```json
95
+ {
96
+ "type": "mcp",
97
+ "total": 1,
98
+ "showing": 1,
99
+ "operations": [
100
+ { "id": "search_agno", "description": "Search across the Agno knowledge base..." }
101
+ ]
102
+ }
103
+ ```
104
+
105
+ Use `--compact false` for full details including `inputSchema` for MCP tools.
106
+
107
+ ### Inspect one operation or tool
108
+
109
+ `show` gives you everything to make a call — params, body schema, response schemas, related types — in one call.
110
+
111
+ ```bash
112
+ spec show --spec petstore getPetById # OpenAPI: by operationId
113
+ spec show --spec petstore /pet/{petId} # OpenAPI: by path
114
+ spec show --spec petstore "GET /pet/{petId}" # OpenAPI: by method + path
115
+ spec show --spec hashnode publishPost # GraphQL: by operation name
116
+ spec show --spec agno search_agno # MCP: by tool name
117
+ ```
118
+
119
+ MCP output includes the full `inputSchema` so you know exactly what arguments to pass.
120
+
121
+ ### Drill into types (OpenAPI/GraphQL only)
122
+
123
+ ```bash
124
+ spec types --spec petstore # List all schema names
125
+ spec types --spec petstore Pet # Inspect one schema
126
+ spec types --spec hashnode PublishPostInput # GraphQL input type
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Calling APIs
132
+
133
+ ```bash
134
+ # OpenAPI
135
+ spec call --spec petstore getPetById --var petId=1
136
+ spec call --spec petstore findPetsByStatus --query status=available
137
+ spec call --spec petstore addPet --data '{"name":"Rex","photoUrls":[]}'
138
+
139
+ # GraphQL (auto-generates query from schema)
140
+ spec call --spec hashnode me
141
+ spec call --spec hashnode publication --var host=blog.hashnode.dev
142
+
143
+ # MCP
144
+ spec call --spec agno search_agno --var query="how to create an agent"
145
+ spec call --spec agno search_agno --data '{"query":"agents"}'
146
+
147
+ # Read body from stdin (explicit --data -)
148
+ echo '{"query":"agents"}' | spec call --spec agno search_agno --data -
149
+ cat body.json | spec call --spec petstore addPet --data -
150
+
151
+ # Inline (no registration)
152
+ spec call --openapi https://petstore3.swagger.io/api/v3/openapi.json \
153
+ getPetById --var petId=1 --base-url https://petstore3.swagger.io/api/v3
154
+ ```
155
+
156
+ ### Per-call overrides
157
+
158
+ Flags passed at call time win over registry entry config, which wins over `.spec-cli/config.json`.
159
+
160
+ ```bash
161
+ spec call --spec agno search_agno --var query="foo" --header X-Tenant=acme
162
+ spec call --spec petstore getPetById --var petId=1 --auth staging-token
163
+ spec list --spec petstore --base-url https://staging.api.example.com
164
+ ```
165
+
166
+ ---
167
+
168
+ ## Registry Management
169
+
170
+ ```bash
171
+ spec remove <name> # Delete entry and remove cache
172
+ spec enable <name> # Re-enable a disabled spec
173
+ spec disable <name> # Disable without removing
174
+ spec refresh <name> # Force re-fetch and update cache
175
+ ```
176
+
177
+ ---
178
+
179
+ ## spec add options
180
+
181
+ ```bash
182
+ spec add <name> --openapi <url-or-file> [--base-url <url>] [--auth <token>] [--header k=v]
183
+ spec add <name> --graphql <url> [--auth <token>] [--header k=v]
184
+ spec add <name> --mcp-http <url> [--auth <token>] [--header k=v]
185
+ spec add <name> --mcp-sse <url> [--auth <token>] [--header k=v]
186
+ spec add <name> --mcp-stdio "<cmd args>" [--env KEY=VAL] [--cwd <path>]
187
+ [--description <text>] (all types)
188
+ ```
189
+
190
+ All options are repeatable where it makes sense (`--header`, `--env`). `--auth` adds `Authorization: Bearer <token>` unless the header is already set.
191
+
192
+ Operation filtering works for all spec types — MCP, OpenAPI, and GraphQL:
193
+
194
+ ```bash
195
+ # MCP: allow only read/list tools
196
+ spec add <name> --mcp-http <url> \
197
+ --allow-tool "read_*" --allow-tool "list_*" \
198
+ --disable-tool "delete_*"
199
+
200
+ # OpenAPI: allow only GET operations (by operationId)
201
+ spec add <name> --openapi <url> \
202
+ --allow-tool "get*" --allow-tool "find*"
203
+
204
+ # GraphQL: allow specific operations by exact name
205
+ spec add <name> --graphql <url> \
206
+ --allow-tool "me" --allow-tool "publication"
207
+ ```
208
+
209
+ `--allow-tool` keeps only matching operations. `--disable-tool` removes matching operations (applied after allow). Both are repeatable.
210
+
211
+ **Matching rules:**
212
+ - Plain text → **exact match** (case-insensitive): `"me"` matches only `me`
213
+ - Glob patterns → anchored match: `"get*"` matches `getPetById`, `"*post*"` matches `createPost`
214
+
215
+ Use `grep` for search (substring) — `--allow-tool` / `--disable-tool` for precise whitelists (exact or glob).
216
+
217
+ ---
218
+
219
+ ## OAuth / Authentication
220
+
221
+ MCP HTTP and SSE servers that require OAuth 2.1 are handled automatically. spec-cli detects the 401 on `spec add` and runs the flow before returning.
222
+
223
+ Two modes depending on whether the server supports Dynamic Client Registration (DCR):
224
+
225
+ - **DCR-enabled servers** (e.g. self-hosted with Cloudflare workers-oauth-provider, Stytch, Curity) — no flags needed, browser opens automatically
226
+ - **Pre-registered-only servers** (e.g. GitHub) pass `--oauth-client-id` with your app's client ID
227
+
228
+ ### Interactive (browser) — default
229
+
230
+ ```bash
231
+ # DCR-enabled server: fully automatic
232
+ spec add myserver --mcp-http https://...
233
+
234
+ # GitHub (no DCR) — create an OAuth App at github.com/settings/developers first
235
+ # Set callback URL to http://127.0.0.1:8090/callback
236
+ spec add github --mcp-http https://api.githubcopilot.com/mcp/ \
237
+ --oauth-client-id <your-github-app-client-id> \
238
+ --oauth-callback-port 8090
239
+ ```
240
+
241
+ ### Headless / device flow
242
+
243
+ ```bash
244
+ spec add myserver --mcp-http https://... --oauth-flow device
245
+ # Prints a URL to stderr — open in any browser to authorize
246
+ ```
247
+
248
+ ### Machine / CI (client credentials)
249
+
250
+ ```bash
251
+ spec add myserver --mcp-http https://... \
252
+ --oauth-client-id <id> --oauth-client-secret <secret>
253
+ ```
254
+
255
+ ### Re-authenticate
256
+
257
+ ```bash
258
+ spec auth myserver # Re-run the OAuth flow
259
+ spec auth myserver --revoke # Clear stored token only
260
+ ```
261
+
262
+ Tokens are stored in `~/spec-cli-config/tokens/<name>.json` separate from the cache, not touched by `spec refresh`.
263
+
264
+ ### OAuth flags
265
+
266
+ | Flag | Description |
267
+ | --- | --- |
268
+ | `--oauth-client-id <id>` | Skip DCR — use a pre-registered OAuth app client ID |
269
+ | `--oauth-client-secret <secret>` | Use client credentials flow (machine/CI) |
270
+ | `--oauth-callback-port <port>` | Fixed callback port (required for apps with exact redirect URL match, e.g. GitHub) |
271
+ | `--oauth-flow device` | Force device authorization flow (headless/SSH) |
272
+
273
+ ---
274
+
275
+ ## Config
276
+
277
+ Persistent config stored in `.spec-cli/config.json` (lowest priority — overridden by registry entry config and call-time flags).
278
+
279
+ ```bash
280
+ spec config set baseUrl https://api.example.com
281
+ spec config set auth my-token # Auto-adds "Bearer " prefix
282
+ spec config set auth "Basic dXNlcjpwYXNz" # Or explicit scheme
283
+ spec config set headers.X-API-Key abc123 # Custom header (dot notation)
284
+ spec config get
285
+ spec config unset auth
286
+ ```
287
+
288
+ ## Validate
289
+
290
+ ```bash
291
+ spec validate https://api.example.com/openapi.json
292
+ spec validate ./openapi.yaml
293
+ ```
294
+
295
+ Reports broken `$ref` references, missing required fields, duplicate operationIds, invalid schema types, and more.
296
+
297
+ ## Output Format
298
+
299
+ JSON by default. Errors go to stderr as `{"error": "message"}` with a non-zero exit code.
300
+
301
+ ```bash
302
+ spec list --spec petstore --format text
303
+ spec show --spec petstore getPetById --format yaml
304
+ spec list --spec petstore --format=json # equals syntax also works
305
+ ```
306
+
307
+ ## Token Efficiency
308
+
309
+ - `list` returns only IDs by default — no schemas
310
+ - `show` resolves `$ref` compactly — nested refs show as names, not explosions
311
+ - `types` lets you inspect one schema at a time
312
+ - `--limit` / `--offset` paginate large APIs
313
+ - `--filter` and `--tag` narrow results before output
314
+
315
+ ## MCP Options
316
+
317
+ ```bash
318
+ # Retry on connection failure (useful for stdio servers that take time to start)
319
+ MCP_MAX_RETRIES=3 # Attempts (default: 3)
320
+ MCP_RETRY_DELAY=1000 # Base delay in ms, doubles each attempt, capped at 5s (default: 1000)
321
+
322
+ # HTTP timeout for OpenAPI/GraphQL calls
323
+ SPEC_HTTP_TIMEOUT=30000 # ms (default: 30000)
324
+ ```
325
+
326
+ Stdio env vars support `${VAR}` expansion from the host environment:
327
+
328
+ ```bash
329
+ spec add fs --mcp-stdio "npx -y server /tmp" --env "TOKEN=${MY_SECRET}"
330
+ ```
331
+
332
+ ## Storage
333
+
334
+ | Path | Purpose |
335
+ |---|---|
336
+ | `~/spec-cli-config/registry.json` | Global named registry |
337
+ | `~/spec-cli-config/cache/<name>.json` | Cached spec per registered entry |
338
+ | `~/spec-cli-config/tokens/<name>.json` | OAuth tokens per MCP entry |
339
+ | `.spec-cli/config.json` | Project-local config (baseUrl, auth, headers) |
340
+
341
+ ## Planned
342
+
343
+ - `spec import <file>` — bulk import servers from VS Code `mcp.json` or Claude Desktop config format