appilot-mcp 0.2.1 → 0.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.
Files changed (36) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/LICENSE +15 -0
  4. package/README.md +74 -16
  5. package/dist/appilot-configurator.mcpb +0 -0
  6. package/dist/cli.d.ts +34 -0
  7. package/dist/cli.js +171 -0
  8. package/dist/client.d.ts +45 -1
  9. package/dist/client.js +74 -1
  10. package/dist/contract/healthContract.js +31 -4
  11. package/dist/index.bundle.js +820 -142
  12. package/dist/index.js +7 -0
  13. package/dist/manifest.d.ts +14 -2
  14. package/dist/manifest.js +31 -9
  15. package/dist/public-marketplace/.claude-plugin/marketplace.json +20 -0
  16. package/dist/public-marketplace/README.md +23 -0
  17. package/dist/public-marketplace/plugins/app-configurator/.claude-plugin/plugin.json +43 -0
  18. package/dist/public-marketplace/plugins/app-configurator/README.md +328 -0
  19. package/dist/public-marketplace/plugins/app-configurator/dist/index.bundle.js +57370 -0
  20. package/dist/public-marketplace/plugins/app-configurator/skills/app-configurator/SKILL.md +267 -0
  21. package/dist/public-marketplace/plugins/app-configurator/skills/app-configurator/agents/openai.yaml +13 -0
  22. package/dist/remote/consent.d.ts +10 -2
  23. package/dist/remote/consent.js +15 -6
  24. package/dist/remote/consentMessages.d.ts +4 -1
  25. package/dist/remote/consentMessages.js +9 -6
  26. package/dist/remote/httpServer.js +2 -2
  27. package/dist/remote/oauth.js +9 -9
  28. package/dist/scaffold.d.ts +68 -6
  29. package/dist/scaffold.js +424 -97
  30. package/dist/server.js +175 -18
  31. package/dist/version.d.ts +1 -1
  32. package/dist/version.js +1 -1
  33. package/examples/app.appilot.json +212 -0
  34. package/mcpb/manifest.json +117 -21
  35. package/package.json +5 -3
  36. package/skills/app-configurator/SKILL.md +61 -19
@@ -2,9 +2,9 @@
2
2
  "manifest_version": "0.3",
3
3
  "name": "appilot-configurator",
4
4
  "display_name": "Appilot Configurator",
