@awesomate/hosting-mcp 0.21.0 → 0.22.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/dist/index.js CHANGED
@@ -40196,6 +40196,41 @@ async function knowledgeSources(config3, args) {
40196
40196
  const page = await hubGet(config3, `/api/knowledge/sources${qs ? `?${qs}` : ""}`);
40197
40197
  return describeSourcePage(page);
40198
40198
  }
40199
+ if (args.action === "sync_rules") {
40200
+ const r = await hubGet(config3, "/api/knowledge/files-sync/rules");
40201
+ return { ...r, note: "Each rule keeps a File Manager folder synced into the knowledge base: files under path_prefix (matching include_globs, if any) are ingested with the rule visibility/tags/collection, re-ingested when they change, and handled per on_file_removed when they disappear. A worker sweeps every 15 min; uploads under an auto rule sync immediately; sync_run sweeps now." };
40202
+ }
40203
+ if (args.action === "sync_state") {
40204
+ const q = new URLSearchParams();
40205
+ if (args.ruleId !== void 0) q.set("rule_id", String(args.ruleId));
40206
+ if (args.status) q.set("status", args.status);
40207
+ if (args.limit !== void 0) q.set("limit", String(args.limit));
40208
+ const qs = q.toString();
40209
+ return await hubGet(config3, `/api/knowledge/files-sync/state${qs ? `?${qs}` : ""}`);
40210
+ }
40211
+ if (args.action === "sync_rule_create") {
40212
+ if (!args.pathPrefix) return { error: "invalid_request", note: "sync_rule_create needs pathPrefix (a File Manager folder such as 'public/reports')" };
40213
+ if (args.visibility === "public" && !args.confirm) {
40214
+ return { error: "confirmation_required", note: "A rule that makes every file in a folder PUBLIC is a standing publication. Explain that, then call again with confirm set to the account slug only after the user agrees in words." };
40215
+ }
40216
+ return await hubPost(config3, "/api/knowledge/files-sync/rules", {
40217
+ path_prefix: args.pathPrefix,
40218
+ ...args.includeGlobs?.length ? { include_globs: args.includeGlobs } : {},
40219
+ ...args.collectionIds?.[0] ? { collection_id: args.collectionIds[0] } : {},
40220
+ ...args.visibility ? { visibility: args.visibility } : {},
40221
+ ...args.tags?.length ? { tags: args.tags } : {},
40222
+ ...args.onFileRemoved ? { on_file_removed: args.onFileRemoved } : {},
40223
+ ...args.confirm ? { confirm: args.confirm } : {}
40224
+ });
40225
+ }
40226
+ if (args.action === "sync_rule_delete") {
40227
+ if (args.ruleId === void 0) return { error: "invalid_request", note: "sync_rule_delete needs ruleId (from sync_rules)" };
40228
+ return await hubDelete(config3, `/api/knowledge/files-sync/rules/${args.ruleId}`);
40229
+ }
40230
+ if (args.action === "sync_run") {
40231
+ const r = await hubPost(config3, "/api/knowledge/files-sync/run", {});
40232
+ return { ...r, note: 'Files ingested this run are queued on the platform; verify with awesomate_knowledge_sources {action:"jobs"} and a search for a phrase from the file, never with the run summary alone.' };
40233
+ }
40199
40234
  if (args.action === "search") {
40200
40235
  const q = new URLSearchParams();
40201
40236
  if (args.q) q.set("q", args.q);
@@ -41636,9 +41671,13 @@ server.registerTool(
41636
41671
  server.registerTool(
41637
41672
  "awesomate_knowledge_sources",
41638
41673
  {
41639
- description: "The knowledge base's content sources \u2014 the LIBRARY. action 'search' {q?, kind?, visibility?, tags?, collectionIds?, cursor?, limit?} \u2014 find sources by title/tag substring and metadata filters (instant, free; for CONTENT search use awesomate_knowledge_search); each row carries visibility (private|internal|public \u2014 who may retrieve it, ENFORCED), tags and collections. 'tag' {sourceId, tags} \u2014 REPLACE a source's free-form tags. 'set_visibility' {sourceId|sourceIds, visibility, confirm?} \u2014 change who may retrieve the source(s); 'public' is irreversible once fetched, so it needs the user's explicit agreement and their account slug as confirm. 'move' {sourceId|sourceIds, collectionIds?, removeCollectionIds?} \u2014 add to / remove from collections. 'list' \u2014 ONE page of sources, most recently ingested first (default 50, max 200 via limit): read `page.has_more`/`next_cursor` and pass cursor to continue \u2014 a page is never the whole library. 'summary' \u2014 exact whole-library counts {total, by_kind, chunks, indexed_chunks, failed_sources, failed_jobs_7d}: use THIS to say what the knowledge base contains, and if failed_jobs_7d > 0 say so \u2014 those ingests are missing from every other count. 'jobs' \u2014 ingest job statuses (optional status filter: queued|running|succeeded|failed). 'add' \u2014 ingest a public page {url} or a whole site {sitemap, since?}, optionally with visibility (default private), tags and collectionIds; ALWAYS get explicit approval first (ingest costs money and counts against quota), for a local FILE on the user's machine use awesomate_knowledge_upload instead (it streams the file from disk; this tool takes URLs only). A pack_required response means the allowance is exhausted: NOTHING was purchased \u2014 present the pack price (1 credit = $100) and let the user buy from the hub if they want it. 'remove' {sourceId} \u2014 deletes the source AND its indexed content; explicit approval required.",
41674
+ description: "The knowledge base's content sources \u2014 the LIBRARY. action 'search' {q?, kind?, visibility?, tags?, collectionIds?, cursor?, limit?} \u2014 find sources by title/tag substring and metadata filters (instant, free; for CONTENT search use awesomate_knowledge_search); each row carries visibility (private|internal|public \u2014 who may retrieve it, ENFORCED), tags and collections. 'tag' {sourceId, tags} \u2014 REPLACE a source's free-form tags. 'set_visibility' {sourceId|sourceIds, visibility, confirm?} \u2014 change who may retrieve the source(s); 'public' is irreversible once fetched, so it needs the user's explicit agreement and their account slug as confirm. 'move' {sourceId|sourceIds, collectionIds?, removeCollectionIds?} \u2014 add to / remove from collections. 'sync_rules' / 'sync_rule_create' {pathPrefix, includeGlobs?, visibility?, tags?, collectionIds?, onFileRemoved?} / 'sync_rule_delete' {ruleId} / 'sync_run' / 'sync_state' \u2014 keep a folder of the account's File Manager (their n8n file system: public/, private/, temp/) synced into the knowledge base, so files their workflows write become searchable; a public rule needs confirm. 'list' \u2014 ONE page of sources, most recently ingested first (default 50, max 200 via limit): read `page.has_more`/`next_cursor` and pass cursor to continue \u2014 a page is never the whole library. 'summary' \u2014 exact whole-library counts {total, by_kind, chunks, indexed_chunks, failed_sources, failed_jobs_7d}: use THIS to say what the knowledge base contains, and if failed_jobs_7d > 0 say so \u2014 those ingests are missing from every other count. 'jobs' \u2014 ingest job statuses (optional status filter: queued|running|succeeded|failed). 'add' \u2014 ingest a public page {url} or a whole site {sitemap, since?}, optionally with visibility (default private), tags and collectionIds; ALWAYS get explicit approval first (ingest costs money and counts against quota), for a local FILE on the user's machine use awesomate_knowledge_upload instead (it streams the file from disk; this tool takes URLs only). A pack_required response means the allowance is exhausted: NOTHING was purchased \u2014 present the pack price (1 credit = $100) and let the user buy from the hub if they want it. 'remove' {sourceId} \u2014 deletes the source AND its indexed content; explicit approval required.",
41640
41675
  inputSchema: {
41641
- action: external_exports.enum(["list", "summary", "add", "remove", "jobs", "search", "tag", "set_visibility", "move"]),
41676
+ action: external_exports.enum(["list", "summary", "add", "remove", "jobs", "search", "tag", "set_visibility", "move", "sync_rules", "sync_rule_create", "sync_rule_delete", "sync_run", "sync_state"]),
41677
+ pathPrefix: external_exports.string().max(512).optional().describe("sync_rule_create: a File Manager folder to keep synced, e.g. 'public/reports'"),
41678
+ includeGlobs: external_exports.array(external_exports.string().max(120)).max(20).optional().describe("sync_rule_create: only files matching these globs (relative to the folder), e.g. ['**/*.pdf']"),
41679
+ onFileRemoved: external_exports.enum(["keep", "demote_to_private", "delete"]).optional().describe("sync_rule_create: what happens to the knowledge source when the file is removed (default demote_to_private for internal/public rules, keep for private)"),
41680
+ ruleId: external_exports.number().int().optional().describe("sync_rule_delete / sync_state: rule id from sync_rules"),
41642
41681
  q: external_exports.string().max(100).optional().describe("search: title/tag substring"),
41643
41682
  kind: external_exports.string().max(32).optional().describe("search: source kind filter (web, document, video, audio, image, book, dataset)"),
41644
41683
  visibility: external_exports.enum(["private", "internal", "public"]).optional().describe("add: the audience the new source is cleared for (default private); set_visibility: the level to apply; search: filter"),
@@ -41656,10 +41695,10 @@ server.registerTool(
41656
41695
  limit: external_exports.number().int().min(1).max(200).optional().describe("list only: page size (default 50, max 200)")
41657
41696
  }
41658
41697
  },
41659
- async ({ action, url, sitemap, since, sourceId, status, cursor, limit, q, kind, visibility, tags, collectionIds, removeCollectionIds, sourceIds, confirm }) => {
41698
+ async ({ action, url, sitemap, since, sourceId, status, cursor, limit, q, kind, visibility, tags, collectionIds, removeCollectionIds, sourceIds, confirm, pathPrefix, includeGlobs, onFileRemoved, ruleId }) => {
41660
41699
  try {
41661
41700
  return knowledgeResult(
41662
- await knowledgeSources(requireConfig(), { action, url, sitemap, since, sourceId, status, cursor, limit, q, kind, visibility, tags, collectionIds, removeCollectionIds, sourceIds, confirm })
41701
+ await knowledgeSources(requireConfig(), { action, url, sitemap, since, sourceId, status, cursor, limit, q, kind, visibility, tags, collectionIds, removeCollectionIds, sourceIds, confirm, pathPrefix, includeGlobs, onFileRemoved, ruleId })
41663
41702
  );
41664
41703
  } catch (err) {
41665
41704
  return knowledgeError(err);
@@ -42097,15 +42136,26 @@ server.registerTool(
42097
42136
  {
42098
42137
  description: "Ingest ONE file from the user's own computer into their Knowledge Base (Pro+). Pass a LOCAL PATH \u2014 this server runs on their machine and streams the file to the hub itself, so the file contents never pass through the conversation. Handles documents (pdf, md, txt), business data (csv, tsv, xls, xlsx, json), audio and video (transcribed), and images. Word/PowerPoint/RTF/EPUB files are NOT parseable yet \u2014 the tool refuses them with the workaround (export to PDF, or save as .md/.txt). Max 100 MB per file; bigger media goes through the hub's Knowledge \u2192 Sources page. INGESTING COSTS MONEY and counts against the monthly allowance, so ALWAYS get explicit approval for the specific file(s) first and say what it will consume. For several files, call once per file and report progress \u2014 do not loop silently. Returns a job with its live status; poll awesomate_knowledge_sources {action:'jobs'} until it succeeds (a duplicate upload replays the earlier job \u2014 a response already reading succeeded needs no polling), then probe the content with awesomate_knowledge_ask before building anything on it. A pack_required response means the allowance is exhausted: nothing was ingested and nothing was purchased.",
42099
42138
  inputSchema: {
42100
- path: external_exports.string().min(1).max(4096).describe("Path to the file on the user's machine (~ is expanded)"),
42101
- title: external_exports.string().max(300).optional().describe("Display title; defaults to the filename"),
42139
+ path: external_exports.string().min(1).max(4096).optional().describe("Path to the file on the user's machine (~ is expanded). Omit when using fromFilesPath."),
42140
+ fromFilesPath: external_exports.string().max(1024).optional().describe("Instead of a local file: a path in the account's File Manager (their n8n file system), relative to files/, e.g. 'public/reports/weekly.md'. The hub streams it from their storage \u2014 nothing leaves this machine."),
42141
+ title: external_exports.string().max(300).optional().describe("Display title; defaults to the filename (local uploads only)"),
42102
42142
  visibility: external_exports.enum(["private", "internal", "public"]).optional().describe("Who may retrieve this source (default private). public = customers and public chatbots; irreversible once fetched \u2014 ask first."),
42103
42143
  tags: external_exports.array(external_exports.string().max(64)).max(64).optional().describe("Free-form tags for the new source"),
42104
42144
  collectionIds: external_exports.array(external_exports.string().max(64)).max(16).optional().describe("Put the new source in these collections (awesomate_knowledge_collections list)")
42105
42145
  }
42106
42146
  },
42107
- async ({ path: rawPath, title, visibility, tags, collectionIds }) => {
42147
+ async ({ path: rawPath, fromFilesPath, title, visibility, tags, collectionIds }) => {
42108
42148
  try {
42149
+ if (fromFilesPath) {
42150
+ const out = await hubPost(requireConfig(), "/api/knowledge/sources/from-files", {
42151
+ path: fromFilesPath,
42152
+ ...visibility ? { visibility } : {},
42153
+ ...tags?.length ? { tags } : {},
42154
+ ...collectionIds?.length ? { collection_ids: collectionIds } : {}
42155
+ });
42156
+ return knowledgeResult({ ...out, note: 'Queued from the File Manager. Poll awesomate_knowledge_sources {action:"jobs"} until succeeded, then verify with a search for a phrase from the file.' });
42157
+ }
42158
+ if (!rawPath) return errorResult(new Error("Give either path (a local file) or fromFilesPath (a File Manager path)."));
42109
42159
  const { statSync, existsSync: existsSync3 } = await import("node:fs");
42110
42160
  const { resolve: resolve2, basename, extname } = await import("node:path");
42111
42161
  const expanded = rawPath.startsWith("~") ? join3(homedir3(), rawPath.slice(1).replace(/^[/\\]/, "")) : rawPath;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awesomate/hosting-mcp",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "Awesomate MCP server — lets Claude manage your Awesomate WordPress hosting, plan, limits, n8n automations, and build Node/static apps + databases",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -60,6 +60,7 @@ platform's answer beats anything you remember.
60
60
  | Enable the knowledge base (idempotent; 202 = keep polling status) | `awesomate_knowledge_provision` |
61
61
  | The LIBRARY: search by title/tag/collection/visibility, list, add url·sitemap (with visibility, tags, collections), tag, set visibility (public needs the slug typed), move between collections, remove, ingest jobs | `awesomate_knowledge_sources` |
62
62
  | Collections — named sets of sources a chatbot is scoped to: list / create / update / delete / add / remove members | `awesomate_knowledge_collections` |
63
+ | Keep a File Manager folder (their n8n file system) synced into the knowledge base: `sync_rules` / `sync_rule_create` / `sync_rule_delete` / `sync_run` / `sync_state` on the sources tool; one file at a time via `awesomate_knowledge_upload {fromFilesPath}` | `awesomate_knowledge_sources`, `awesomate_knowledge_upload` |
63
64
  | Instant search with facet counts (find WHAT is in there: moments, pages, datasets; free) | `awesomate_knowledge_search` |
64
65
  | Ask a question → verified answer + numbered sources (accepts the same facet `filters` to ask within a slice) | `awesomate_knowledge_ask` |
65
66
  | Agent persona / fallback message / model tier — get & set (the single workspace default) | `awesomate_knowledge_agent` |
@@ -37,6 +37,15 @@ contents never pass through the conversation and a 100 MB PDF costs no context.
37
37
  - A folder path is rejected on purpose — list it, agree the files, then upload.
38
38
  - Public URLs and whole sitemaps stay on `awesomate_knowledge_sources`
39
39
  `{action:'add'}`. Use that for their website; use upload for their disk.
40
+ - **Files already in their File Manager** (the n8n file system at hub
41
+ Files — `public/`, `private/`, `temp/`, where their workflows write
42
+ outputs): `awesomate_knowledge_upload {fromFilesPath: 'public/reports/x.md'}`
43
+ for one file, or a folder rule with `awesomate_knowledge_sources
44
+ {action:'sync_rule_create', pathPrefix, visibility, collectionIds}` so
45
+ every file a workflow drops there is ingested automatically (uploads sync
46
+ at once, everything else on a 15-minute sweep). A `public/` folder being
47
+ web-served does NOT make its knowledge sources public — say which
48
+ visibility the rule should use, default private.
40
49
  - **What parses:** pdf, md, txt (documents); csv, tsv, xls, xlsx, json (business data);
41
50
  audio, video, images. Word/PowerPoint/RTF/EPUB/HTML files are refused with a
42
51
  workaround — export to PDF or save as .md/.txt; a web page goes in by URL.