appcrane-mcp 1.1.1 → 1.3.2
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 +14 -3
- package/catalog.json +81 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -103,9 +103,20 @@ Both catalog scripts import the platform's own `getToolCatalog()` from a sibling
|
|
|
103
103
|
`deployhub` checkout; set `APPCRANE_SRC` to point at its `server/services/mcpTools.js`
|
|
104
104
|
if yours lives elsewhere.
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
### Releasing
|
|
107
|
+
|
|
108
|
+
Bump `version` in `package.json`, commit, then push a matching tag:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
git tag v1.3.2 && git push origin v1.3.2
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`.github/workflows/publish.yml` publishes it to npm with **npm Trusted Publishing**: no npm
|
|
115
|
+
token and no one-time password, and npm attaches provenance (the commit it was built from).
|
|
116
|
+
The workflow refuses a tag that does not match `package.json`, and checks the catalog against
|
|
117
|
+
the platform's current `main` before publishing, so a stale `catalog.json` cannot ship. (It
|
|
118
|
+
has rotted silently before: 22 tools behind the platform, 35 advertised against 57 real.)
|
|
119
|
+
Run `npm run check:catalog` locally first to find out before CI does.
|
|
109
120
|
|
|
110
121
|
The bundled `catalog.json` is generated from the real tool definitions in the AppCrane platform (`deployhub/server/services/mcpTools.js`) and reflects the AWS-aligned tool vocabulary (`appcrane_set_secret`, `appcrane_get_secret`, `appcrane_cp`, and the `stage` parameter). It is committed so the package ships self-contained.
|
|
111
122
|
|
package/catalog.json
CHANGED
|
@@ -219,7 +219,7 @@
|
|
|
219
219
|
},
|
|
220
220
|
{
|
|
221
221
|
"name": "appcrane_rollback",
|
|
222
|
-
"description": "Roll an env back to a prior release. Pass deployment_id (from appcrane_list_releases) to target a specific release, or omit it to roll back to the immediately previous one. Re-runs that release from its recorded build
|
|
222
|
+
"description": "Roll an env back to a prior release. Pass deployment_id (from appcrane_list_releases) to target a specific release, or omit it to roll back to the immediately previous one. Re-runs that release from its recorded build and health-checks it. A rollback to the IMMEDIATELY PREVIOUS release restarts the cached per-commit image without rebuilding, because image_retention defaults to 1 (the running image plus the one behind it); rolling back further, or on an app whose image_retention is 0, rebuilds that commit first. Records a NEW deployment and marks the previous live one rolled_back. Owner-only (or global admin).",
|
|
223
223
|
"inputSchema": {
|
|
224
224
|
"type": "object",
|
|
225
225
|
"properties": {
|
|
@@ -819,7 +819,8 @@
|
|
|
819
819
|
"image_retention": {
|
|
820
820
|
"type": "integer",
|
|
821
821
|
"minimum": 0,
|
|
822
|
-
"maximum": 50
|
|
822
|
+
"maximum": 50,
|
|
823
|
+
"description": "How many PREVIOUS per-commit images to keep per environment, on top of the running one. Default 1: the previous release's image stays on disk, so rolling back to it restarts instead of rebuilding. Raise it to make older rollback targets fast too (each extra image costs roughly the app's own layers, tens of kB when only source changed between deploys, tens of MB when dependencies did). 0 keeps only the running image and makes every rollback rebuild."
|
|
823
824
|
},
|
|
824
825
|
"frame_ancestors": {
|
|
825
826
|
"type": "string"
|
|
@@ -847,6 +848,71 @@
|
|
|
847
848
|
"additionalProperties": false
|
|
848
849
|
}
|
|
849
850
|
},
|
|
851
|
+
{
|
|
852
|
+
"name": "appcrane_get_app_context",
|
|
853
|
+
"description": "Read an app's agent context — the operator notes at DATA_DIR/apps/<slug>/agent-context.md that are injected into every AppCrane coder dispatch for that app. Use this before writing, so an append or a replace is an informed one. Returns an empty string when no context has been written yet. App admin or owner (or global admin) required, because these notes routinely contain internal detail about how an app is built and operated.",
|
|
854
|
+
"inputSchema": {
|
|
855
|
+
"type": "object",
|
|
856
|
+
"properties": {
|
|
857
|
+
"slug": {
|
|
858
|
+
"type": "string",
|
|
859
|
+
"description": "App slug."
|
|
860
|
+
}
|
|
861
|
+
},
|
|
862
|
+
"required": [
|
|
863
|
+
"slug"
|
|
864
|
+
],
|
|
865
|
+
"additionalProperties": false
|
|
866
|
+
}
|
|
867
|
+
},
|
|
868
|
+
{
|
|
869
|
+
"name": "appcrane_append_app_context",
|
|
870
|
+
"description": "Append a note to an app's agent context, so the AppCrane coder knows what you just learned. This is the tool to reach for by default: it cannot destroy what someone else wrote, which appcrane_set_app_context can. The note is added under a timestamped heading. Write what would be expensive for the next agent to rediscover — a constraint, a gotcha, why something is the way it is — not a transcript of what you did. App admin or owner required.",
|
|
871
|
+
"inputSchema": {
|
|
872
|
+
"type": "object",
|
|
873
|
+
"properties": {
|
|
874
|
+
"slug": {
|
|
875
|
+
"type": "string",
|
|
876
|
+
"description": "App slug."
|
|
877
|
+
},
|
|
878
|
+
"note": {
|
|
879
|
+
"type": "string",
|
|
880
|
+
"description": "Markdown to append. Written under a heading naming who added it and when."
|
|
881
|
+
},
|
|
882
|
+
"heading": {
|
|
883
|
+
"type": "string",
|
|
884
|
+
"description": "Optional short title for this note, e.g. \"Deploy gotcha\". Defaults to a timestamp alone."
|
|
885
|
+
}
|
|
886
|
+
},
|
|
887
|
+
"required": [
|
|
888
|
+
"slug",
|
|
889
|
+
"note"
|
|
890
|
+
],
|
|
891
|
+
"additionalProperties": false
|
|
892
|
+
}
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
"name": "appcrane_set_app_context",
|
|
896
|
+
"description": "REPLACE an app's entire agent context. Destructive: whatever a human or another agent wrote is gone. Prefer appcrane_append_app_context unless you are deliberately rewriting the whole document — and read it first with appcrane_get_app_context so you know what you are discarding. Pass an empty string to clear it. App admin or owner required.",
|
|
897
|
+
"inputSchema": {
|
|
898
|
+
"type": "object",
|
|
899
|
+
"properties": {
|
|
900
|
+
"slug": {
|
|
901
|
+
"type": "string",
|
|
902
|
+
"description": "App slug."
|
|
903
|
+
},
|
|
904
|
+
"content": {
|
|
905
|
+
"type": "string",
|
|
906
|
+
"description": "The full new content. Replaces everything. Empty string clears the context."
|
|
907
|
+
}
|
|
908
|
+
},
|
|
909
|
+
"required": [
|
|
910
|
+
"slug",
|
|
911
|
+
"content"
|
|
912
|
+
],
|
|
913
|
+
"additionalProperties": false
|
|
914
|
+
}
|
|
915
|
+
},
|
|
850
916
|
{
|
|
851
917
|
"name": "appcrane_set_app_meta",
|
|
852
918
|
"description": "Set an app's category, visibility, auth_mode, and/or auth_bypass_paths — the owner self-service fields (same controls the dashboard Launcher exposes to owners). Owner of the app (or global admin) required. visibility is one of public / private / hidden. auth_mode is `authenticated` (default — all routes go through AppCrane SSO) or `headless` (the app bypasses forward_auth ENTIRELY and is reachable without identity — right tool for telemetry ingest, public webhooks, status pages; the app's own server is responsible for any payload-level authn). A headless app is still served BY CADDY over HTTP — TLS, security headers and access logging all still apply; it is not a raw port. An app that does not speak HTTP at all needs ingress_type='tcp', and an app that speaks HTTP AND needs a second raw port for non-HTTP clients needs ingress_type='dual' (both via appcrane_set_app_ingress, platform admin only) — different and far more exposed things. auth_bypass_paths (v2.7.27+) is an array of path prefixes (e.g. [\"/ws/local-runner\"]) that bypass SSO on this app only — narrower than headless mode; the app authenticates those paths itself (e.g. token in query string). The platform strips incoming X-AppCrane-* headers on bypass paths (forgery defense intact) and suppresses access logging for them (token-in-query never sits in log storage). Owners may only assign an EXISTING category; creating a brand-new category is reserved for global admins. For powerful fields (github_url, branch, token, source_type, resource limits) use appcrane_update_app (admin only).",
|
|
@@ -1265,7 +1331,7 @@
|
|
|
1265
1331
|
},
|
|
1266
1332
|
{
|
|
1267
1333
|
"name": "appcrane_push_to_managed_app",
|
|
1268
|
-
"description": "Push a batch of files to a managed app's AMC_<slug> repo, authenticated server-side via AppCrane's service-account credential. Use this — NOT github_push_files — for managed apps, because github_* tools authenticate with the caller's personal PAT, which has zero access to the service account's repos. Multiple files become a single commit. files: [{ path, content, encoding? }] where encoding defaults to \"utf-8\" (use \"base64\" for binaries like icons). Requires the app to already exist via appcrane_create_managed_app. v2.7.22: response now includes per-file `sha256` (hex) and decoded `bytes` length so you can verify integrity — compute the SHA-256 of the bytes you sent, compare to the server's echo, and fail loudly if they differ. Essential for binary files where inline-string truncation or trailing-byte issues would otherwise produce a silently-broken commit. v2.10.7: for a large CODE file, do NOT inline it — upload the bytes over HTTP and commit by token. (1) `curl -F file=@big.js -H \"X-API-Key: <your dhk_mcp_ key>\" https://<host>/api/files/staged` returns { token, sha256, size_bytes }. (2) Pass that file as { path, staged_token } instead of { path, content }. The server reads the staged bytes and commits them verbatim, so 100+ KB sources push reliably without the model having to emit the content (which is where inline truncation comes from). Per file, provide exactly one of content or staged_token. Staged tokens are owner-scoped and expiring.",
|
|
1334
|
+
"description": "Push a batch of files to a managed app's AMC_<slug> repo, authenticated server-side via AppCrane's service-account credential. Use this — NOT github_push_files — for managed apps, because github_* tools authenticate with the caller's personal PAT, which has zero access to the service account's repos. Multiple files become a single commit. files: [{ path, content, encoding? }] where encoding defaults to \"utf-8\" (use \"base64\" for binaries like icons). Requires the app to already exist via appcrane_create_managed_app. v2.7.22: response now includes per-file `sha256` (hex) and decoded `bytes` length so you can verify integrity — compute the SHA-256 of the bytes you sent, compare to the server's echo, and fail loudly if they differ. Essential for binary files where inline-string truncation or trailing-byte issues would otherwise produce a silently-broken commit. v2.10.7: for a large CODE file, do NOT inline it — upload the bytes over HTTP and commit by token. (1) `curl -F file=@big.js -H \"X-API-Key: <your dhk_mcp_ key>\" https://<host>/api/files/staged` returns { token, sha256, size_bytes }. (2) Pass that file as { path, staged_token } instead of { path, content }. The server reads the staged bytes and commits them verbatim, so 100+ KB sources push reliably without the model having to emit the content (which is where inline truncation comes from). Per file, provide exactly one of content or staged_token. Staged tokens are owner-scoped and expiring. DELETIONS: pass `deletions: [\"old/path.js\", ...]` to remove files in the SAME commit as the writes. Crane-hosted apps only (a GitHub-backed managed app is refused — GitHub's contents API cannot express a deletion). For a pure deletion send files: []. Every deleted path must already exist on the branch (a typo is refused by name, never a silent no-op), no path may appear in both files and deletions, and a push that would leave the repository with no files at all is refused. The response echoes what was removed as `deleted`.",
|
|
1269
1335
|
"inputSchema": {
|
|
1270
1336
|
"type": "object",
|
|
1271
1337
|
"properties": {
|
|
@@ -1275,7 +1341,7 @@
|
|
|
1275
1341
|
},
|
|
1276
1342
|
"files": {
|
|
1277
1343
|
"type": "array",
|
|
1278
|
-
"minItems":
|
|
1344
|
+
"minItems": 0,
|
|
1279
1345
|
"maxItems": 200,
|
|
1280
1346
|
"items": {
|
|
1281
1347
|
"type": "object",
|
|
@@ -1307,6 +1373,15 @@
|
|
|
1307
1373
|
"additionalProperties": false
|
|
1308
1374
|
}
|
|
1309
1375
|
},
|
|
1376
|
+
"deletions": {
|
|
1377
|
+
"type": "array",
|
|
1378
|
+
"maxItems": 200,
|
|
1379
|
+
"items": {
|
|
1380
|
+
"type": "string",
|
|
1381
|
+
"description": "Repo-relative path to delete (no leading slash, no ..). Must already exist on the branch."
|
|
1382
|
+
},
|
|
1383
|
+
"description": "Paths to remove in this same commit. Crane-hosted (repo_backend=local) apps only. Combine with files, or send files: [] for a pure deletion."
|
|
1384
|
+
},
|
|
1310
1385
|
"message": {
|
|
1311
1386
|
"type": "string",
|
|
1312
1387
|
"description": "Commit message. Defaults to \"chore: scaffolding for <slug>\"."
|
|
@@ -1608,7 +1683,7 @@
|
|
|
1608
1683
|
},
|
|
1609
1684
|
{
|
|
1610
1685
|
"name": "appcrane_get_backup_status",
|
|
1611
|
-
"description": "Is
|
|
1686
|
+
"description": "Is backup actually working? Reports BOTH schedules — the off-site S3/R2 upload and the local nightly archive — with a verdict for each, so \"are we backed up\" is one call rather than an inference from raw settings. READ `off_site.has_off_site_copy` BEFORE ANY OTHER FIELD. It is true only when a destination is configured AND an upload has actually completed; a stored bucket with the schedule off, and a schedule that is on and has never finished, both produce NO copy off this host and both report false. When it is false, `off_site.notice` says so in words (\"No off-site copy — everything AppCrane knows lives on this host.\") and that sentence must be relayed, not summarised away: a local archive is not a substitute, because losing the host loses both copies. The LOCAL schedule (`local`) is ON BY DEFAULT and writes deployhub.db + .env ONLY, to DATA_DIR/backups/local, keeping `local.keep` copies — it covers a corrupted, deleted or badly-restored database, and nothing else: NOT app icons, NOT per-app /data, NOT declared volumes, NOT managed-app repositories, NOT images. The off-site upload covers the database, .env, icons and appdata. NEVER returns the secret access key; `has_secret` reports only whether one is stored. A config can be fully populated and still not be running (enabled=false), and it can be enabled and failing every night (see last_error). PLATFORM ADMIN ONLY.",
|
|
1612
1687
|
"inputSchema": {
|
|
1613
1688
|
"type": "object",
|
|
1614
1689
|
"properties": {},
|
|
@@ -1679,7 +1754,7 @@
|
|
|
1679
1754
|
},
|
|
1680
1755
|
{
|
|
1681
1756
|
"name": "appcrane_scan_report",
|
|
1682
|
-
"description": "Which hosted apps have known-vulnerable dependencies? Reports the recorded CVE scan state for the whole fleet, or for one app with `slug`. REPORT ONLY: this scan has never blocked a deploy and cannot — the apps belong to other teams who did not choose the control, so findings are recorded and mailed and the deploy proceeds either way. Never relay a finding as a deploy failure. READ `status` BEFORE READING COUNTS. It is four-valued: `ok` (scanned, nothing found) and `findings` (scanned, something found) are results; `skipped` (no lockfile AppCrane can read) and `error` (OSV unreachable, unparseable lockfile) mean the app was NOT SCANNED, as does having no scan row at all. Those two carry no findings for the same reason an unopened box is empty, and an agent that reports such an app as clean has stated the opposite of what is known — \"no vulnerabilities found\" is only ever true of an app whose status is `ok`. `assurance`
|
|
1757
|
+
"description": "Which hosted apps have known-vulnerable dependencies? Reports the recorded CVE scan state for the whole fleet, or for one app with `slug`. REPORT ONLY: this scan has never blocked a deploy and cannot — the apps belong to other teams who did not choose the control, so findings are recorded and mailed and the deploy proceeds either way. Never relay a finding as a deploy failure. READ `status` BEFORE READING COUNTS. It is four-valued: `ok` (scanned, nothing found) and `findings` (scanned, something found) are results; `skipped` (no lockfile AppCrane can read) and `error` (OSV unreachable, unparseable lockfile) mean the app was NOT SCANNED, as does having no scan row at all. Those two carry no findings for the same reason an unopened box is empty, and an agent that reports such an app as clean has stated the opposite of what is known — \"no vulnerabilities found\" is only ever true of an app whose status is `ok`. READ `coverage` BEFORE THE FINDINGS AND BEFORE `assurance`. It is the explicit arithmetic — `{ rows, covered, not_covered, skipped, errored, never_scanned, percent }` — where `percent` is covered/rows floored, and it is the only field that says how much of the fleet these numbers describe. `assurance` is still none / partial / complete and still means exactly that, but `partial` spans 1% to 99%: 30 covered rows out of 99 is `partial` and so is 98 out of 99, so NEVER relay `partial` as \"mostly covered\" or relay it without the counts beside it (`assurance_note` states this too). `skip_reasons` and `error_reasons` name WHY rows are uncovered, counted and most-common first, from the reason each row recorded — quote them instead of reporting a bare \"67 skipped\". `unscanned_count` and `unscanned_by_status` are unchanged. EVERY FINDING CARRIES `ecosystem` AND `fixed` beside `name`, `version` and `ids`. `fixed` is the version that resolves those advisories, or null when OSV PUBLISHED NO FIXED VERSION — a null means there is nothing to upgrade to yet, NEVER that no fix is needed and never that AppCrane did not look, so a null-`fixed` finding is not a harmless one. `manifests_scanned` says WHICH manifests were actually read, because coverage is per manifest and not per app: one scan row reads ONE manifest — the ecosystem named on it — so an app whose Go service was never read appears here beside its scanned npm frontend with an empty findings list, and that emptiness is evidence about the frontend only. Scans run at deploy AND daily, and the daily run is the one that matters, because it catches an advisory published against code that was already deployed and has not changed since. ADMIN ONLY.",
|
|
1683
1758
|
"inputSchema": {
|
|
1684
1759
|
"type": "object",
|
|
1685
1760
|
"properties": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appcrane-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.2",
|
|
4
4
|
"mcpName": "io.github.gitayg/appcrane",
|
|
5
5
|
"description": "Standalone MCP connector for AppCrane \u2014 the self-hosted deployment platform for AI-built apps. Serves the appcrane_* tool catalog for offline introspection and proxies real tool calls to your AppCrane instance.",
|
|
6
6
|
"type": "module",
|