5
- "version": "0.2.1",
6
- "description": "Configure, audit, repair, back up, and restore an Appilot app's content model.",
7
- "long_description": "Connects Claude Desktop to an Appilot instance, cloud or on-premise, so it can read the app's content-model configuration, audit it against the Appilot config health contract, repair what it finds, and export or restore a whole configuration bundle. The static gate runs locally, so an audit works without network access to anything but your own instance. Access is a scoped service token you create in the Backoffice and revoke there.",
5
+ "version": "0.3.0",
6
+ "description": "Set up, configure, audit, repair, back up and restore an Appilot app's content model, and provision the app, its domains and its widget key.",
7
+ "long_description": "Connects Claude Desktop to an Appilot instance, cloud or on-premise. It provisions an app, its domains and its widget key, generates the host application's integration code, and verifies the result against the running page. It then reads the app's content-model configuration, audits it against the Appilot config health contract, repairs what it finds, and exports or restores a whole configuration bundle. The static gate runs locally, so an audit works without network access to anything but your own instance. Access is a scoped service token you create in the Backoffice and revoke there.",
8
8
  "author": {
9
9
  "name": "Appilot",
10
10
  "url": "https://appilot.space"
@@ -12,13 +12,20 @@
12
12
  "homepage": "https://appilot.space",
13
13
  "documentation": "https://docs.appilot.space/docs/developers/configure-with-ai/overview",
14
14
  "license": "ISC",
15
- "keywords": ["appilot", "configuration", "content-model", "audit"],
15
+ "keywords": [
16
+ "appilot",
17
+ "configuration",
18
+ "content-model",
19
+ "audit"
20
+ ],
16
21
  "server": {
17
22
  "type": "node",
18
23
  "entry_point": "dist/index.bundle.js",
19
24
  "mcp_config": {
20
25
  "command": "node",
21
- "args": ["${__dirname}/dist/index.bundle.js"],
26
+ "args": [
27
+ "${__dirname}/dist/index.bundle.js"
28
+ ],
22
29
  "env": {
23
30
  "APPILOT_BASE_URL": "${user_config.base_url}",
24
31
  "APPILOT_PAT": "${user_config.pat}",
@@ -27,21 +34,106 @@
27
34
  }
28
35
  },
29
36
  "tools": [
30
- { "name": "capabilities", "description": "Probe the instance for its version, migration level, and configurable entities." },
31
- { "name": "read_config", "description": "Read an app's content-model configuration as a normalized snapshot." },
32
- { "name": "validate_config", "description": "Audit a configuration against the Appilot config health contract." },
33
- { "name": "entity_template", "description": "A valid skeleton for one entity kind, with the enums this instance accepts." },
34
- { "name": "create_entity", "description": "Create a view, control, form, tool, zone, action plan, knowledge article or session template." },
35
- { "name": "update_entity", "description": "Patch any of the eight entity kinds by its row id." },
36
- { "name": "delete_entity", "description": "Delete an entity, refused when something still references it." },
37
- { "name": "validate_action_plan", "description": "Check draft plan sections before writing them." },
38
- { "name": "inspect_page", "description": "Read a page and rank locator candidates. Takes a URL or pasted markup." },
39
- { "name": "export_config", "description": "Export the whole configuration as a portable ConfigBundle." },
40
- { "name": "import_config", "description": "Import a ConfigBundle, dry-run first, merge or replace." },
41
- { "name": "soak_selectors", "description": "Check control selectors against a live page. Needs Playwright." },
42
- { "name": "scaffold_agent_first", "description": "The four artifacts one capability needs to be agent-operable." },
43
- { "name": "report_feedback", "description": "Report a gap or a defect in Appilot. Needs the feedback:write scope." },
44
- { "name": "list_feedback", "description": "This organization's reports, with status and occurrence count." }
37
+ {
38
+ "name": "capabilities",
39
+ "description": "Probe the instance for its version, migration level, and the closed vocabularies its entities accept."
40
+ },
41
+ {
42
+ "name": "read_config",
43
+ "description": "Read an app's content-model configuration as a normalized snapshot."
44
+ },
45
+ {
46
+ "name": "validate_config",
47
+ "description": "Audit a configuration against the Appilot config health contract."
48
+ },
49
+ {
50
+ "name": "entity_template",
51
+ "description": "A valid skeleton for one entity kind, with the enums this instance accepts."
52
+ },
53
+ {
54
+ "name": "create_entity",
55
+ "description": "Create a view, control, form, tool, zone, action plan, knowledge article or session template."
56
+ },
57
+ {
58
+ "name": "update_entity",
59
+ "description": "Patch any of the eight entity kinds by its row id."
60
+ },
61
+ {
62
+ "name": "delete_entity",
63
+ "description": "Delete an entity, refused when something still references it."
64
+ },
65
+ {
66
+ "name": "validate_action_plan",
67
+ "description": "Check draft plan sections before writing them."
68
+ },
69
+ {
70
+ "name": "export_config",
71
+ "description": "Export the whole configuration as a portable ConfigBundle."
72
+ },
73
+ {
74
+ "name": "import_config",
75
+ "description": "Import a ConfigBundle, dry-run first, merge or replace."
76
+ },
77
+ {
78
+ "name": "whoami",
79
+ "description": "Which organization, which app and which scopes this credential reaches."
80
+ },
81
+ {
82
+ "name": "create_app",
83
+ "description": "Provision an app, its domains and a widget key, with the snippets to paste in."
84
+ },
85
+ {
86
+ "name": "list_apps",
87
+ "description": "The apps this organization has provisioned, with their domains and verification status."
88
+ },
89
+ {
90
+ "name": "list_widget_keys",
91
+ "description": "The organization's widget keys by label and prefix. No raw key, no secret."
92
+ },
93
+ {
94
+ "name": "verify_domain",
95
+ "description": "Where a domain's DNS verification stands, and the TXT record it needs."
96
+ },
97
+ {
98
+ "name": "integration_snippet",
99
+ "description": "The script tag and boot call for an app that already exists. Writes nothing."
100
+ },
101
+ {
102
+ "name": "plan_manifest",
103
+ "description": "Preview what an appilot.app-manifest would change. Writes nothing."
104
+ },
105
+ {
106
+ "name": "apply_manifest",
107
+ "description": "Provision and configure an app from a previously planned manifest."
108
+ },
109
+ {
110
+ "name": "scaffold_integration",
111
+ "description": "The host application's integration source: identity relay, widget boot, a client action."
112
+ },
113
+ {
114
+ "name": "verify_integration",
115
+ "description": "Load the running page and report what is actually true about the integration."
116
+ },
117
+ {
118
+ "name": "soak_selectors",
119
+ "description": "Check control selectors against a live page. Needs Playwright."
120
+ },
121
+ {
122
+ "name": "inspect_page",
123
+ "description": "Read a page and rank locator candidates. Takes a URL or pasted markup."
124
+ },
125
+ {
126
+ "name": "scaffold_agent_first",
127
+ "description": "The artifacts one capability needs to be agent-operable."
128
+ },
129
+ {
130
+ "name": "report_feedback",
131
+ "description": "Report a gap or a defect in Appilot. Needs the feedback:write scope."
132
+ },
133
+ {
134
+ "name": "list_feedback",
135
+ "description": "This organization's reports, with status and occurrence count."
136
+ }
45
137
  ],
46
138
  "user_config": {
47
139
  "base_url": {
@@ -65,7 +157,11 @@
65
157
  }
66
158
  },
67
159
  "compatibility": {
68
- "platforms": ["darwin", "win32", "linux"],
160
+ "platforms": [
161
+ "darwin",
162
+ "win32",
163
+ "linux"
164
+ ],
69
165
  "runtimes": {
70
166
  "node": ">=18.0.0"
71
167
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "appilot-mcp",
3
- "version": "0.2.1",
4
- "description": "Appilot MCP server: read, validate, and fix an Appilot app's content-model configuration against the config health contract. Endpoint-agnostic (cloud or on-premise), scoped-service-token auth, local static gate + optional live DOM soak.",
3
+ "version": "0.3.0",
4
+ "description": "Appilot MCP server: provision an Appilot app, scaffold and verify the host integration, then read, validate and fix its content-model configuration against the config health contract. Endpoint-agnostic (cloud or on-premise), scoped-service-token auth, local static gate + optional live DOM soak.",
5
5
  "homepage": "https://appilot.space",
6
6
  "author": "BetterKnow GmbH",
7
7
  "keywords": [
@@ -24,6 +24,7 @@
24
24
  "files": [
25
25
  "dist",
26
26
  "skills",
27
+ "examples",
27
28
  "mcpb",
28
29
  ".mcp.json",
29
30
  ".codex-plugin",
@@ -66,6 +67,7 @@
66
67
  "test": "vitest run",
67
68
  "test:watch": "vitest",
68
69
  "start:http": "node dist/index.bundle.js --http",
69
- "build:mcpb": "node scripts/build-mcpb.mjs"
70
+ "build:mcpb": "node scripts/build-mcpb.mjs",
71
+ "build:marketplace": "node scripts/build-public-marketplace.mjs"
70
72
  }
71
73
  }
@@ -18,7 +18,9 @@ well-formed configuration; every rule maps to a real failure mode.
18
18
  - **Connected (Appilot MCP server available).** `capabilities`, `read_config` and
19
19
  `validate_config` read and audit. `entity_template`, `create_entity`,
20
20
  `update_entity`, `delete_entity` and `validate_action_plan` author, across all
21
- eight entity kinds. `inspect_page` looks at the screen. `export_config` /
21
+ eight entity kinds. `whoami`, `list_apps`, `list_widget_keys`, `create_app`,
22
+ `verify_domain`, `scaffold_integration` and `integration_snippet` set an app up
23
+ from nothing. `inspect_page` looks at the screen. `export_config` /
22
24
  `import_config` back up, clone and promote. `soak_selectors` and
23
25
  `verify_integration` prove it works on the real page. Prefer this mode. Always
24
26
  start with `capabilities` so you configure against what THIS instance supports
@@ -39,25 +41,52 @@ runs in the customer's own repository, where you already are.
39
41
  1. **`whoami`.** Which org does this credential reach, and which scopes does it
40
42
  hold? A mistyped or revoked token should fail here, not as an opaque 401
41
43
  halfway through. Provisioning needs `provision:write`, minted in the
42
- Backoffice under Admin, Service Tokens with the read/write/provision preset.
44
+ Backoffice under Service tokens with the preset called **Set up
45
+ integrations**. Only an organization administrator can mint it, so a
46
+ configurator who is not one has to ask for it rather than work around it.
47
+ `list_apps` then answers what already exists, and `list_widget_keys` answers
48
+ which keys were already minted, so a re-run recognises them instead of asking
49
+ for more.
43
50
  2. **`create_app`** with the app name and the domains it runs on. Idempotent, so
44
51
  a re-run converges rather than creating a second app. It returns the script
45
52
  tag, the boot snippet, and (once, at creation) the widget key and its secret.
46
53
  A **live** key needs a verified domain: on a hostname nobody has proved they
47
54
  control, the key comes back `blocked` with the TXT record to publish, while
48
- the app and its domains are created anyway. Publish the record and verify, or
49
- pass `isTest` for a test key that works the same way and claims nothing.
55
+ the app and its domains are created anyway. Publish the record, then
56
+ `verify_domain` with `trigger`, or pass `isTest: true` for a test key that
57
+ claims nothing. The parameter is `isTest`, the same name the manifest and the
58
+ API use.
50
59
  The **key** is publishable and belongs in the page. The **secret** is not: it
51
60
  goes in the host's backend environment and must never reach a browser or a
52
61
  client bundle. If you are connected over the remote transport the secret is
53
62
  withheld on purpose; point the user at the Backoffice for it.
54
- 3. **`scaffold_integration`** for the host's framework. It returns file CONTENTS,
55
- which you write into the repository. The identity relay is the piece that
56
- matters: `resolveUser` is the security boundary and must derive the user from
57
- a credential the host already trusts, never from the request body.
63
+
64
+ **Working on the user's own machine.** There are two answers and they are not
65
+ equal. Preferred: have them run the app on a hostname that resolves to
66
+ 127.0.0.1 (`myapp.lvh.me:3000`, or an `/etc/hosts` entry) and register THAT
67
+ hostname as a domain. The page then resolves its tenant by hostname, no widget
68
+ key is needed, verification is not required for that path, and the turn gets
69
+ the full app context: views, controls, forms, plans, knowledge. Fallback:
70
+ bare `localhost` with a `wk_test_` key, which gets the organization and the
71
+ user and NO app context, because no domain resolves. Never pass `localhost` or
72
+ `127.0.0.1` as a domain: they name every developer's machine, one row for the
73
+ whole platform, and the write is refused.
74
+ 3. **`scaffold_integration`** for the host's framework, or `other` when the
75
+ backend is not Node (Django, Rails, PHP), which returns the raw exchange
76
+ instead. It returns file CONTENTS, which you write into the repository. The
77
+ identity relay is the piece that matters: `resolveUser` is the security
78
+ boundary and must derive the user from a credential the host already trusts,
79
+ never from the request body. The boot file reads the publishable key from the
80
+ framework's public variable (`NEXT_PUBLIC_APPILOT_WIDGET_KEY`,
81
+ `VITE_APPILOT_WIDGET_KEY`, `PUBLIC_APPILOT_WIDGET_KEY`); do not replace that
82
+ with a literal. `integration_snippet` returns the same two snippets later, for
83
+ an app that already exists, without a provisioning write.
58
84
  4. **Make one capability agent-operable** before adding screens' worth of
59
85
  configuration. The test for agent-first is whether a user could complete the
60
- feature end to end through the assistant alone.
86
+ feature end to end through the assistant alone. `scaffold_agent_first` takes a
87
+ `shape`: `create` for an open/fill/submit flow, `navigate` for one step to a
88
+ screen, and `read` for a capability the agent answers, which gets no action
89
+ plan at all.
61
90
  5. **`verify_integration`** against the running page. It answers what is actually
62
91
  true: does the domain resolve to a tenant, does the relay refuse an
63
92
  unauthenticated caller correctly, does the widget boot, is the console clean.
@@ -65,12 +94,23 @@ runs in the customer's own repository, where you already are.
65
94
  6. Then configure the content model, below, and `validate_config`.
66
95
 
67
96
  **A whole tenant as one file.** `plan_manifest` / `apply_manifest` take an
68
- `appilot.app-manifest`: the app, its domains, its keys, and a ConfigBundle. Keep
69
- it in the repository under version control, so configuration is diffable in a
70
- pull request and promotable from staging to production. `apply_manifest` requires
71
- the `planToken` that `plan_manifest` returned for the same file, so you cannot
72
- apply something nobody previewed, and an edit between the two calls fails rather
73
- than committing silently.
97
+ `appilot.app-manifest`: the app, its domains, its keys, and a ConfigBundle. A
98
+ complete example ships with the server at `examples/app.appilot.json`; copy it
99
+ rather than assembling one from doc snippets. Keep it in the repository under
100
+ version control, so configuration is diffable in a pull request and promotable
101
+ from staging to production. `apply_manifest` requires the `planToken` that
102
+ `plan_manifest` returned for the same file, so you cannot apply something nobody
103
+ previewed, and an edit between the two calls fails rather than committing
104
+ silently.
105
+
106
+ Two things about an apply are worth saying out loud. Only the CONFIG half is
107
+ revisioned: every commit persists a `pre_restore` revision, so a wrong import is
108
+ undone by restoring it, while a domain or a key the provisioning half created is
109
+ undone by hand. And provisioning is asked for by the manifest, not by the tool:
110
+ an apply whose app, domains and keys already exist needs only `config:write`,
111
+ which is what lets a CI token keep content in sync without being able to claim
112
+ domains. Outside an MCP client, `appilot-mcp plan <file>` and
113
+ `appilot-mcp apply <file>` are the same two calls from a shell.
74
114
 
75
115
  ## The content model (what you configure)
76
116
 
@@ -239,10 +279,12 @@ file is safe to save, commit, or share. `read_config` stays the reasoning view;
239
279
  ## Guardrails
240
280
 
241
281
  - Confirm before writing. Show the diff you intend to apply; get a yes.
242
- - Writing needs a `config:write` service token; reading/validating needs only
243
- `config:read`; provisioning needs `provision:write`. If a call 403s on scope,
244
- tell the user to mint a token with that scope in the Backoffice (admin →
245
- service tokens), don't work around it.
282
+ - Writing needs a `config:write` service token; reading and validating need only
283
+ `config:read`; provisioning needs `provision:write`. If a call is refused on
284
+ scope, say which scope is missing and who grants it: `provision:write` comes
285
+ from an organization administrator in the Backoffice, under Service tokens
286
+ with the "Set up integrations" preset, or from the account approval screen. Do
287
+ not work around it.
246
288
  - **Never put a widget secret in a file that ships to the browser.** It goes in
247
289
  the server environment: no `NEXT_PUBLIC_` prefix, no `VITE_`, no committed
248
290
  `.env`. The publishable key is different and belongs in the page.