mc8yp 2.2.4 → 2.3.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
@@ -82,6 +82,12 @@ In this mode, mc8yp exposes an HTTP MCP endpoint at `/mcp` and is intended for u
82
82
 
83
83
  ### 2. CLI Mode (local development)
84
84
 
85
+ > **Platform requirement:** CLI mode requires **macOS or Linux**. The sandboxed V8 runtime
86
+ > (`@iso4/sandbox`) communicates with a Rust subprocess over Unix domain sockets, which are not
87
+ > available on Windows. If you are on Windows, use
88
+ > [WSL 2](https://learn.microsoft.com/windows/wsl/) or connect to a
89
+ > [Cumulocity microservice deployment](#1-cumulocity-microservice-mode-recommended) instead.
90
+
85
91
  CLI mode is ideal for:
86
92
 
87
93
  - local debugging
@@ -158,6 +164,20 @@ pnpm dlx mc8yp creds list
158
164
  pnpm dlx mc8yp creds remove
159
165
  ```
160
166
 
167
+ ### Active Tenant Flow
168
+
169
+ Adding credentials does not automatically activate a tenant. CLI sessions only run `query` against live tenant data and `execute` against the live API once a tenant has been selected via the `set-active-tenant` MCP tool.
170
+
171
+ First-time setup an agent will perform once the MCP client is connected:
172
+
173
+ 1. Call `cli-status` to see stored credentials and the current active tenant.
174
+ 2. Call `set-active-tenant` with one of the tenant URLs from `cli-status`. The selection is written to `~/.config/mc8yp/active-tenant.json` and re-applied automatically on every subsequent CLI start.
175
+ 3. Call `query` and `execute` as needed. The query footer and execute marker keep the active tenant visible on every result.
176
+
177
+ To switch tenants mid-session, call `set-active-tenant` again with the new URL. To deliberately stop working against any tenant and just browse the bundled OpenAPI snapshots, call `set-active-tenant` with `tenantUrl: null`. In that state `query` continues to work against every bundled spec and `execute` returns a missing-auth error — so an agent cannot accidentally hit a tenant it has not selected.
178
+
179
+ If the stored credentials for the active tenant are removed (for example by `mc8yp creds remove`), the next `cli-status` call — or the next CLI restart — detects the drift and automatically resets the active tenant to `(none)`, preventing stale auth headers from going on the wire.
180
+
161
181
  ### Connecting a Local MCP Client
162
182
 
163
183
  For Claude Desktop or any MCP client, add:
@@ -223,16 +243,17 @@ This only changes the bundled OpenAPI data that `query` sees. The `execute` tool
223
243
 
224
244
  ### Tools
225
245
 
226
- | Tool | Description |
227
- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
228
- | `query` | Search and inspect the bundled OpenAPI specs by running a JavaScript function expression. The sandbox exposes `coreSpec`, `dtmSpec`, and `specsEnabled`, and it never hides bundled specs from the query surface. |
229
- | `execute` | Execute JavaScript against the live Cumulocity API. Provide an async JavaScript function expression. A top-level `cumulocity` binding provides `cumulocity.request({ method, path, body?, headers? })`. Return the final value from that function. |
230
- | `list-credentials` | _(CLI mode only)_ List stored credentials from your system keyring. |
246
+ | Tool | Description |
247
+ | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
248
+ | `query` | Search and inspect the bundled and discovered OpenAPI specs by running a JavaScript function expression. The sandbox exposes `coreSpec` and `serviceSpecs` (microservice APIs keyed by `contextPath`). |
249
+ | `execute` | Execute JavaScript against the live Cumulocity API. Provide an async JavaScript function expression. A top-level `cumulocity` binding provides `cumulocity.request({ method, path, body?, headers? })`. Return the final value from that function. |
250
+ | `cli-status` | _(CLI mode only)_ Read the active tenant (or note that none is set) and the list of stored credentials from your system keyring. Auto-clears the active tenant if its credentials have been removed. Call this before `query` / `execute` so you know which tenant they will hit. |
251
+ | `set-active-tenant` | _(CLI mode only)_ Select the tenant `query` and `execute` operate against, persisted to `~/.config/mc8yp/active-tenant.json` across CLI restarts. Pass `tenantUrl: null` to clear the selection and fall back to browsing the bundled OpenAPI snapshots. |
231
252
 
232
- Both code-mode tools run in a sandboxed runtime ([secure-exec](https://github.com/nicepkg/secure-exec)).
253
+ Both code-mode tools run in a sandboxed V8 runtime ([@iso4/sandbox](https://github.com/schplitt/iso4)) hosted in a separate Rust subprocess.
233
254
 
234
- - `query` returns JSON text for easier inspection of OpenAPI data.
235
- - `execute` returns the successful function result in [Toon format](https://github.com/nicepkg/toon). If execution is blocked or fails, it returns a plain text message instead.
255
+ - `query` returns JSON text for easier inspection of OpenAPI data. Every result ends with a footer line naming the active tenant (or noting there is none) so the agent can verify which tenant the visible specs reflect.
256
+ - `execute` returns the successful function result in [Toon format](https://github.com/nicepkg/toon). If execution is blocked or fails, it returns a plain text message instead. In CLI mode every `execute` result is prefixed with an `Executed against tenant: <url>` marker line so the active tenant is always visible — the active tenant is global to a CLI session and can be flipped between calls by `set-active-tenant`.
236
257
 
237
258
  ### Prompts
238
259
 
@@ -382,26 +403,14 @@ mc8yp --allow "GET:/inventory/**" --allowed "POST:/alarm/**"
382
403
  mc8yp -a "/inventory/**" -r "/inventory/managedObjects"
383
404
  ```
384
405
 
385
- To forbid one or more bundled OpenAPI parts for execute policy, repeat `--disable-openapi` (or `-d`) in CLI mode. `query` still sees all bundled specs and can inspect `specsEnabled` to understand which spec families remain enabled for execute policy:
386
-
387
- ```sh
388
- # Disable bundled DTM APIs for execute policy on this CLI connection
389
- mc8yp -d dtm
390
-
391
- # Disable multiple bundled specs if more are added in the future
392
- mc8yp -d dtm -d core
393
- ```
394
-
395
406
  ### Microservice Mode (HTTP)
396
407
 
397
408
  Pass restrictions as `restriction`, `restrict`, or `r` query parameters on the MCP endpoint URL.
398
409
  Pass allow rules as `allowed`, `allow`, or `a` query parameters.
399
- To forbid bundled OpenAPI parts for execute policy, pass the `openapi-disabled` query parameter.
400
410
  You can also send project-scoped HTTP headers to avoid conflicts with well-known headers:
401
411
 
402
412
  - `mc8yp-restriction` for deny rules
403
413
  - `mc8yp-allow` for allow-list rules
404
- - `mc8yp-openapi-disabled` for bundled OpenAPI part disablement
405
414
 
406
415
  Both headers accept either repeated header instances or a comma-separated list of values. Query parameters and headers can be combined on the same connection.
407
416
 
@@ -409,8 +418,6 @@ Both headers accept either repeated header instances or a comma-separated list o
409
418
  /mcp?restriction=/inventory/**&restrict=DELETE:/alarm/**
410
419
  /mcp?r=/inventory/**&r=DELETE:/alarm/**
411
420
  /mcp?allow=/inventory/**&allowed=POST:/alarm/**
412
- /mcp?openapi-disabled=dtm
413
- /mcp?openapi-disabled=dtm&openapi-disabled=core
414
421
  ```
415
422
 
416
423
  ```http
@@ -419,18 +426,15 @@ Authorization: Bearer <token>
419
426
  mc8yp-restriction: /inventory/**
420
427
  mc8yp-restriction: DELETE:/alarm/**
421
428
  mc8yp-allow: GET:/measurement/**
422
- mc8yp-openapi-disabled: dtm
423
429
  ```
424
430
 
425
431
  ### How Access Policy Works
426
432
 
427
- 1. **Query visibility**: The `query` tool exposes the raw bundled OpenAPI specs for the current MCP connection. Bundled specs are not hidden or rewritten, and the query sandbox exposes `specsEnabled` so the model can see which spec families are enabled for execute policy.
428
-
429
- 2. **Sandbox request enforcement**: The `execute` tool checks restrictions and allow rules inside the generated sandbox request helper, where the actual HTTP method and normalized path are both available. Matching deny rules block first. If any allow rules are configured, requests must also match at least one allow rule.
433
+ 1. **Query visibility**: The `query` tool exposes resolved OpenAPI specs through `coreSpec` and `serviceSpecs`. With an active tenant, services not installed on that tenant are dropped from the sandbox surface so the agent only sees what is actually reachable. In CLI mode with no active tenant, every bundled snapshot is exposed for reference browsing only — `execute` is unavailable in that state.
430
434
 
431
- 3. **Bundled spec disablement**: When the connection disables bundled OpenAPI parts such as `dtm`, `query` still shows all bundled specs, while the server expands that selection into additional restrictions so `execute` stays path-and-method based.
435
+ 2. **Request enforcement**: The host-side bridge that backs `cumulocity.request` evaluates restrictions and allow rules before any HTTP request leaves the host. Matching deny rules block first. If any allow rules are configured, requests must also match at least one allow rule. Blocked requests never reach Cumulocity.
432
436
 
433
- 4. **Network boundary**: The secure-exec permission layer independently restricts network access to the configured tenant host. Other network operations are denied.
437
+ 3. **Network boundary**: The sandbox itself has no `fetch` global. Sandbox code reaches the tenant only through the host-bridged `cumulocity.request` helper, which injects auth, evaluates restriction and allow rules, and issues the live HTTP call via [@iso4/fetch](https://www.npmjs.com/package/@iso4/fetch) (DNS-pinned, SSRF-hardened). Every other network egress is unavailable to the agent.
434
438
 
435
439
  When an `execute` request is blocked by MCP connection policy, the tool returns explanatory text stating whether the operation was denied by a restriction or blocked because it is outside the configured allow list, no request was sent to Cumulocity, and retrying through the same connection will not help.
436
440