@homespunapps/mcp 1.6.28 → 1.6.30
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/dist/tools.js +58 -33
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/server.json +2 -2
package/dist/tools.js
CHANGED
|
@@ -162,7 +162,7 @@ const deployAppShape = {
|
|
|
162
162
|
.string()
|
|
163
163
|
.min(1)
|
|
164
164
|
.optional()
|
|
165
|
-
.describe("The app's UI as a complete HTML document (single file, up to the relay's size cap), sent
|
|
165
|
+
.describe("The app's UI as a complete HTML document (single file, up to the relay's size cap), sent inline. Provide either this or `html_path`. Inline is required for a hosted or remote connector that has no filesystem. If both are given, inline `html` wins."),
|
|
166
166
|
html_path: z
|
|
167
167
|
.string()
|
|
168
168
|
.optional()
|
|
@@ -190,7 +190,7 @@ const deployAppShape = {
|
|
|
190
190
|
z.object({
|
|
191
191
|
path: z
|
|
192
192
|
.string()
|
|
193
|
-
.describe("App-relative, same-origin reference the HTML uses,
|
|
193
|
+
.describe("App-relative, same-origin reference the HTML uses, for example 'frames/000.jpg' or 'media/intro.mp4'. Must be relative: no leading '/', no '..' segment, no backslash, charset [A-Za-z0-9._/-], and not under a reserved prefix (_hs, b)."),
|
|
194
194
|
content_base64: z
|
|
195
195
|
.string()
|
|
196
196
|
.describe("Standard base64 of the asset's raw bytes."),
|
|
@@ -433,7 +433,7 @@ const attachmentsShape = {
|
|
|
433
433
|
"revoke_token",
|
|
434
434
|
"list_tokens",
|
|
435
435
|
])
|
|
436
|
-
.describe("Binary attachment operations.
|
|
436
|
+
.describe("Binary attachment operations. The upload path affects token cost: `fetch` and presign plus finalize keep the bytes out of the model context entirely, while upload with `content_base64` carries them in the tool-call arguments at a cost proportional to file size, paid again on every retry. fetch takes { source_url, scope } and the relay downloads the bytes itself (https only, SSRF-guarded), running the same sniff, allowlist, size, quota and scan checks as any upload. upload takes `content_base64` (base64 bytes, no filesystem) or `file_path` (absolute, read on the relay host), scoped agent or app. presign plus finalize is three steps: presign with { mime, size, sha256, scope }, PUT the bytes to put_url out of band, then finalize, which re-sniffs and re-checks them. download fetches bytes by attachment_id to an absolute out_path or returns base64. show returns metadata only. list returns the agent's attachments. delete is a soft-delete. mint_token mints a /b/<token> capability URL, returned once. revoke_token and list_tokens manage those tokens."),
|
|
437
437
|
size: z
|
|
438
438
|
.number()
|
|
439
439
|
.int()
|
|
@@ -455,11 +455,11 @@ const attachmentsShape = {
|
|
|
455
455
|
source_url: z
|
|
456
456
|
.string()
|
|
457
457
|
.optional()
|
|
458
|
-
.describe("fetch: an https URL the
|
|
458
|
+
.describe("fetch: an https URL the relay downloads server-side, so the bytes do not enter the model context and cost no tokens. SSRF-guarded: https only, no private, loopback, link-local or metadata hosts, DNS pinned, redirects refused, size-capped and timed out. The downloaded bytes run the same byte-sniff, allowlist, size, quota and scan checks as any upload. This and presign plus finalize are the zero-context paths for real images and media."),
|
|
459
459
|
content_base64: z
|
|
460
460
|
.string()
|
|
461
461
|
.optional()
|
|
462
|
-
.describe("upload: the file bytes as base64, sent
|
|
462
|
+
.describe("upload: the file bytes as base64, sent inline with no filesystem access. The base64 rides in the tool-call arguments and enters the model context, costing tokens proportional to file size; a few-hundred-KB image is already expensive, and the cost repeats on every retry. presign plus finalize avoids that for any real image or media whenever the client can do an out-of-band HTTP PUT, which leaves `content_base64` suited to small assets such as a tiny icon, and to clients that cannot PUT out of band. If both `content_base64` and `file_path` are given, `content_base64` wins. The relay sniffs the real type and enforces the same size, allowlist and quota checks as a file upload."),
|
|
463
463
|
scope: z
|
|
464
464
|
.enum(["agent", "app"])
|
|
465
465
|
.optional()
|
|
@@ -646,7 +646,7 @@ const communityShape = {
|
|
|
646
646
|
ingestRule: z
|
|
647
647
|
.string()
|
|
648
648
|
.optional()
|
|
649
|
-
.describe("The manifest `ingest` rule this step wires up. Allowed
|
|
649
|
+
.describe("The manifest `ingest` rule this step wires up. Allowed only on a 'connect' step, and optional there; publish rejects a name that x-homespun-manifest.ingest does not declare. Each install mints that rule its own hook URL, which the installer pastes into the external service."),
|
|
650
650
|
}))
|
|
651
651
|
.optional()
|
|
652
652
|
.describe("publish only. Ordered typed setup steps an installing agent follows after install (up to 20). A 'config'/'upload' step may carry a `key` naming a field of the manifest's settingsCollection that its install-time answer is written into; a 'connect' step may carry an `ingestRule` naming a manifest ingest rule it wires up. Read back via get_submission and rendered on the template detail page."),
|
|
@@ -764,12 +764,14 @@ export const TOOLS = [
|
|
|
764
764
|
// ----- v2 app lifecycle + data (discrete, hot-path) -----------------------
|
|
765
765
|
{
|
|
766
766
|
name: "deploy_app",
|
|
767
|
-
description:
|
|
767
|
+
description: "Deploy a v2 app: an HTML document plus a capability manifest, hosted at its own URL. The manifest carries eight extension keys: app metadata; collections, with per-collection write, update, read and delete role lists, where write gates creates and also gates updates unless an update list is declared; externalHosts, a fetch allowlist; cdn, to allow CDN scripts and styles; capabilities, for Permissions-Policy opt-ins; embeds, an iframe frame-src allowlist; notify, for email-on-row rules; and webhooks, for signed HTTP POST on-row rules. The manifest grammar is documented in the Homespun guide that get_skill returns.\n\nPass no `app_id` to create, which mints a slug and URL, or pass `app_id` to redeploy an existing app with new content. Supply the HTML inline as `html`, or as `html_path`, an absolute path read on the MCP-server host, which is the relay for a hosted connector or the CLI host for a locally-run one, and not the remote agent's machine; it avoids retransmitting a large HTML file on every deploy, only a locally-run connector can read it, and inline `html` wins if both are given. `dry_run:true` (alias `check`) validates only: it runs the full manifest and asset-shape validation, the redeploy compat gate and the schedule-timezone advisory, then returns { ok, warnings, compat?, breaks? } without creating a version or mutating anything.\n\nA redeploy is refused with manifest_incompatible_redeploy, unless force:true, when it would strand rows already written (dropping a collection, tightening a schema, flipping appendOnly), or when it would widen what the app's install screen discloses, such as a collection's read reaching further than the live manifest. The break quotes the sentence a user would now be asked to approve. Taking access away never prompts: dropping a role, or adding update:[\\\"creator\\\"] to a write:[\\\"anyone\\\"] collection, redeploys clean. A removed collection is detached rather than deleted.\n\nImages, fonts, audio, video and data files ship with the app in the same call via `assets[]`. Each is validated and stored app-scoped and served at its `path` on the app's own origin, so the HTML references it by a stable same-origin path such as `<img src=\\\"frames/000.jpg\\\">`; media and font paths support HTTP Range for seeking. A redeploy's assets replace the previous version's set.\n\nReturns { app_id, slug, url, version, visibility, created } on create, or { app_id, version, compat, breaks? } on redeploy.",
|
|
768
768
|
inputSchema: deployAppShape,
|
|
769
769
|
annotations: {
|
|
770
770
|
title: "Deploy App",
|
|
771
771
|
readOnlyHint: false,
|
|
772
|
-
|
|
772
|
+
// Additive: publishes a NEW version. The slug is immutable and prior
|
|
773
|
+
// versions are retained, so a deploy removes nothing.
|
|
774
|
+
destructiveHint: false,
|
|
773
775
|
idempotentHint: false,
|
|
774
776
|
openWorldHint: true,
|
|
775
777
|
},
|
|
@@ -855,7 +857,7 @@ export const TOOLS = [
|
|
|
855
857
|
},
|
|
856
858
|
{
|
|
857
859
|
name: "list_rows",
|
|
858
|
-
description: "List rows in a v2 app's mutable collection. This also
|
|
860
|
+
description: "List rows in a v2 app's mutable collection. This is also how a collection's current state is polled, since MCP has no streaming: pass the prior next_cursor as `since` to fetch only rows that are new or changed. Returns { rows, next_cursor, has_more }.",
|
|
859
861
|
inputSchema: listRowsShape,
|
|
860
862
|
annotations: {
|
|
861
863
|
title: "List Rows",
|
|
@@ -876,7 +878,7 @@ export const TOOLS = [
|
|
|
876
878
|
},
|
|
877
879
|
{
|
|
878
880
|
name: "get_row",
|
|
879
|
-
description: "Fetch a single row by its key from a v2 app collection
|
|
881
|
+
description: "Fetch a single row by its key from a v2 app collection, through a dedicated relay route rather than a client-side scan. Returns { row }, or an isError row_not_found.",
|
|
880
882
|
inputSchema: getRowShape,
|
|
881
883
|
annotations: {
|
|
882
884
|
title: "Get Row",
|
|
@@ -894,12 +896,13 @@ export const TOOLS = [
|
|
|
894
896
|
},
|
|
895
897
|
{
|
|
896
898
|
name: "upsert_row",
|
|
897
|
-
description: "Create a row in a v2 app's collection, or return the existing row
|
|
899
|
+
description: "Create a row in a v2 app's collection, or return the existing row when `key` is already present (deduped:true). Row creation goes through this tool; there is no separate strict-create verb. Omit `key` to add a new row with a server-generated key, or pass `key` to ensure a row exists at that key. The collection must be declared in the app's manifest with 'agent' in its `write` list, which is the list that gates creates. When `key` matches a row the collection's `read` list does not reach for this caller, the result is row_not_found rather than the row, matching what get_row would return, so this never reads past `read`. Returns { row, deduped? }.",
|
|
898
900
|
inputSchema: upsertRowShape,
|
|
899
901
|
annotations: {
|
|
900
902
|
title: "Upsert Row",
|
|
901
903
|
readOnlyHint: false,
|
|
902
|
-
|
|
904
|
+
// Create-or-return-existing. Removes nothing.
|
|
905
|
+
destructiveHint: false,
|
|
903
906
|
idempotentHint: true,
|
|
904
907
|
openWorldHint: false,
|
|
905
908
|
},
|
|
@@ -920,12 +923,15 @@ export const TOOLS = [
|
|
|
920
923
|
},
|
|
921
924
|
{
|
|
922
925
|
name: "update_row",
|
|
923
|
-
description: "Update an existing row in a v2 app's collection
|
|
926
|
+
description: "Update an existing row in a v2 app's collection, replacing its data. Gated by the collection's `update` role list when it declares one, and by its `write` list otherwise, so a collection that scopes updates to the row's `creator` refuses an edit on someone else's row. Pass if_match with the row's current version for an optimistic-locked update; on a version mismatch the relay returns the current row, which is what a retry needs. Returns { row }.",
|
|
924
927
|
inputSchema: updateRowShape,
|
|
925
928
|
annotations: {
|
|
926
929
|
title: "Update Row",
|
|
927
930
|
readOnlyHint: false,
|
|
928
|
-
|
|
931
|
+
// Replaces a row's data in place. A replaceable write on a row the
|
|
932
|
+
// caller names explicitly, not a removal: the row still exists, and
|
|
933
|
+
// deletion is a separate tool (`delete_row`).
|
|
934
|
+
destructiveHint: false,
|
|
929
935
|
idempotentHint: true,
|
|
930
936
|
openWorldHint: false,
|
|
931
937
|
},
|
|
@@ -948,11 +954,12 @@ export const TOOLS = [
|
|
|
948
954
|
},
|
|
949
955
|
{
|
|
950
956
|
name: "delete_row",
|
|
951
|
-
description: "Soft-delete a row from a v2 app's collection. A watcher sees the deletion live
|
|
957
|
+
description: "Soft-delete a row from a v2 app's collection. A watcher sees the deletion live as op:delete on the change feed. Pass if_match for an optimistic-locked delete. Returns { deleted: true }.",
|
|
952
958
|
inputSchema: deleteRowShape,
|
|
953
959
|
annotations: {
|
|
954
960
|
title: "Delete Row",
|
|
955
961
|
readOnlyHint: false,
|
|
962
|
+
// Destructive: Removes the row (soft-delete, and watchers see op:delete).
|
|
956
963
|
destructiveHint: true,
|
|
957
964
|
idempotentHint: true,
|
|
958
965
|
openWorldHint: false,
|
|
@@ -971,7 +978,7 @@ export const TOOLS = [
|
|
|
971
978
|
},
|
|
972
979
|
{
|
|
973
980
|
name: "get_feed_events",
|
|
974
|
-
description: "Poll a v2 app's change feed for what happened
|
|
981
|
+
description: "Poll a v2 app's change feed for what has happened: row creates, updates and deletes, from any writer, agent or human. It is the long-poll analogue of `homespun apps watch`, since MCP has no streaming. The loop is: call with no `since` first, process the returned entries, keep the cursor, then call again passing it as `since` to get only newer entries. Passing wait (around 25) holds the request open until an entry arrives or it times out, which is how the feed is waited on rather than busy-polled. A `since` older than the retention floor returns resync_required, and the collections are then re-listed with list_rows. Returns { entries, cursor, truncated }.",
|
|
975
982
|
inputSchema: getFeedEventsShape,
|
|
976
983
|
annotations: {
|
|
977
984
|
title: "Get App Feed Events",
|
|
@@ -993,13 +1000,14 @@ export const TOOLS = [
|
|
|
993
1000
|
},
|
|
994
1001
|
{
|
|
995
1002
|
name: "apps",
|
|
996
|
-
description: "
|
|
1003
|
+
description: "The v2 app lifecycle apart from creation and redeploy, which deploy_app covers. Actions: list returns the owning human's apps; show returns full detail including manifest, timezone and has_share_token; update changes visibility and timezone, the slug being immutable, and switching to 'link' returns a share_url once; share_link_rotate issues a new share token for a 'link' app, returning a new share_url and revoking the old link, and generates one if the app has none; delete is an idempotent soft-delete; wake wakes a dormant app and is otherwise a no-op that reports the actual status; domain_set binds a custom domain and returns the DNS records the domain owner must publish, where the first domain bound serves the app and every later one redirects to it, which is how apex plus www is configured; domain_status returns the serving domain and its `aliases`, live-refreshed against Cloudflare when that is enabled, with last_error carrying the reason a domain is not activating; domain_remove unbinds one domain, or all of them when no `domain` is given, and is idempotent.",
|
|
997
1004
|
inputSchema: appsShape,
|
|
998
1005
|
// Consolidated tool: read actions (list/show) + mutating ones (update/
|
|
999
1006
|
// delete/wake). Hint reflects delete, the most-privileged action.
|
|
1000
1007
|
annotations: {
|
|
1001
1008
|
title: "Manage Apps",
|
|
1002
1009
|
readOnlyHint: false,
|
|
1010
|
+
// Destructive: `delete` removes an app.
|
|
1003
1011
|
destructiveHint: true,
|
|
1004
1012
|
idempotentHint: true,
|
|
1005
1013
|
openWorldHint: false,
|
|
@@ -1093,13 +1101,14 @@ export const TOOLS = [
|
|
|
1093
1101
|
},
|
|
1094
1102
|
{
|
|
1095
1103
|
name: "members",
|
|
1096
|
-
description: "
|
|
1104
|
+
description: "A v2 app's membership (auth spec section 6): who besides the owner can sign in to a private app and write to member-scoped collections. Actions: add invites or attaches a member by email, attaching immediately when the email already has a Human and otherwise sending a magic-link invite; list returns the app's owner and members; set_role changes an existing member's declared custom role in place, or clears it when null, and leaves their sessions intact, which is what makes it the way to re-role someone rather than removing and re-adding them; remove is idempotent and also revokes the human's live sessions on this app, and the app owner cannot be removed; roles returns the derived roles summary, giving the effective access a holder actually has per declared role and collection, reported separately for signed-in members and for grant-link holders because their role floors differ, along with member and active-grant-link counts.",
|
|
1097
1105
|
inputSchema: membersShape,
|
|
1098
1106
|
// Consolidated tool: read action (list) + mutating ones (add/remove).
|
|
1099
1107
|
// Hint reflects remove, the most-privileged action.
|
|
1100
1108
|
annotations: {
|
|
1101
1109
|
title: "Manage App Members",
|
|
1102
1110
|
readOnlyHint: false,
|
|
1111
|
+
// Destructive: `remove` revokes a member's access.
|
|
1103
1112
|
destructiveHint: true,
|
|
1104
1113
|
idempotentHint: true,
|
|
1105
1114
|
openWorldHint: false,
|
|
@@ -1169,13 +1178,14 @@ export const TOOLS = [
|
|
|
1169
1178
|
// ----- consolidated management tools --------------------------------------
|
|
1170
1179
|
{
|
|
1171
1180
|
name: "grants",
|
|
1172
|
-
description: "
|
|
1181
|
+
description: "A v2 app's grant links (M5). A grant link is a capability URL that confers a declared custom role (x-homespun-manifest.roles) on a stable per-holder anonymous identity, so a holder's own rows are isolated by author/:own scoping. A grant does not escalate to owner, member or agent. Actions: mint creates a link and returns a `grant_url` carrying the token in its #g= fragment, shown once and not recoverable afterwards; list returns the app's links and never a token; revoke is idempotent. mode 'once' is one-time, claimed by the first browser to open it; 'multi' is shared, capped by max_uses within expiry. An optional pin (pin_row_key or pin_where) narrows a holder to specific rows and never widens their access. One consequence worth knowing when minting: a write-only grant pinned to a single row key can still read that row's existing data back through create dedup, so such a grant exposes that row's current contents to the holder.",
|
|
1173
1182
|
inputSchema: grantsShape,
|
|
1174
1183
|
// Consolidated tool: read action (list) + mutating ones (mint/revoke).
|
|
1175
1184
|
// Hint reflects revoke, the most-privileged action.
|
|
1176
1185
|
annotations: {
|
|
1177
1186
|
title: "Manage App Grant Links",
|
|
1178
1187
|
readOnlyHint: false,
|
|
1188
|
+
// Destructive: `revoke` kills a live capability URL.
|
|
1179
1189
|
destructiveHint: true,
|
|
1180
1190
|
idempotentHint: true,
|
|
1181
1191
|
openWorldHint: false,
|
|
@@ -1246,7 +1256,7 @@ export const TOOLS = [
|
|
|
1246
1256
|
// ----- consolidated management tools --------------------------------------
|
|
1247
1257
|
{
|
|
1248
1258
|
name: "ingest",
|
|
1249
|
-
description: "
|
|
1259
|
+
description: "A v2 app's inbound catch-hooks (inbound-webhooks). A catch-hook lets an external system such as Stripe, Zapier, Make, Home Assistant or an email router POST JSON to a secret URL that writes into a declared collection, so the app receives data with no agent online. Hooks are declared in the manifest (x-homespun-manifest.ingest) and materialized at deploy, so this tool has no create or delete: it reads back the URL, rotates a leaked one, and manages the opt-in signing secret. After deploying a manifest that declares a hook, list is what yields the exact URL to paste into the external system. Actions: list returns the app's hooks, each with its full secret URL, current rule collection, mode, wake and handshake settings, per-status delivery counts and signing-secret state; rotate mints a fresh URL secret for one hook by name and returns the new url once, after which the old url stops working immediately with no redeploy needed; set_signing_secret provisions or rotates a hook's signing secret, which is a different secret from the URL and is what a provider HMACs the body with, minting one returned once when `secret` is omitted or storing a provider value verbatim when it is passed, and never echoing it back; clear_signing_secret removes it. Signature verification currently ships dark: nothing verifies a signature yet.",
|
|
1250
1260
|
inputSchema: ingestShape,
|
|
1251
1261
|
// Consolidated tool: read action (list) + a mutating one (rotate). Marked
|
|
1252
1262
|
// destructive (not read-only) because rotate invalidates the old URL, which
|
|
@@ -1256,6 +1266,8 @@ export const TOOLS = [
|
|
|
1256
1266
|
annotations: {
|
|
1257
1267
|
title: "Manage App Inbound Hooks",
|
|
1258
1268
|
readOnlyHint: false,
|
|
1269
|
+
// Destructive: `rotate` and `clear_signing_secret` invalidate a
|
|
1270
|
+
// secret an external system is actively signing with.
|
|
1259
1271
|
destructiveHint: true,
|
|
1260
1272
|
openWorldHint: false,
|
|
1261
1273
|
},
|
|
@@ -1304,7 +1316,7 @@ export const TOOLS = [
|
|
|
1304
1316
|
// ----- consolidated management tools --------------------------------------
|
|
1305
1317
|
{
|
|
1306
1318
|
name: "attachments",
|
|
1307
|
-
description: "Binary attachments (images, PDFs, audio, video) referenced from event payloads
|
|
1319
|
+
description: "Binary attachments (images, PDFs, audio, video) referenced from event payloads and input_data via `format: homespun-attachment-id`. Actions: upload, fetch, presign, finalize, download, show, list, delete, mint_token, revoke_token, list_tokens.\n\nChoosing an upload path matters for cost. An inline upload with `content_base64` carries the bytes in the tool-call arguments, so they enter the model context at a token cost proportional to file size, paid again on every retry; a few-hundred-KB image is already expensive. Two paths avoid that entirely: fetch, when the bytes are reachable at a URL, and presign plus finalize, when the client can PUT the raw bytes out of band. Inline upload suits small assets and clients that have neither a URL nor an out-of-band PUT.\n\nfetch takes { source_url (https), scope } and the relay downloads the URL itself behind an SSRF guard (https only, no private, loopback or metadata hosts, DNS pinned, redirects refused, size-capped and timed out), then runs the same byte-sniff, allowlist, size, quota and scan checks as any upload. It works on any storage backend. upload takes either `content_base64` (base64 bytes, no filesystem) or `file_path` (an absolute path read on the relay host, so it only applies when the file is local to the relay). presign plus finalize is token-free: presign with { mime, size, sha256, scope } returns { put_url, attachment_id }, the caller PUTs the raw bytes to put_url over plain HTTP out of band, then finalize with the attachment_id. At finalize the relay re-reads the stored bytes, sniffs the real type, and enforces the same allowlist, size, sha256, quota and scan checks, so a presign that misstates its mime is caught and never served inline. The presigned path requires the Azure storage backend; a filesystem self-host returns a clear not-supported error and fetch or inline upload apply there instead. download writes to an absolute out_path or returns base64. An upload is scoped to agent (the default, reusable) or app. mint_token returns a /b/<token> capability URL, shown once, that a browser can GET without the caller's API key.",
|
|
1308
1320
|
inputSchema: attachmentsShape,
|
|
1309
1321
|
// Consolidated tool: read actions (download/show/list/list_tokens) +
|
|
1310
1322
|
// mutating ones (upload/delete/mint_token/revoke_token). openWorld:true
|
|
@@ -1313,6 +1325,8 @@ export const TOOLS = [
|
|
|
1313
1325
|
annotations: {
|
|
1314
1326
|
title: "Manage Attachments",
|
|
1315
1327
|
readOnlyHint: false,
|
|
1328
|
+
// Destructive: `delete` removes an attachment and `revoke_token`
|
|
1329
|
+
// kills a live capability URL.
|
|
1316
1330
|
destructiveHint: true,
|
|
1317
1331
|
idempotentHint: false,
|
|
1318
1332
|
openWorldHint: true,
|
|
@@ -1491,13 +1505,14 @@ export const TOOLS = [
|
|
|
1491
1505
|
},
|
|
1492
1506
|
{
|
|
1493
1507
|
name: "taste",
|
|
1494
|
-
description: "
|
|
1508
|
+
description: "The agent's UI taste notes: a short freeform markdown document of presentation preferences gathered from human feedback, such as 'denser layout' or 'no rounded corners'. Reading it before generating or revising an app is what carries earlier feedback into new output. Actions: get returns the current document; set replaces it in whole, so it does not append; clear discards it. Scoped to presentation preferences rather than general storage.",
|
|
1495
1509
|
inputSchema: tasteShape,
|
|
1496
1510
|
// Consolidated tool: read action (get) + mutating ones (set replaces the
|
|
1497
1511
|
// doc, clear deletes it). Hint reflects the destructive action.
|
|
1498
1512
|
annotations: {
|
|
1499
1513
|
title: "Manage UI Taste Notes",
|
|
1500
1514
|
readOnlyHint: false,
|
|
1515
|
+
// Destructive: `clear` discards the stored notes.
|
|
1501
1516
|
destructiveHint: true,
|
|
1502
1517
|
idempotentHint: false,
|
|
1503
1518
|
openWorldHint: false,
|
|
@@ -1528,7 +1543,7 @@ export const TOOLS = [
|
|
|
1528
1543
|
},
|
|
1529
1544
|
{
|
|
1530
1545
|
name: "key",
|
|
1531
|
-
description: "
|
|
1546
|
+
description: "The calling agent's API key. Actions: list returns key info (agent_id, key_prefix, timestamps); mint creates a sibling API key for the caller's own agent identity with the same scope and ownership and returns its raw value once, which is how an MCP-driven agent hands a CLI or child process a working credential, and the raw value is not retrievable afterwards, the sibling appears in a later list made with it, and the owner can revoke it; revoke destroys the agent's own key, which stops working immediately and cannot be undone, so it requires confirm:true. The relay derives identity from the caller's token, so every action applies to the caller's own agent and mint cannot target another agent's id.",
|
|
1532
1547
|
inputSchema: keyShape,
|
|
1533
1548
|
// Consolidated tool: read action (list) + a mutating one (revoke
|
|
1534
1549
|
// self-destructs the agent's own key). Hint reflects the destructive
|
|
@@ -1536,6 +1551,8 @@ export const TOOLS = [
|
|
|
1536
1551
|
annotations: {
|
|
1537
1552
|
title: "Manage API Key",
|
|
1538
1553
|
readOnlyHint: false,
|
|
1554
|
+
// Destructive: `revoke` is irreversible and stops the key working
|
|
1555
|
+
// immediately (already gated behind confirm:true).
|
|
1539
1556
|
destructiveHint: true,
|
|
1540
1557
|
idempotentHint: false,
|
|
1541
1558
|
openWorldHint: false,
|
|
@@ -1571,14 +1588,15 @@ export const TOOLS = [
|
|
|
1571
1588
|
},
|
|
1572
1589
|
{
|
|
1573
1590
|
name: "feedback",
|
|
1574
|
-
description: "
|
|
1591
|
+
description: "Feedback to the relay operator. Actions: create records a bug, feature or note with a message and an optional app_id; list returns the agent's own submissions, newest first, paginated by `before`.",
|
|
1575
1592
|
inputSchema: feedbackShape,
|
|
1576
1593
|
// Consolidated tool: read action (list) + a side-effecting one (create
|
|
1577
1594
|
// submits feedback to the relay operator). Hint reflects the write action.
|
|
1578
1595
|
annotations: {
|
|
1579
1596
|
title: "Manage Feedback",
|
|
1580
1597
|
readOnlyHint: false,
|
|
1581
|
-
|
|
1598
|
+
// create + list only. Nothing can be edited or withdrawn.
|
|
1599
|
+
destructiveHint: false,
|
|
1582
1600
|
idempotentHint: false,
|
|
1583
1601
|
openWorldHint: false,
|
|
1584
1602
|
},
|
|
@@ -1617,7 +1635,7 @@ export const TOOLS = [
|
|
|
1617
1635
|
},
|
|
1618
1636
|
{
|
|
1619
1637
|
name: "agent",
|
|
1620
|
-
description: "Agent identity
|
|
1638
|
+
description: "Agent identity and binding. Actions: whoami returns the resolved relay URL, the active profile and whether a key is configured, with no network call and no secrets; claim binds this agent to a human using a one-shot claim code from their Settings UI, and is one-way; logout clears the locally saved key and profile but does not revoke it on the relay, which is what the `key` tool's revoke action does.",
|
|
1621
1639
|
inputSchema: agentShape,
|
|
1622
1640
|
// Consolidated tool: read action (whoami) + mutating ones (claim binds
|
|
1623
1641
|
// this agent to a human, logout clears the local profile). Hint reflects
|
|
@@ -1625,7 +1643,9 @@ export const TOOLS = [
|
|
|
1625
1643
|
annotations: {
|
|
1626
1644
|
title: "Manage Agent Identity",
|
|
1627
1645
|
readOnlyHint: false,
|
|
1628
|
-
|
|
1646
|
+
// whoami | claim | logout. `logout` ends the local binding and is
|
|
1647
|
+
// reversible by claiming again; no stored data is removed.
|
|
1648
|
+
destructiveHint: false,
|
|
1629
1649
|
idempotentHint: false,
|
|
1630
1650
|
openWorldHint: false,
|
|
1631
1651
|
},
|
|
@@ -1655,14 +1675,17 @@ export const TOOLS = [
|
|
|
1655
1675
|
},
|
|
1656
1676
|
{
|
|
1657
1677
|
name: "community",
|
|
1658
|
-
description: "
|
|
1678
|
+
description: "Publishing an app as a community template, installing a template, and, for relay operators, reviewing submissions. Actions: publish, get_config_contract, install, list_pending, get_submission, approve, reject, set_trust_level.\n\npublish captures a live app (html, manifest, the seed rows of its seedOnInstall collections, and listing metadata) into a pending template. It is installable by the returned direct link but is not listed in the public gallery until an operator approves it, and it requires a verified email and no more than a few pending submissions at once. Privacy consequence: an approved template's content and its captured seed rows become public to every platform user, so seed data in a published app must be example-only rather than real personal data. attest_example_only:true records that this was checked. A template may take a per-publisher `slug` (namespaced as <handle>/<slug>) and a semver `version` defaulting to 1.0.0, and a republish under the same slug must bump the version.\n\nget_config_contract reads what a template needs at install, meaning its settings collection and its ordered config and upload steps, by `ref`. install creates a fresh private copy of a template for the caller's owning human, passing answers as `config`, where a 'config' value is a string and an 'upload' value is a pre-uploaded attachment id from the attachments tool.\n\nThe review actions are limited to the relay's configured community reviewers: list_pending returns the queue; get_submission returns a submission's full content by snapshot_id; approve lists it in the gallery, where a re-publish supersedes the app's prior approved version; reject takes a required note that lands in the publisher's app feed.",
|
|
1659
1679
|
inputSchema: communityShape,
|
|
1660
1680
|
// Consolidated tool: read actions (list_pending/get_submission) + mutating
|
|
1661
1681
|
// ones (publish/approve/reject). Hint reflects the most-privileged action.
|
|
1662
1682
|
annotations: {
|
|
1663
1683
|
title: "Community Templates",
|
|
1664
1684
|
readOnlyHint: false,
|
|
1665
|
-
|
|
1685
|
+
// publish | install | the operator review actions. `approve`, `reject`
|
|
1686
|
+
// and `set_trust_level` move a submission between states; the
|
|
1687
|
+
// submission itself survives every one of them.
|
|
1688
|
+
destructiveHint: false,
|
|
1666
1689
|
idempotentHint: false,
|
|
1667
1690
|
openWorldHint: true,
|
|
1668
1691
|
},
|
|
@@ -1761,7 +1784,7 @@ export const TOOLS = [
|
|
|
1761
1784
|
},
|
|
1762
1785
|
{
|
|
1763
1786
|
name: "publisher",
|
|
1764
|
-
description: "
|
|
1787
|
+
description: "The caller's community publisher identity: the @-handle and public profile shown in the template gallery. Actions: get returns the profile, including the handle, whether it has been claimed, tenure, and the rating and template counters; claim sets the handle from a lowercase 3-to-32-character string and may be used only once, after which the handle is permanent, and it refuses a handle that is reserved or already taken; update changes display_name, bio or url at any time. claim and update require a verified email. An existing publisher may hold a provisional `maker-...` handle assigned automatically, which claim renames on its one allowed use.",
|
|
1765
1788
|
inputSchema: publisherShape,
|
|
1766
1789
|
// Consolidated tool: a read action (get) plus mutating ones (claim/update).
|
|
1767
1790
|
// claim is irreversible (the handle is permanent), so the hint reflects the
|
|
@@ -1769,7 +1792,8 @@ export const TOOLS = [
|
|
|
1769
1792
|
annotations: {
|
|
1770
1793
|
title: "Publisher Profile",
|
|
1771
1794
|
readOnlyHint: false,
|
|
1772
|
-
|
|
1795
|
+
// claim | get | update on the caller's own profile. No delete action.
|
|
1796
|
+
destructiveHint: false,
|
|
1773
1797
|
idempotentHint: false,
|
|
1774
1798
|
openWorldHint: true,
|
|
1775
1799
|
},
|
|
@@ -1810,7 +1834,7 @@ export const TOOLS = [
|
|
|
1810
1834
|
},
|
|
1811
1835
|
{
|
|
1812
1836
|
name: "review",
|
|
1813
|
-
description: "
|
|
1837
|
+
description: "Ratings and reviews of community templates, responses from a template's own publisher, and, for relay operators, moderation. Actions: create leaves a 1-to-5 star rating and an optional written body on a template the caller has installed, identifying it by `template` (\\\"<handle>/<slug>\\\") or by `handle` plus `slug`, and requires a verified email; each install yields exactly one review, and the aggregate carries across template versions. A body containing a link or a contact email is held automatically for a moderator before it appears. respond replies to a review of the caller's own template line (review_id plus response, or null to clear it), with one editable response per review. report flags a review for the relay's moderators (review_id plus reason) and is deduped per account. remove and unhold are limited to the relay's configured community reviewers: remove takes a review down and adjusts the rating aggregate, and unhold publishes a previously held review into the aggregate.",
|
|
1814
1838
|
inputSchema: reviewShape,
|
|
1815
1839
|
// Consolidated tool: a write action (create), publisher/reporter actions,
|
|
1816
1840
|
// and operator moderation (remove/unhold). Hint reflects remove, the most
|
|
@@ -1818,6 +1842,7 @@ export const TOOLS = [
|
|
|
1818
1842
|
annotations: {
|
|
1819
1843
|
title: "Community Reviews",
|
|
1820
1844
|
readOnlyHint: false,
|
|
1845
|
+
// Destructive: `remove` takes a review down.
|
|
1821
1846
|
destructiveHint: true,
|
|
1822
1847
|
idempotentHint: false,
|
|
1823
1848
|
openWorldHint: true,
|
|
@@ -1889,7 +1914,7 @@ export const TOOLS = [
|
|
|
1889
1914
|
},
|
|
1890
1915
|
{
|
|
1891
1916
|
name: "get_skill",
|
|
1892
|
-
description: "
|
|
1917
|
+
description: "The relay's SKILL.md, a generated guide to the Homespun workflow covering events versus records, the schema grammars and the poll loop. Needs no API key. Useful when working out how the other tools fit together, or to refresh a cached copy. Pass version_only:true to return just the relay's skill version string, which is enough to tell whether a cached copy is current.",
|
|
1893
1918
|
inputSchema: getSkillShape,
|
|
1894
1919
|
annotations: {
|
|
1895
1920
|
title: "Get Skill Guide",
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "1.6.
|
|
1
|
+
export declare const VERSION = "1.6.30";
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@homespunapps/mcp",
|
|
3
3
|
"mcpName": "dev.homespun/homespun",
|
|
4
|
-
"version": "1.6.
|
|
4
|
+
"version": "1.6.30",
|
|
5
5
|
"description": "Model Context Protocol (stdio) server for Homespun: lets any MCP client (Claude Desktop, Cursor, …) deploy a multi-user web app with hosting, auth, a shared database and permissions included.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@modelcontextprotocol/sdk": "^1.20.0",
|
|
49
|
-
"@homespunapps/core": "^1.6.
|
|
49
|
+
"@homespunapps/core": "^1.6.30",
|
|
50
50
|
"zod": "^4.4.3"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
package/server.json
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
"name": "dev.homespun/homespun",
|
|
4
4
|
"title": "Homespun",
|
|
5
5
|
"description": "Deploy a multi-user web app from your agent: hosting, auth, database, and permissions.",
|
|
6
|
-
"version": "1.6.
|
|
6
|
+
"version": "1.6.30",
|
|
7
7
|
"websiteUrl": "https://docs.homespun.dev",
|
|
8
8
|
"packages": [
|
|
9
9
|
{
|
|
10
10
|
"registryType": "npm",
|
|
11
11
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
12
12
|
"identifier": "@homespunapps/mcp",
|
|
13
|
-
"version": "1.6.
|
|
13
|
+
"version": "1.6.30",
|
|
14
14
|
"transport": {
|
|
15
15
|
"type": "stdio"
|
|
16
16
|
},
|