mc8yp 2.1.0 → 2.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 +57 -22
- package/dist/{add-C-dXxz3k.mjs → add-BecAtXuv.mjs} +12 -4
- package/dist/cli.mjs +8810 -800
- package/dist/{creds-CpDDNTs5.mjs → creds-CmsPhr1t.mjs} +2 -2
- package/package.json +11 -10
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|

|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that gives AI agents full access to the Cumulocity IoT platform through code execution. Instead of exposing dozens of fixed tools, the server provides two code-mode tools — `query` and `execute` — that let the agent write JavaScript to inspect the
|
|
7
|
+
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that gives AI agents full access to the Cumulocity IoT platform through code execution. Instead of exposing dozens of fixed tools, the server provides two code-mode tools — `query` and `execute` — that let the agent write JavaScript to inspect the bundled OpenAPI specs and call any API endpoint.
|
|
8
8
|
|
|
9
9
|
**Two Deployment Modes:**
|
|
10
10
|
|
|
@@ -19,7 +19,7 @@ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that gi
|
|
|
19
19
|
# Run directly (recommended)
|
|
20
20
|
pnpm dlx mc8yp
|
|
21
21
|
|
|
22
|
-
# Pick a specific
|
|
22
|
+
# Pick a specific bundled OpenAPI build for query
|
|
23
23
|
pnpm dlx mc8yp --spec 2025
|
|
24
24
|
|
|
25
25
|
# Or install globally
|
|
@@ -28,7 +28,7 @@ mc8yp
|
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
**Credential Storage:**
|
|
31
|
-
Credentials are stored using your operating system's secure credential manager
|
|
31
|
+
Credentials are stored using your operating system's secure credential manager. The interactive `mc8yp creds add` flow uses hidden password input so the secret is not echoed back in the terminal while you type it.
|
|
32
32
|
|
|
33
33
|
- **macOS**: Keychain
|
|
34
34
|
- **Windows**: Credential Vault
|
|
@@ -50,7 +50,7 @@ No additional credential configuration needed — the microservice uses Cumuloci
|
|
|
50
50
|
### Managing Credentials (CLI)
|
|
51
51
|
|
|
52
52
|
```sh
|
|
53
|
-
# Add credentials (prompts for tenant URL, username, password)
|
|
53
|
+
# Add credentials (prompts for tenant URL, username, and a masked password)
|
|
54
54
|
pnpm dlx mc8yp creds add
|
|
55
55
|
|
|
56
56
|
# List stored credentials
|
|
@@ -60,24 +60,31 @@ pnpm dlx mc8yp creds list
|
|
|
60
60
|
pnpm dlx mc8yp creds remove
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
### Selecting The
|
|
63
|
+
### Selecting The Bundled OpenAPI Build (CLI)
|
|
64
64
|
|
|
65
|
-
Use `--spec` or `-s` to choose which bundled core OpenAPI snapshot the `query` tool exposes.
|
|
65
|
+
Use `--spec` or `-s` to choose which bundled **core** OpenAPI snapshot the `query` tool exposes.
|
|
66
66
|
|
|
67
67
|
Supported values are `release`, `2026`, `2025`, and `2024`.
|
|
68
68
|
|
|
69
|
+
This flag selects the bundled **core** API version only. The bundled **dtm** OpenAPI snapshot is currently fixed and is included alongside every supported core build.
|
|
70
|
+
|
|
71
|
+
Each bundled CLI build currently contains:
|
|
72
|
+
|
|
73
|
+
- the selected bundled **core** OpenAPI snapshot
|
|
74
|
+
- the bundled **dtm** OpenAPI snapshot
|
|
75
|
+
|
|
69
76
|
```sh
|
|
70
|
-
# Default: latest bundled release
|
|
77
|
+
# Default: latest bundled release build
|
|
71
78
|
mc8yp
|
|
72
79
|
|
|
73
|
-
# Explicitly use the 2025
|
|
80
|
+
# Explicitly use the 2025 bundled build
|
|
74
81
|
mc8yp --spec 2025
|
|
75
82
|
|
|
76
83
|
# Short form
|
|
77
84
|
mc8yp -s 2024
|
|
78
85
|
```
|
|
79
86
|
|
|
80
|
-
This only affects the `query`
|
|
87
|
+
This only affects the bundled OpenAPI data that `query` sees. The `execute` tool still calls the live Cumulocity API of the selected tenant or deployed service environment.
|
|
81
88
|
|
|
82
89
|
### Connecting to AI Agents
|
|
83
90
|
|
|
@@ -115,7 +122,7 @@ With restrictions (see [API Restrictions](#api-restrictions)):
|
|
|
115
122
|
|
|
116
123
|
| Tool | Description |
|
|
117
124
|
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
118
|
-
| `query` | Search and inspect the bundled
|
|
125
|
+
| `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. |
|
|
119
126
|
| `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. |
|
|
120
127
|
| `list-credentials` | _(CLI mode only)_ List stored credentials from your system keyring. |
|
|
121
128
|
|
|
@@ -237,6 +244,7 @@ Supported wildcards:
|
|
|
237
244
|
- `/inventory/**` already matches `/inventory` itself, so you do **not** need both `/inventory` and `/inventory/**`
|
|
238
245
|
- `/i**` is **not valid** because `**` must be its own segment. Use `/i*/**` if you want to match a first segment starting with `i` and everything below it
|
|
239
246
|
- `*:/inventory/**` is allowed and means the same thing as `/inventory/**`
|
|
247
|
+
- Root paths across the bundled core and DTM specs are intentionally treated as disjoint, so path-based restriction and allow rules are enough for request enforcement
|
|
240
248
|
- Rule patterns may not contain empty segments (`//`), `.` or `..` segments, query strings, or fragments
|
|
241
249
|
|
|
242
250
|
### CLI Mode
|
|
@@ -252,9 +260,6 @@ mc8yp -r "/inventory/**"
|
|
|
252
260
|
# Block deletes on inventory and all alarm access
|
|
253
261
|
mc8yp -r "DELETE:/inventory/**" -r "/alarm/**"
|
|
254
262
|
|
|
255
|
-
# Block everything under user management
|
|
256
|
-
mc8yp --restriction "/user/**"
|
|
257
|
-
|
|
258
263
|
# Same thing using the long alias
|
|
259
264
|
mc8yp --restrict "/user/**"
|
|
260
265
|
```
|
|
@@ -272,31 +277,61 @@ mc8yp --allow "GET:/inventory/**" --allowed "POST:/alarm/**"
|
|
|
272
277
|
mc8yp -a "/inventory/**" -r "/inventory/managedObjects"
|
|
273
278
|
```
|
|
274
279
|
|
|
280
|
+
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:
|
|
281
|
+
|
|
282
|
+
```sh
|
|
283
|
+
# Disable bundled DTM APIs for execute policy on this CLI connection
|
|
284
|
+
mc8yp -d dtm
|
|
285
|
+
|
|
286
|
+
# Disable multiple bundled specs if more are added in the future
|
|
287
|
+
mc8yp -d dtm -d core
|
|
288
|
+
```
|
|
289
|
+
|
|
275
290
|
### Microservice Mode (HTTP)
|
|
276
291
|
|
|
277
292
|
Pass restrictions as `restriction`, `restrict`, or `r` query parameters on the MCP endpoint URL.
|
|
278
293
|
Pass allow rules as `allowed`, `allow`, or `a` query parameters.
|
|
294
|
+
To forbid bundled OpenAPI parts for execute policy, pass the `openapi-disabled` query parameter.
|
|
295
|
+
You can also send project-scoped HTTP headers to avoid conflicts with well-known headers:
|
|
296
|
+
|
|
297
|
+
- `mc8yp-restriction` for deny rules
|
|
298
|
+
- `mc8yp-allow` for allow-list rules
|
|
299
|
+
- `mc8yp-openapi-disabled` for bundled OpenAPI part disablement
|
|
300
|
+
|
|
301
|
+
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.
|
|
279
302
|
|
|
280
303
|
```
|
|
281
304
|
/mcp?restriction=/inventory/**&restrict=DELETE:/alarm/**
|
|
282
305
|
/mcp?r=/inventory/**&r=DELETE:/alarm/**
|
|
283
306
|
/mcp?allow=/inventory/**&allowed=POST:/alarm/**
|
|
284
|
-
/mcp?
|
|
307
|
+
/mcp?openapi-disabled=dtm
|
|
308
|
+
/mcp?openapi-disabled=dtm&openapi-disabled=core
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
```http
|
|
312
|
+
POST /mcp HTTP/1.1
|
|
313
|
+
Authorization: Bearer <token>
|
|
314
|
+
mc8yp-restriction: /inventory/**
|
|
315
|
+
mc8yp-restriction: DELETE:/alarm/**
|
|
316
|
+
mc8yp-allow: GET:/measurement/**
|
|
317
|
+
mc8yp-openapi-disabled: dtm
|
|
285
318
|
```
|
|
286
319
|
|
|
287
320
|
### How Access Policy Works
|
|
288
321
|
|
|
289
|
-
1. **Query visibility**: The `query` tool exposes the raw bundled OpenAPI
|
|
322
|
+
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.
|
|
290
323
|
|
|
291
324
|
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.
|
|
292
325
|
|
|
293
|
-
3. **
|
|
326
|
+
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.
|
|
327
|
+
|
|
328
|
+
4. **Network boundary**: The secure-exec permission layer independently restricts network access to the configured tenant host. Other network operations are denied.
|
|
294
329
|
|
|
295
330
|
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.
|
|
296
331
|
|
|
297
332
|
## Build And Packaging
|
|
298
333
|
|
|
299
|
-
The repository bundles multiple
|
|
334
|
+
The repository bundles multiple OpenAPI specs for CLI use and builds one microservice server bundle per configured build version.
|
|
300
335
|
|
|
301
336
|
### Build Outputs
|
|
302
337
|
|
|
@@ -305,7 +340,7 @@ The repository bundles multiple core OpenAPI snapshots for CLI use and builds on
|
|
|
305
340
|
- CLI bundle in `dist/`
|
|
306
341
|
- Versioned server bundles in `.output/release/`, `.output/2026/`, `.output/2025/`, and `.output/2024/`
|
|
307
342
|
|
|
308
|
-
The
|
|
343
|
+
The build matrix is driven by [`openapi-builds.json`](openapi-builds.json). Core snapshots live under `openapi/core/`, DTM snapshots live under `openapi/dtm/`, and each server bundle contains the configured combination for that build.
|
|
309
344
|
|
|
310
345
|
### Release Packaging
|
|
311
346
|
|
|
@@ -321,10 +356,10 @@ pnpm package:microservices
|
|
|
321
356
|
|
|
322
357
|
That command creates one zip per bundled server variant in the repository root, for example:
|
|
323
358
|
|
|
324
|
-
- `mc8yp-release-v1.2.3.zip`
|
|
325
|
-
- `mc8yp-2026-v1.2.3.zip`
|
|
326
|
-
- `mc8yp-2025-v1.2.3.zip`
|
|
327
|
-
- `mc8yp-2024-v1.2.3.zip`
|
|
359
|
+
- `mc8yp-core-release-dtm-v1.2.3.zip`
|
|
360
|
+
- `mc8yp-core-2026-dtm-v1.2.3.zip`
|
|
361
|
+
- `mc8yp-core-2025-dtm-v1.2.3.zip`
|
|
362
|
+
- `mc8yp-core-2024-dtm-v1.2.3.zip`
|
|
328
363
|
|
|
329
364
|
The GitHub release workflow uses that packaging command when building tagged releases.
|
|
330
365
|
|
|
@@ -3,6 +3,7 @@ import { defineCommand } from "citty";
|
|
|
3
3
|
import consola from "consola";
|
|
4
4
|
import * as v from "valibot";
|
|
5
5
|
import { exit } from "node:process";
|
|
6
|
+
import { cancel, isCancel, password } from "@clack/prompts";
|
|
6
7
|
//#region src/cli/subcommands/subcommands/add.ts
|
|
7
8
|
const command = defineCommand({
|
|
8
9
|
meta: {
|
|
@@ -20,10 +21,17 @@ const command = defineCommand({
|
|
|
20
21
|
type: "text",
|
|
21
22
|
cancel: "reject"
|
|
22
23
|
});
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
const passwordPrompt = await password({
|
|
25
|
+
message: "Password:",
|
|
26
|
+
clearOnError: true,
|
|
27
|
+
validate: (value) => {
|
|
28
|
+
if (!value) return "Password is required.";
|
|
29
|
+
}
|
|
26
30
|
});
|
|
31
|
+
if (isCancel(passwordPrompt)) {
|
|
32
|
+
cancel("Cancelled.");
|
|
33
|
+
exit();
|
|
34
|
+
}
|
|
27
35
|
if ((await getStoredC8yAuth()).some((cred) => cred.tenantUrl === cleanTenantUrl(tenantUrl))) {
|
|
28
36
|
if (!await consola.prompt("Credentials for this tenant already exist. Overwrite?", {
|
|
29
37
|
type: "confirm",
|
|
@@ -36,7 +44,7 @@ const command = defineCommand({
|
|
|
36
44
|
await setStoredC8yAuth({
|
|
37
45
|
tenantUrl,
|
|
38
46
|
user,
|
|
39
|
-
password
|
|
47
|
+
password: passwordPrompt
|
|
40
48
|
});
|
|
41
49
|
consola.success("Credentials saved successfully!");
|
|
42
50
|
exit();
|