@neopress/mcp 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -1
- package/dist/bin.cjs +483 -27
- package/dist/http-bin.cjs +483 -27
- package/dist/index.d.ts +163 -4
- package/dist/index.js +483 -27
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -252,6 +252,12 @@ var FormsEndpoint = class {
|
|
|
252
252
|
async deleteResponse(formId, responseId) {
|
|
253
253
|
await this.client.delete(`${this.basePath}/${formId}/responses/${responseId}`);
|
|
254
254
|
}
|
|
255
|
+
async getResponse(formId, responseId) {
|
|
256
|
+
return (await this.client.get(`${this.basePath}/${formId}/responses/${responseId}`)).data;
|
|
257
|
+
}
|
|
258
|
+
async markResponseRead(formId, responseId) {
|
|
259
|
+
return (await this.client.patch(`${this.basePath}/${formId}/responses/${responseId}`, { read: true })).data;
|
|
260
|
+
}
|
|
255
261
|
};
|
|
256
262
|
//#endregion
|
|
257
263
|
//#region ../sdk/src/endpoints/assets.ts
|
|
@@ -399,8 +405,14 @@ var PublishEndpoint = class {
|
|
|
399
405
|
async preview() {
|
|
400
406
|
return (await this.client.get(`${this.client.siteBasePath}/publish`)).data;
|
|
401
407
|
}
|
|
402
|
-
async site() {
|
|
403
|
-
return (await this.client.post(`${this.client.siteBasePath}/publish
|
|
408
|
+
async site(selection) {
|
|
409
|
+
return (await this.client.post(`${this.client.siteBasePath}/publish`, selection ? { selection } : void 0)).data;
|
|
410
|
+
}
|
|
411
|
+
async unpublishPages(pageIds) {
|
|
412
|
+
return (await this.client.patch(`${this.client.siteBasePath}/publish`, { pageIds })).data;
|
|
413
|
+
}
|
|
414
|
+
async undeploy() {
|
|
415
|
+
return (await this.client.delete(`${this.client.siteBasePath}/publish`)).data;
|
|
404
416
|
}
|
|
405
417
|
};
|
|
406
418
|
//#endregion
|
|
@@ -568,6 +580,14 @@ var AnalyticsFunnelsEndpoint = class {
|
|
|
568
580
|
async delete(funnelId) {
|
|
569
581
|
await this.client.delete(`${this.basePath}/${funnelId}`);
|
|
570
582
|
}
|
|
583
|
+
async results(funnelId, params) {
|
|
584
|
+
const query = new URLSearchParams();
|
|
585
|
+
if (params?.dateFrom) query.set("dateFrom", params.dateFrom);
|
|
586
|
+
if (params?.dateTo) query.set("dateTo", params.dateTo);
|
|
587
|
+
if (params?.timezone) query.set("timezone", params.timezone);
|
|
588
|
+
const suffix = query.size > 0 ? `?${query.toString()}` : "";
|
|
589
|
+
return (await this.client.get(`${this.basePath}/${funnelId}/results${suffix}`)).data;
|
|
590
|
+
}
|
|
571
591
|
};
|
|
572
592
|
//#endregion
|
|
573
593
|
//#region ../sdk/src/endpoints/templates.ts
|
|
@@ -696,6 +716,122 @@ var LogosEndpoint = class {
|
|
|
696
716
|
}
|
|
697
717
|
};
|
|
698
718
|
//#endregion
|
|
719
|
+
//#region ../sdk/src/endpoints/domains.ts
|
|
720
|
+
var DomainsEndpoint = class {
|
|
721
|
+
client;
|
|
722
|
+
constructor(client) {
|
|
723
|
+
this.client = client;
|
|
724
|
+
}
|
|
725
|
+
get basePath() {
|
|
726
|
+
return `${this.client.siteBasePath}/domains`;
|
|
727
|
+
}
|
|
728
|
+
async status() {
|
|
729
|
+
return (await this.client.get(this.basePath)).data;
|
|
730
|
+
}
|
|
731
|
+
async connect(domain) {
|
|
732
|
+
return (await this.client.post(this.basePath, { domain })).data;
|
|
733
|
+
}
|
|
734
|
+
async refresh() {
|
|
735
|
+
return (await this.client.patch(this.basePath, {})).data;
|
|
736
|
+
}
|
|
737
|
+
async remove(domain) {
|
|
738
|
+
return (await this.client.delete(this.basePath, { domain })).data;
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
//#endregion
|
|
742
|
+
//#region ../sdk/src/endpoints/search-console.ts
|
|
743
|
+
var SearchConsoleConnectionEndpoint = class {
|
|
744
|
+
client;
|
|
745
|
+
constructor(client) {
|
|
746
|
+
this.client = client;
|
|
747
|
+
}
|
|
748
|
+
get basePath() {
|
|
749
|
+
return `${this.client.siteBasePath}/search-console`;
|
|
750
|
+
}
|
|
751
|
+
async status() {
|
|
752
|
+
return (await this.client.get(this.basePath)).data;
|
|
753
|
+
}
|
|
754
|
+
async authorize(locale) {
|
|
755
|
+
return (await this.client.post(this.basePath, locale ? { locale } : {})).data;
|
|
756
|
+
}
|
|
757
|
+
async disconnect() {
|
|
758
|
+
return (await this.client.delete(this.basePath)).data;
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
//#endregion
|
|
762
|
+
//#region ../sdk/src/endpoints/billing.ts
|
|
763
|
+
var BillingEndpoint = class {
|
|
764
|
+
client;
|
|
765
|
+
constructor(client) {
|
|
766
|
+
this.client = client;
|
|
767
|
+
}
|
|
768
|
+
get basePath() {
|
|
769
|
+
return `${this.client.siteBasePath}/billing`;
|
|
770
|
+
}
|
|
771
|
+
async status() {
|
|
772
|
+
return (await this.client.get(this.basePath)).data;
|
|
773
|
+
}
|
|
774
|
+
async checkout(plan) {
|
|
775
|
+
return (await this.client.post(`${this.basePath}/checkout`, { plan })).data;
|
|
776
|
+
}
|
|
777
|
+
async portal() {
|
|
778
|
+
return (await this.client.post(`${this.basePath}/portal`)).data;
|
|
779
|
+
}
|
|
780
|
+
async cancel() {
|
|
781
|
+
return (await this.client.post(`${this.basePath}/subscription/cancel`)).data;
|
|
782
|
+
}
|
|
783
|
+
async resume() {
|
|
784
|
+
return (await this.client.post(`${this.basePath}/subscription/resume`)).data;
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
//#endregion
|
|
788
|
+
//#region ../sdk/src/endpoints/team.ts
|
|
789
|
+
var TeamEndpoint = class {
|
|
790
|
+
client;
|
|
791
|
+
constructor(client) {
|
|
792
|
+
this.client = client;
|
|
793
|
+
}
|
|
794
|
+
get basePath() {
|
|
795
|
+
return `${this.client.siteBasePath}/team`;
|
|
796
|
+
}
|
|
797
|
+
async list() {
|
|
798
|
+
return (await this.client.get(this.basePath)).data;
|
|
799
|
+
}
|
|
800
|
+
async invite(input) {
|
|
801
|
+
return (await this.client.post(this.basePath, input)).data;
|
|
802
|
+
}
|
|
803
|
+
async updateRole(profileId, role) {
|
|
804
|
+
return (await this.client.patch(`${this.basePath}/${profileId}`, { role })).data;
|
|
805
|
+
}
|
|
806
|
+
async remove(profileId) {
|
|
807
|
+
return (await this.client.delete(`${this.basePath}/${profileId}`)).data;
|
|
808
|
+
}
|
|
809
|
+
async transferOwnership(profileId) {
|
|
810
|
+
return (await this.client.post(`${this.basePath}/ownership`, { profileId })).data;
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
//#endregion
|
|
814
|
+
//#region ../sdk/src/endpoints/history.ts
|
|
815
|
+
var HistoryEndpoint = class {
|
|
816
|
+
client;
|
|
817
|
+
constructor(client) {
|
|
818
|
+
this.client = client;
|
|
819
|
+
}
|
|
820
|
+
get basePath() {
|
|
821
|
+
return `${this.client.siteBasePath}/history/snapshots`;
|
|
822
|
+
}
|
|
823
|
+
async list(limit) {
|
|
824
|
+
const query = limit === void 0 ? "" : `?limit=${encodeURIComponent(String(limit))}`;
|
|
825
|
+
return (await this.client.get(`${this.basePath}${query}`)).data;
|
|
826
|
+
}
|
|
827
|
+
async get(snapshotId) {
|
|
828
|
+
return (await this.client.get(`${this.basePath}/${snapshotId}`)).data;
|
|
829
|
+
}
|
|
830
|
+
async restore(snapshotId) {
|
|
831
|
+
return (await this.client.post(`${this.basePath}/${snapshotId}/restore`)).data;
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
//#endregion
|
|
699
835
|
//#region ../sdk/src/client.ts
|
|
700
836
|
/**
|
|
701
837
|
* @neopress/sdk — API Client
|
|
@@ -720,6 +856,11 @@ var NeopressClient = class {
|
|
|
720
856
|
templates;
|
|
721
857
|
headshots;
|
|
722
858
|
logos;
|
|
859
|
+
domains;
|
|
860
|
+
searchConsole;
|
|
861
|
+
billing;
|
|
862
|
+
team;
|
|
863
|
+
history;
|
|
723
864
|
constructor(options) {
|
|
724
865
|
this.baseUrl = (options.baseUrl || "https://app.neopress.ai").replace(/\/$/, "");
|
|
725
866
|
this.accessToken = options.accessToken || "";
|
|
@@ -738,6 +879,11 @@ var NeopressClient = class {
|
|
|
738
879
|
this.templates = new TemplatesEndpoint(this);
|
|
739
880
|
this.headshots = new HeadshotsEndpoint(this);
|
|
740
881
|
this.logos = new LogosEndpoint(this);
|
|
882
|
+
this.domains = new DomainsEndpoint(this);
|
|
883
|
+
this.searchConsole = new SearchConsoleConnectionEndpoint(this);
|
|
884
|
+
this.billing = new BillingEndpoint(this);
|
|
885
|
+
this.team = new TeamEndpoint(this);
|
|
886
|
+
this.history = new HistoryEndpoint(this);
|
|
741
887
|
}
|
|
742
888
|
get siteBasePath() {
|
|
743
889
|
return `/api/v1/sites/${this.siteId}`;
|
|
@@ -787,8 +933,8 @@ var NeopressClient = class {
|
|
|
787
933
|
async patch(path, body) {
|
|
788
934
|
return this.request("PATCH", path, body);
|
|
789
935
|
}
|
|
790
|
-
async delete(path) {
|
|
791
|
-
return this.request("DELETE", path);
|
|
936
|
+
async delete(path, body) {
|
|
937
|
+
return this.request("DELETE", path, body);
|
|
792
938
|
}
|
|
793
939
|
};
|
|
794
940
|
//#endregion
|
|
@@ -923,9 +1069,8 @@ Use these rules before generating pages, collection schemas, entries, forms, or
|
|
|
923
1069
|
|
|
924
1070
|
## Operating boundary
|
|
925
1071
|
|
|
926
|
-
-
|
|
927
|
-
-
|
|
928
|
-
- MCP is available as local stdio and remote Streamable HTTP over the first-party SDK/API.
|
|
1072
|
+
- Connect the remote MCP server and sign in with your Neopress account through OAuth.
|
|
1073
|
+
- MCP is available on Launch and above. Your site role controls which actions you can perform.
|
|
929
1074
|
- MCP is a Neopress contract adapter, not a reference crawler or managed page generator.
|
|
930
1075
|
- The host coding agent should perform \`r.jina.ai\` markdown fetches, browser screenshots, DOM/CSS/SVG/background-image extraction, reference analysis, and TSX authoring with its own tools and tokens.
|
|
931
1076
|
- Use MCP to read/write Neopress resources, upload or register assets, compile, publish, and verify. Do not expect MCP to spend Neopress server-side LLM tokens for reference analysis or page generation.
|
|
@@ -939,13 +1084,15 @@ Use these rules before generating pages, collection schemas, entries, forms, or
|
|
|
939
1084
|
|
|
940
1085
|
## Cache
|
|
941
1086
|
|
|
942
|
-
- Site publish invalidates site/layout/collection reader cache tags in the
|
|
1087
|
+
- Site publish invalidates site/layout/collection reader cache tags in the environment connected to MCP.
|
|
943
1088
|
- Entry publish/unpublish invalidates entry reader cache when production visibility changes.
|
|
944
|
-
- A localhost publish does not invalidate production reader cache. For production validation, publish through the production
|
|
1089
|
+
- A localhost publish does not invalidate production reader cache. For production validation, publish through the production MCP server and verify the live URL.
|
|
945
1090
|
|
|
946
1091
|
## Analytics and autopilot
|
|
947
1092
|
|
|
948
|
-
- Analytics tools are
|
|
1093
|
+
- Analytics result tools are OAuth-authenticated read queries for traffic, forms, AI crawler reach, Search Console, and tenant-owned saved funnels. Event/funnel definitions and the Search Console connection have separate mutation tools.
|
|
1094
|
+
- The API re-checks site role, work access, and plan entitlements on every MCP call. MCP starts at Launch; deep analytics such as saved funnel results requires Growth. Billing is Owner-only and team/domain management is Owner/Admin.
|
|
1095
|
+
- Consequential public, account, billing, team, deletion, and history-restore tools carry destructive/open-world annotations for host approval. OAuth consent, DNS-provider credentials, checkout, and billing-portal steps still require user interaction.
|
|
949
1096
|
- Generated page TSX must not call analytics APIs, Tinybird, Search Console, Supabase, or server resources directly.
|
|
950
1097
|
- Search Console can return connected=false. Do not claim query-level SEO evidence unless connected data is returned.
|
|
951
1098
|
- Analytics may justify the next draft change, but mutations still follow the compile, publish, entry publish, form publish, and production verification contracts.
|
|
@@ -954,7 +1101,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
|
|
|
954
1101
|
|
|
955
1102
|
- Layout owns header, footer, global CSS, and 404. Page TSX starts at page content.
|
|
956
1103
|
- Generated page TSX is sandboxed. Do not import Supabase, create API clients, read env vars, use filesystem/process APIs, or assume arbitrary npm packages.
|
|
957
|
-
- Use allowed runtime packages only: React/Next basics, react-dom (createPortal), shadcn UI imports, lucide-react, @base-ui/react/drawer, @base-ui/react/dialog, @base-ui/react/accordion, @base-ui/react/switch, @base-ui/react/tabs, @base-ui/react/select, @neopress/youtube, @neopress/map, clsx, class-variance-authority, tailwind-merge, motion/react (never \`framer-motion\` — old package name, not on the allowlist), motion-plus/react (Motion+ premium components: Ticker, Carousel, Cursor, AnimateNumber, AnimateText, Typewriter, ScrambleText, Curtains), @paper-design/shaders-react, gsap (including \`gsap/ScrollTrigger\`, driven via \`@gsap/react\`'s \`useGSAP\`), react-hook-form, zod, @hookform/resolvers, @hookform/resolvers/zod, @neopress/content, @neopress/routing, @neopress/i18n, and @neopress/forms.
|
|
1104
|
+
- Use allowed runtime packages only: React/Next basics, react-dom (createPortal), shadcn UI imports, lucide-react, @base-ui/react/drawer, @base-ui/react/dialog, @base-ui/react/accordion, @base-ui/react/switch, @base-ui/react/tabs, @base-ui/react/select, @neopress/youtube, @neopress/map, clsx, class-variance-authority, tailwind-merge, motion/react (never \`framer-motion\` — old package name, not on the allowlist), motion-plus/react (Motion+ premium components: Ticker, Carousel, Cursor, AnimateNumber, AnimateText, Typewriter, ScrambleText, Curtains), @paper-design/shaders-react, gsap (including \`gsap/ScrollTrigger\`, driven via \`@gsap/react\`'s \`useGSAP\`), react-hook-form, zod, @hookform/resolvers, @hookform/resolvers/zod, @neopress/content, @neopress/routing, @neopress/i18n, @neopress/responsive (MobileOnly with deferred desktop/mobile callbacks), and @neopress/forms.
|
|
958
1105
|
- For dates, render an existing \`displayDate\` field directly when available. For raw timestamps, use \`Intl.DateTimeFormat\` or \`Date#toLocaleDateString\` with an explicit locale and \`timeZone\` so server rendering and hydration agree; use the site's required zone, or \`UTC\` when none is specified.
|
|
959
1106
|
- @base-ui/react/select is an accessible listbox/dropdown (replaces a native \`<select>\`, whose popup is unstyled OS chrome). Compose its parts directly in page TSX; a \`<Select.Item value>\` is a string or the documented \`null\` sentinel (unlike Radix, an empty string is not banned); the \`Select.Popup\` portals to \`document.body\`, so give it an explicit z-index and an opaque background; match the trigger width with \`min-w-[var(--anchor-width)]\` (from \`Select.Positioner\`), cap the list with \`max-h-[var(--available-height)]\`, and set \`alignItemWithTrigger={false}\` for standard below-trigger placement. @base-ui/react/drawer is the gesture mobile sheet; @base-ui/react/dialog the non-gesture modal — both portal to \`document.body\`, need an opaque Popup background + z-index, and take \`modal\` for focus-trap.
|
|
960
1107
|
- react-dom is for \`createPortal\` — portal full-viewport overlays (mobile drawer, modal) to \`document.body\` so a \`backdrop-filter\`/\`transform\` ancestor can't trap their \`position: fixed\` inside its box. ALWAYS render the portal behind an open-state guard (\`{open && createPortal(…, document.body)}\`): an unguarded \`document\` reference throws during SSR.
|
|
@@ -976,7 +1123,9 @@ Use these rules before generating pages, collection schemas, entries, forms, or
|
|
|
976
1123
|
- \`queryConfig\` is stored in page \`draftMeta.queryConfig\`.
|
|
977
1124
|
- Query labels become React props. Entry query results are flattened, so use \`post.body\` instead of \`post.data.body\`.
|
|
978
1125
|
- A query may include \`collectionWindow\` on an \`entries\` query for a dynamic detail route. Its label receives \`{ before, after, items }\`; each is a flattened-entry array around the current entry, and \`items\` combines both directions. Windows use \`published_at DESC, id DESC\`, allow 0–20 entries per direction, and may only declare that exact order. Use the exact configured label, never a guessed prop name. Optional \`matchFields\` compare raw anchor-snapshot fields only when the source field has a value.
|
|
979
|
-
- Initial CMS data arrives through those injected query props. \`entryClient\`, when injected in reader/preview for a site handle, is only a client-side auxiliary for load-more/filter/get/create interactions after the initial render; do not use it for initial render or server data loading.
|
|
1126
|
+
- Initial CMS data arrives through those injected query props. \`entryClient\`, when injected in reader/preview for a site handle, is only a client-side auxiliary for load-more/filter/get/create interactions after the initial render; do not use it for initial render or server data loading. Its entries come back flattened like injected props, ordered \`published_at DESC, id DESC\`.
|
|
1127
|
+
- Server-side binding is the default because injected props are server-rendered and crawlable; \`entryClient\` is for after-hydration needs only (large-collection load-more, a read that depends on visitor input such as search text or a chosen filter, or an explicit client-side request).
|
|
1128
|
+
- Load-more pagination: give the list query a \`limit\` (first page injected server-side), then append \`entryClient.more(propLabel, { offset: shown.length, filters? })\` — the server re-runs that page's stored binding query from the offset, so the page restates nothing; \`filters\` is equality on scalar schema fields (\`{ category: "TECH" }\`), applied to the same published data. \`entryClient.list({ collectionId, offset, limit, filters? })\` is only for reads whose query depends on visitor input or that are too large to inject; a light, fixed set revealed on click is a bound query instead. Judge "light" by what the query injects into the page, not by how much the UI shows: a query without a \`limit\` ships every entry with every field. Without a \`limit\` a list query injects every entry, so paginate by slicing the prop instead.
|
|
980
1129
|
- Use numeric \`collection_id\` filters. Runtime controls site, status, locale, deleted state, and published snapshots.
|
|
981
1130
|
|
|
982
1131
|
## Collections and entries
|
|
@@ -990,7 +1139,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
|
|
|
990
1139
|
|
|
991
1140
|
- Reference fields require a schema field with \`type: "references"\` and target \`collection_id\`.
|
|
992
1141
|
- Links live in \`entry_references\`, not only in raw entry \`data\`.
|
|
993
|
-
- \`includeReferences\` fetches arrays keyed by the includeReferences alias or field key, and parent entry \`id\` must be selected. With an alias, the alias prop remains an array of referenced entries. Without an alias, if the field key matches a raw numeric reference field in \`entry.data\`, flattening unwraps that array to one
|
|
1142
|
+
- \`includeReferences\` fetches arrays keyed by the includeReferences alias or field key, and parent entry \`id\` must be selected. With an alias, the alias prop remains an array of referenced entries. Without an alias, if the field key matches a raw numeric reference field in \`entry.data\`, flattening unwraps that array to one object or null; references linked only through \`entry_references\` stay arrays. Every referenced entry is flattened like the parent (\`ref.<fieldId>\`; \`ref.data\` kept for backward compatibility), one level deep.
|
|
994
1143
|
- After changing references, publish the source entry again.
|
|
995
1144
|
|
|
996
1145
|
## Forms
|
|
@@ -1003,7 +1152,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
|
|
|
1003
1152
|
## Unsupported visitor features
|
|
1004
1153
|
|
|
1005
1154
|
Generated Neopress pages do not support visitor login/accounts, member areas, carts, checkout, payments, subscriptions, or order management.`;
|
|
1006
|
-
const SERVER_INSTRUCTIONS = `Use Neopress MCP tools to manage a selected Neopress site through
|
|
1155
|
+
const SERVER_INSTRUCTIONS = `Use Neopress MCP tools to manage a selected Neopress site through an authenticated MCP connection.
|
|
1007
1156
|
|
|
1008
1157
|
Before generating TSX or schema-backed pages, call neopress_get_runtime_contract or read neopress://runtime-contract.
|
|
1009
1158
|
Use numeric IDs returned by tools. Publish entries separately from site publish. Use read-only analytics tools before autopilot recommendations. Verify production URLs after production publish.
|
|
@@ -1286,6 +1435,7 @@ const READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
|
1286
1435
|
"neopress_forms_list",
|
|
1287
1436
|
"neopress_form_get",
|
|
1288
1437
|
"neopress_form_responses_list",
|
|
1438
|
+
"neopress_form_response_get",
|
|
1289
1439
|
"neopress_analytics_query",
|
|
1290
1440
|
"neopress_analytics_pageviews",
|
|
1291
1441
|
"neopress_analytics_summary",
|
|
@@ -1302,6 +1452,13 @@ const READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
|
1302
1452
|
"neopress_assets_list",
|
|
1303
1453
|
"neopress_asset_get",
|
|
1304
1454
|
"neopress_publish_preview",
|
|
1455
|
+
"neopress_domain_status",
|
|
1456
|
+
"neopress_search_console_connection_status",
|
|
1457
|
+
"neopress_billing_status",
|
|
1458
|
+
"neopress_team_list",
|
|
1459
|
+
"neopress_history_snapshots_list",
|
|
1460
|
+
"neopress_history_snapshot_get",
|
|
1461
|
+
"neopress_analytics_funnel_results",
|
|
1305
1462
|
"neopress_template_get"
|
|
1306
1463
|
]);
|
|
1307
1464
|
const DESTRUCTIVE_TOOLS = /* @__PURE__ */ new Set([
|
|
@@ -1327,15 +1484,48 @@ const DESTRUCTIVE_TOOLS = /* @__PURE__ */ new Set([
|
|
|
1327
1484
|
"neopress_analytics_event_delete",
|
|
1328
1485
|
"neopress_analytics_funnel_create",
|
|
1329
1486
|
"neopress_analytics_funnel_update",
|
|
1330
|
-
"neopress_analytics_funnel_delete"
|
|
1487
|
+
"neopress_analytics_funnel_delete",
|
|
1488
|
+
"neopress_domain_connect",
|
|
1489
|
+
"neopress_domain_remove",
|
|
1490
|
+
"neopress_search_console_disconnect",
|
|
1491
|
+
"neopress_billing_cancel",
|
|
1492
|
+
"neopress_team_member_update_role",
|
|
1493
|
+
"neopress_team_member_remove",
|
|
1494
|
+
"neopress_team_transfer_ownership",
|
|
1495
|
+
"neopress_form_response_delete",
|
|
1496
|
+
"neopress_history_snapshot_restore",
|
|
1497
|
+
"neopress_unpublish_pages",
|
|
1498
|
+
"neopress_undeploy_site"
|
|
1331
1499
|
]);
|
|
1332
|
-
const
|
|
1500
|
+
const OPEN_WORLD_TOOLS = /* @__PURE__ */ new Set([
|
|
1333
1501
|
"neopress_entry_publish",
|
|
1334
1502
|
"neopress_entry_unpublish",
|
|
1335
1503
|
"neopress_form_publish",
|
|
1336
|
-
"neopress_publish_site"
|
|
1504
|
+
"neopress_publish_site",
|
|
1505
|
+
"neopress_unpublish_pages",
|
|
1506
|
+
"neopress_undeploy_site",
|
|
1507
|
+
"neopress_domain_connect",
|
|
1508
|
+
"neopress_domain_refresh",
|
|
1509
|
+
"neopress_domain_remove",
|
|
1510
|
+
"neopress_search_console_authorize",
|
|
1511
|
+
"neopress_search_console_disconnect",
|
|
1512
|
+
"neopress_billing_checkout",
|
|
1513
|
+
"neopress_billing_portal",
|
|
1514
|
+
"neopress_billing_cancel",
|
|
1515
|
+
"neopress_billing_resume",
|
|
1516
|
+
"neopress_team_invite",
|
|
1517
|
+
"neopress_team_member_update_role",
|
|
1518
|
+
"neopress_team_member_remove",
|
|
1519
|
+
"neopress_team_transfer_ownership",
|
|
1520
|
+
"neopress_history_snapshot_restore"
|
|
1521
|
+
]);
|
|
1522
|
+
const IDEMPOTENT_TOOLS = /* @__PURE__ */ new Set([
|
|
1523
|
+
"neopress_site_select",
|
|
1524
|
+
"neopress_page_compile",
|
|
1525
|
+
"neopress_domain_refresh",
|
|
1526
|
+
"neopress_form_response_mark_read",
|
|
1527
|
+
"neopress_billing_resume"
|
|
1337
1528
|
]);
|
|
1338
|
-
const IDEMPOTENT_TOOLS = /* @__PURE__ */ new Set(["neopress_site_select", "neopress_page_compile"]);
|
|
1339
1529
|
function getToolAnnotations(tool) {
|
|
1340
1530
|
const readOnly = READ_ONLY_TOOLS.has(tool.name);
|
|
1341
1531
|
return {
|
|
@@ -1343,7 +1533,7 @@ function getToolAnnotations(tool) {
|
|
|
1343
1533
|
readOnlyHint: readOnly,
|
|
1344
1534
|
destructiveHint: readOnly ? false : DESTRUCTIVE_TOOLS.has(tool.name),
|
|
1345
1535
|
idempotentHint: readOnly || IDEMPOTENT_TOOLS.has(tool.name),
|
|
1346
|
-
openWorldHint:
|
|
1536
|
+
openWorldHint: OPEN_WORLD_TOOLS.has(tool.name)
|
|
1347
1537
|
};
|
|
1348
1538
|
}
|
|
1349
1539
|
function getToolMeta(tool) {
|
|
@@ -1426,7 +1616,7 @@ const toolDefinitions = [
|
|
|
1426
1616
|
{
|
|
1427
1617
|
name: "neopress_site_select",
|
|
1428
1618
|
title: "Select Active Site",
|
|
1429
|
-
description: "Verify access to a site and store it as the active site for future MCP
|
|
1619
|
+
description: "Verify access to a site and store it as the active site for future MCP operations.",
|
|
1430
1620
|
inputSchema: { siteId: z.number().int().positive() },
|
|
1431
1621
|
handler: async (input, context, extra) => {
|
|
1432
1622
|
const selectedSiteId = asNumber(input, "siteId");
|
|
@@ -2090,7 +2280,7 @@ const toolDefinitions = [
|
|
|
2090
2280
|
{
|
|
2091
2281
|
name: "neopress_analytics_event_create",
|
|
2092
2282
|
title: "Create Analytics Event",
|
|
2093
|
-
description: "Create a saved analytics event definition. Discover
|
|
2283
|
+
description: "Create a saved analytics event definition over raw analytics signals. Discover page and form IDs with neopress_analytics_targets_list. Click targets use an observed href:<absolute-url> or selector:<fingerprint> key; outbound counts external-link clicks site-wide. Built-in events start collecting without editing or republishing page TSX. Optional id is a client UUID: reuse the same id and payload after an uncertain response.",
|
|
2094
2284
|
inputSchema: {
|
|
2095
2285
|
...siteIdShape,
|
|
2096
2286
|
id: z.string().uuid().optional(),
|
|
@@ -2101,8 +2291,8 @@ const toolDefinitions = [
|
|
|
2101
2291
|
"click",
|
|
2102
2292
|
"form",
|
|
2103
2293
|
"scroll",
|
|
2104
|
-
"
|
|
2105
|
-
"
|
|
2294
|
+
"dwell",
|
|
2295
|
+
"outbound"
|
|
2106
2296
|
]),
|
|
2107
2297
|
eventName: z.string().optional(),
|
|
2108
2298
|
path: z.string().optional(),
|
|
@@ -2139,8 +2329,8 @@ const toolDefinitions = [
|
|
|
2139
2329
|
"click",
|
|
2140
2330
|
"form",
|
|
2141
2331
|
"scroll",
|
|
2142
|
-
"
|
|
2143
|
-
"
|
|
2332
|
+
"dwell",
|
|
2333
|
+
"outbound"
|
|
2144
2334
|
]).optional(),
|
|
2145
2335
|
eventName: z.string().optional(),
|
|
2146
2336
|
path: z.string().optional(),
|
|
@@ -2637,6 +2827,247 @@ const toolDefinitions = [
|
|
|
2637
2827
|
return { ok: true };
|
|
2638
2828
|
}
|
|
2639
2829
|
},
|
|
2830
|
+
{
|
|
2831
|
+
name: "neopress_domain_status",
|
|
2832
|
+
title: "Get Custom Domain Status",
|
|
2833
|
+
description: "Get the active site's connected custom domain and verification status.",
|
|
2834
|
+
inputSchema: siteIdShape,
|
|
2835
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).domains.status()
|
|
2836
|
+
},
|
|
2837
|
+
{
|
|
2838
|
+
name: "neopress_domain_connect",
|
|
2839
|
+
title: "Connect Custom Domain",
|
|
2840
|
+
description: "Connect a custom domain. Changes public routing and may require DNS updates.",
|
|
2841
|
+
inputSchema: {
|
|
2842
|
+
...siteIdShape,
|
|
2843
|
+
domain: z.string().min(1)
|
|
2844
|
+
},
|
|
2845
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).domains.connect(asString(input, "domain"))
|
|
2846
|
+
},
|
|
2847
|
+
{
|
|
2848
|
+
name: "neopress_domain_refresh",
|
|
2849
|
+
title: "Refresh Custom Domain",
|
|
2850
|
+
description: "Refresh DNS and verification status for the currently connected domain.",
|
|
2851
|
+
inputSchema: siteIdShape,
|
|
2852
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).domains.refresh()
|
|
2853
|
+
},
|
|
2854
|
+
{
|
|
2855
|
+
name: "neopress_domain_remove",
|
|
2856
|
+
title: "Remove Custom Domain",
|
|
2857
|
+
description: "Remove the exact currently connected domain. Call the status tool first and pass that exact domain.",
|
|
2858
|
+
inputSchema: {
|
|
2859
|
+
...siteIdShape,
|
|
2860
|
+
domain: z.string().min(1)
|
|
2861
|
+
},
|
|
2862
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).domains.remove(asString(input, "domain"))
|
|
2863
|
+
},
|
|
2864
|
+
{
|
|
2865
|
+
name: "neopress_search_console_connection_status",
|
|
2866
|
+
title: "Get Search Console Connection",
|
|
2867
|
+
description: "Get Google Search Console authorization and property connection status.",
|
|
2868
|
+
inputSchema: siteIdShape,
|
|
2869
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).searchConsole.status()
|
|
2870
|
+
},
|
|
2871
|
+
{
|
|
2872
|
+
name: "neopress_search_console_authorize",
|
|
2873
|
+
title: "Authorize Search Console",
|
|
2874
|
+
description: "Create a Google OAuth URL that the user must open and complete.",
|
|
2875
|
+
inputSchema: {
|
|
2876
|
+
...siteIdShape,
|
|
2877
|
+
locale: z.string().optional()
|
|
2878
|
+
},
|
|
2879
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).searchConsole.authorize(asOptionalString(input, "locale"))
|
|
2880
|
+
},
|
|
2881
|
+
{
|
|
2882
|
+
name: "neopress_search_console_disconnect",
|
|
2883
|
+
title: "Disconnect Search Console",
|
|
2884
|
+
description: "Disconnect the site's Google Search Console integration.",
|
|
2885
|
+
inputSchema: siteIdShape,
|
|
2886
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).searchConsole.disconnect()
|
|
2887
|
+
},
|
|
2888
|
+
{
|
|
2889
|
+
name: "neopress_billing_status",
|
|
2890
|
+
title: "Get Billing Status",
|
|
2891
|
+
description: "Get owner-only plan and subscription status for the active site.",
|
|
2892
|
+
inputSchema: siteIdShape,
|
|
2893
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).billing.status()
|
|
2894
|
+
},
|
|
2895
|
+
{
|
|
2896
|
+
name: "neopress_billing_checkout",
|
|
2897
|
+
title: "Create Billing Checkout",
|
|
2898
|
+
description: "Create a checkout URL for the user to open. Does not itself complete payment.",
|
|
2899
|
+
inputSchema: {
|
|
2900
|
+
...siteIdShape,
|
|
2901
|
+
plan: z.enum(["launch", "growth"])
|
|
2902
|
+
},
|
|
2903
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).billing.checkout(input.plan)
|
|
2904
|
+
},
|
|
2905
|
+
{
|
|
2906
|
+
name: "neopress_billing_portal",
|
|
2907
|
+
title: "Create Billing Portal",
|
|
2908
|
+
description: "Create a customer-portal URL for the owner to open.",
|
|
2909
|
+
inputSchema: siteIdShape,
|
|
2910
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).billing.portal()
|
|
2911
|
+
},
|
|
2912
|
+
{
|
|
2913
|
+
name: "neopress_billing_cancel",
|
|
2914
|
+
title: "Cancel Subscription",
|
|
2915
|
+
description: "Schedule the site's subscription to cancel at the end of the billing period.",
|
|
2916
|
+
inputSchema: siteIdShape,
|
|
2917
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).billing.cancel()
|
|
2918
|
+
},
|
|
2919
|
+
{
|
|
2920
|
+
name: "neopress_billing_resume",
|
|
2921
|
+
title: "Resume Subscription",
|
|
2922
|
+
description: "Remove a scheduled end-of-period subscription cancellation.",
|
|
2923
|
+
inputSchema: siteIdShape,
|
|
2924
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).billing.resume()
|
|
2925
|
+
},
|
|
2926
|
+
{
|
|
2927
|
+
name: "neopress_team_list",
|
|
2928
|
+
title: "List Project Team",
|
|
2929
|
+
description: "List active members and pending invitations. Requires owner or admin.",
|
|
2930
|
+
inputSchema: siteIdShape,
|
|
2931
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).team.list()
|
|
2932
|
+
},
|
|
2933
|
+
{
|
|
2934
|
+
name: "neopress_team_invite",
|
|
2935
|
+
title: "Invite Project Member",
|
|
2936
|
+
description: "Invite a member. Seat limits and owner-only admin invitation rules apply.",
|
|
2937
|
+
inputSchema: {
|
|
2938
|
+
...siteIdShape,
|
|
2939
|
+
email: z.string().email(),
|
|
2940
|
+
role: z.enum([
|
|
2941
|
+
"admin",
|
|
2942
|
+
"editor",
|
|
2943
|
+
"viewer"
|
|
2944
|
+
]),
|
|
2945
|
+
locale: z.string().optional()
|
|
2946
|
+
},
|
|
2947
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).team.invite({
|
|
2948
|
+
email: asString(input, "email"),
|
|
2949
|
+
role: input.role,
|
|
2950
|
+
locale: asOptionalString(input, "locale")
|
|
2951
|
+
})
|
|
2952
|
+
},
|
|
2953
|
+
{
|
|
2954
|
+
name: "neopress_team_member_update_role",
|
|
2955
|
+
title: "Update Project Member Role",
|
|
2956
|
+
description: "Change an active member's role preset. Owner and seat rules apply.",
|
|
2957
|
+
inputSchema: {
|
|
2958
|
+
...siteIdShape,
|
|
2959
|
+
profileId: z.string().uuid(),
|
|
2960
|
+
role: z.enum([
|
|
2961
|
+
"admin",
|
|
2962
|
+
"editor",
|
|
2963
|
+
"viewer"
|
|
2964
|
+
])
|
|
2965
|
+
},
|
|
2966
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).team.updateRole(asString(input, "profileId"), input.role)
|
|
2967
|
+
},
|
|
2968
|
+
{
|
|
2969
|
+
name: "neopress_team_member_remove",
|
|
2970
|
+
title: "Remove Project Member",
|
|
2971
|
+
description: "Remove an active member. The owner cannot be removed.",
|
|
2972
|
+
inputSchema: {
|
|
2973
|
+
...siteIdShape,
|
|
2974
|
+
profileId: z.string().uuid()
|
|
2975
|
+
},
|
|
2976
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).team.remove(asString(input, "profileId"))
|
|
2977
|
+
},
|
|
2978
|
+
{
|
|
2979
|
+
name: "neopress_team_transfer_ownership",
|
|
2980
|
+
title: "Transfer Project Ownership",
|
|
2981
|
+
description: "Transfer ownership atomically to an active member. Owner-only.",
|
|
2982
|
+
inputSchema: {
|
|
2983
|
+
...siteIdShape,
|
|
2984
|
+
profileId: z.string().uuid()
|
|
2985
|
+
},
|
|
2986
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).team.transferOwnership(asString(input, "profileId"))
|
|
2987
|
+
},
|
|
2988
|
+
{
|
|
2989
|
+
name: "neopress_form_response_get",
|
|
2990
|
+
title: "Get Form Response",
|
|
2991
|
+
description: "Get one form response by form and response ID.",
|
|
2992
|
+
inputSchema: {
|
|
2993
|
+
...siteIdShape,
|
|
2994
|
+
formId: z.number().int().positive(),
|
|
2995
|
+
responseId: z.number().int().positive()
|
|
2996
|
+
},
|
|
2997
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).forms.getResponse(asNumber(input, "formId"), asNumber(input, "responseId"))
|
|
2998
|
+
},
|
|
2999
|
+
{
|
|
3000
|
+
name: "neopress_form_response_mark_read",
|
|
3001
|
+
title: "Mark Form Response Read",
|
|
3002
|
+
description: "Mark one form response as read.",
|
|
3003
|
+
inputSchema: {
|
|
3004
|
+
...siteIdShape,
|
|
3005
|
+
formId: z.number().int().positive(),
|
|
3006
|
+
responseId: z.number().int().positive()
|
|
3007
|
+
},
|
|
3008
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).forms.markResponseRead(asNumber(input, "formId"), asNumber(input, "responseId"))
|
|
3009
|
+
},
|
|
3010
|
+
{
|
|
3011
|
+
name: "neopress_form_response_delete",
|
|
3012
|
+
title: "Delete Form Response",
|
|
3013
|
+
description: "Soft-delete one form response.",
|
|
3014
|
+
inputSchema: {
|
|
3015
|
+
...siteIdShape,
|
|
3016
|
+
formId: z.number().int().positive(),
|
|
3017
|
+
responseId: z.number().int().positive()
|
|
3018
|
+
},
|
|
3019
|
+
handler: async (input, context, extra) => {
|
|
3020
|
+
await (await context.createClient({ siteId: siteId(input) }, extra)).forms.deleteResponse(asNumber(input, "formId"), asNumber(input, "responseId"));
|
|
3021
|
+
return { ok: true };
|
|
3022
|
+
}
|
|
3023
|
+
},
|
|
3024
|
+
{
|
|
3025
|
+
name: "neopress_history_snapshots_list",
|
|
3026
|
+
title: "List Site Snapshots",
|
|
3027
|
+
description: "List restorable page, layout, collection, and form snapshots.",
|
|
3028
|
+
inputSchema: {
|
|
3029
|
+
...siteIdShape,
|
|
3030
|
+
limit: z.number().int().positive().max(100).optional()
|
|
3031
|
+
},
|
|
3032
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).history.list(asOptionalNumber(input, "limit"))
|
|
3033
|
+
},
|
|
3034
|
+
{
|
|
3035
|
+
name: "neopress_history_snapshot_get",
|
|
3036
|
+
title: "Get Site Snapshot",
|
|
3037
|
+
description: "Get one exact restorable snapshot and its stored data.",
|
|
3038
|
+
inputSchema: {
|
|
3039
|
+
...siteIdShape,
|
|
3040
|
+
snapshotId: z.number().int().positive()
|
|
3041
|
+
},
|
|
3042
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).history.get(asNumber(input, "snapshotId"))
|
|
3043
|
+
},
|
|
3044
|
+
{
|
|
3045
|
+
name: "neopress_history_snapshot_restore",
|
|
3046
|
+
title: "Restore Site Snapshot",
|
|
3047
|
+
description: "Restore one exact page, layout, collection, or form snapshot. Draft state changes; page visibility and form settings may affect live behavior immediately.",
|
|
3048
|
+
inputSchema: {
|
|
3049
|
+
...siteIdShape,
|
|
3050
|
+
snapshotId: z.number().int().positive()
|
|
3051
|
+
},
|
|
3052
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).history.restore(asNumber(input, "snapshotId"))
|
|
3053
|
+
},
|
|
3054
|
+
{
|
|
3055
|
+
name: "neopress_analytics_funnel_results",
|
|
3056
|
+
title: "Get Saved Funnel Results",
|
|
3057
|
+
description: "Get aggregate results for a saved funnel. Steps and filters are resolved from the tenant-owned definition.",
|
|
3058
|
+
inputSchema: {
|
|
3059
|
+
...siteIdShape,
|
|
3060
|
+
funnelId: z.string().uuid(),
|
|
3061
|
+
dateFrom: z.string().optional(),
|
|
3062
|
+
dateTo: z.string().optional(),
|
|
3063
|
+
timezone: z.string().optional()
|
|
3064
|
+
},
|
|
3065
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).analytics.funnels.results(asString(input, "funnelId"), {
|
|
3066
|
+
dateFrom: asOptionalString(input, "dateFrom"),
|
|
3067
|
+
dateTo: asOptionalString(input, "dateTo"),
|
|
3068
|
+
timezone: asOptionalString(input, "timezone")
|
|
3069
|
+
})
|
|
3070
|
+
},
|
|
2640
3071
|
{
|
|
2641
3072
|
name: "neopress_publish_preview",
|
|
2642
3073
|
title: "Preview Site Publish",
|
|
@@ -2650,10 +3081,35 @@ const toolDefinitions = [
|
|
|
2650
3081
|
name: "neopress_publish_site",
|
|
2651
3082
|
title: "Publish Site",
|
|
2652
3083
|
description: "Publish layout, pages, collections, and forms from draft to production. Does not publish draft entry rows.",
|
|
2653
|
-
inputSchema:
|
|
3084
|
+
inputSchema: {
|
|
3085
|
+
...siteIdShape,
|
|
3086
|
+
selection: z.object({
|
|
3087
|
+
pageIds: z.array(z.number().int().positive()).optional(),
|
|
3088
|
+
collectionIds: z.array(z.number().int().positive()).optional(),
|
|
3089
|
+
formIds: z.array(z.number().int().positive()).optional(),
|
|
3090
|
+
includeLayout: z.boolean().optional()
|
|
3091
|
+
}).optional()
|
|
3092
|
+
},
|
|
2654
3093
|
handler: async (input, context, extra) => {
|
|
2655
|
-
return (await context.createClient({ siteId: siteId(input) }, extra)).publish.site();
|
|
3094
|
+
return (await context.createClient({ siteId: siteId(input) }, extra)).publish.site(input.selection);
|
|
2656
3095
|
}
|
|
3096
|
+
},
|
|
3097
|
+
{
|
|
3098
|
+
name: "neopress_unpublish_pages",
|
|
3099
|
+
title: "Unpublish Site Pages",
|
|
3100
|
+
description: "Remove exact page IDs from production without deleting their draft state.",
|
|
3101
|
+
inputSchema: {
|
|
3102
|
+
...siteIdShape,
|
|
3103
|
+
pageIds: z.array(z.number().int().positive()).min(1)
|
|
3104
|
+
},
|
|
3105
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).publish.unpublishPages(input.pageIds)
|
|
3106
|
+
},
|
|
3107
|
+
{
|
|
3108
|
+
name: "neopress_undeploy_site",
|
|
3109
|
+
title: "Undeploy Site",
|
|
3110
|
+
description: "Take the whole site offline while preserving draft state.",
|
|
3111
|
+
inputSchema: siteIdShape,
|
|
3112
|
+
handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).publish.undeploy()
|
|
2657
3113
|
}
|
|
2658
3114
|
];
|
|
2659
3115
|
function registerNeopressTools(server, context = createDefaultToolContext(), options = {}) {
|