@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/dist/http-bin.cjs CHANGED
@@ -21133,6 +21133,12 @@ var FormsEndpoint = class {
21133
21133
  async deleteResponse(formId, responseId) {
21134
21134
  await this.client.delete(`${this.basePath}/${formId}/responses/${responseId}`);
21135
21135
  }
21136
+ async getResponse(formId, responseId) {
21137
+ return (await this.client.get(`${this.basePath}/${formId}/responses/${responseId}`)).data;
21138
+ }
21139
+ async markResponseRead(formId, responseId) {
21140
+ return (await this.client.patch(`${this.basePath}/${formId}/responses/${responseId}`, { read: true })).data;
21141
+ }
21136
21142
  };
21137
21143
  //#endregion
21138
21144
  //#region ../sdk/src/endpoints/assets.ts
@@ -21280,8 +21286,14 @@ var PublishEndpoint = class {
21280
21286
  async preview() {
21281
21287
  return (await this.client.get(`${this.client.siteBasePath}/publish`)).data;
21282
21288
  }
21283
- async site() {
21284
- return (await this.client.post(`${this.client.siteBasePath}/publish`)).data;
21289
+ async site(selection) {
21290
+ return (await this.client.post(`${this.client.siteBasePath}/publish`, selection ? { selection } : void 0)).data;
21291
+ }
21292
+ async unpublishPages(pageIds) {
21293
+ return (await this.client.patch(`${this.client.siteBasePath}/publish`, { pageIds })).data;
21294
+ }
21295
+ async undeploy() {
21296
+ return (await this.client.delete(`${this.client.siteBasePath}/publish`)).data;
21285
21297
  }
21286
21298
  };
21287
21299
  //#endregion
@@ -21449,6 +21461,14 @@ var AnalyticsFunnelsEndpoint = class {
21449
21461
  async delete(funnelId) {
21450
21462
  await this.client.delete(`${this.basePath}/${funnelId}`);
21451
21463
  }
21464
+ async results(funnelId, params) {
21465
+ const query = new URLSearchParams();
21466
+ if (params?.dateFrom) query.set("dateFrom", params.dateFrom);
21467
+ if (params?.dateTo) query.set("dateTo", params.dateTo);
21468
+ if (params?.timezone) query.set("timezone", params.timezone);
21469
+ const suffix = query.size > 0 ? `?${query.toString()}` : "";
21470
+ return (await this.client.get(`${this.basePath}/${funnelId}/results${suffix}`)).data;
21471
+ }
21452
21472
  };
21453
21473
  //#endregion
21454
21474
  //#region ../sdk/src/endpoints/templates.ts
@@ -21577,6 +21597,122 @@ var LogosEndpoint = class {
21577
21597
  }
21578
21598
  };
21579
21599
  //#endregion
21600
+ //#region ../sdk/src/endpoints/domains.ts
21601
+ var DomainsEndpoint = class {
21602
+ client;
21603
+ constructor(client) {
21604
+ this.client = client;
21605
+ }
21606
+ get basePath() {
21607
+ return `${this.client.siteBasePath}/domains`;
21608
+ }
21609
+ async status() {
21610
+ return (await this.client.get(this.basePath)).data;
21611
+ }
21612
+ async connect(domain) {
21613
+ return (await this.client.post(this.basePath, { domain })).data;
21614
+ }
21615
+ async refresh() {
21616
+ return (await this.client.patch(this.basePath, {})).data;
21617
+ }
21618
+ async remove(domain) {
21619
+ return (await this.client.delete(this.basePath, { domain })).data;
21620
+ }
21621
+ };
21622
+ //#endregion
21623
+ //#region ../sdk/src/endpoints/search-console.ts
21624
+ var SearchConsoleConnectionEndpoint = class {
21625
+ client;
21626
+ constructor(client) {
21627
+ this.client = client;
21628
+ }
21629
+ get basePath() {
21630
+ return `${this.client.siteBasePath}/search-console`;
21631
+ }
21632
+ async status() {
21633
+ return (await this.client.get(this.basePath)).data;
21634
+ }
21635
+ async authorize(locale) {
21636
+ return (await this.client.post(this.basePath, locale ? { locale } : {})).data;
21637
+ }
21638
+ async disconnect() {
21639
+ return (await this.client.delete(this.basePath)).data;
21640
+ }
21641
+ };
21642
+ //#endregion
21643
+ //#region ../sdk/src/endpoints/billing.ts
21644
+ var BillingEndpoint = class {
21645
+ client;
21646
+ constructor(client) {
21647
+ this.client = client;
21648
+ }
21649
+ get basePath() {
21650
+ return `${this.client.siteBasePath}/billing`;
21651
+ }
21652
+ async status() {
21653
+ return (await this.client.get(this.basePath)).data;
21654
+ }
21655
+ async checkout(plan) {
21656
+ return (await this.client.post(`${this.basePath}/checkout`, { plan })).data;
21657
+ }
21658
+ async portal() {
21659
+ return (await this.client.post(`${this.basePath}/portal`)).data;
21660
+ }
21661
+ async cancel() {
21662
+ return (await this.client.post(`${this.basePath}/subscription/cancel`)).data;
21663
+ }
21664
+ async resume() {
21665
+ return (await this.client.post(`${this.basePath}/subscription/resume`)).data;
21666
+ }
21667
+ };
21668
+ //#endregion
21669
+ //#region ../sdk/src/endpoints/team.ts
21670
+ var TeamEndpoint = class {
21671
+ client;
21672
+ constructor(client) {
21673
+ this.client = client;
21674
+ }
21675
+ get basePath() {
21676
+ return `${this.client.siteBasePath}/team`;
21677
+ }
21678
+ async list() {
21679
+ return (await this.client.get(this.basePath)).data;
21680
+ }
21681
+ async invite(input) {
21682
+ return (await this.client.post(this.basePath, input)).data;
21683
+ }
21684
+ async updateRole(profileId, role) {
21685
+ return (await this.client.patch(`${this.basePath}/${profileId}`, { role })).data;
21686
+ }
21687
+ async remove(profileId) {
21688
+ return (await this.client.delete(`${this.basePath}/${profileId}`)).data;
21689
+ }
21690
+ async transferOwnership(profileId) {
21691
+ return (await this.client.post(`${this.basePath}/ownership`, { profileId })).data;
21692
+ }
21693
+ };
21694
+ //#endregion
21695
+ //#region ../sdk/src/endpoints/history.ts
21696
+ var HistoryEndpoint = class {
21697
+ client;
21698
+ constructor(client) {
21699
+ this.client = client;
21700
+ }
21701
+ get basePath() {
21702
+ return `${this.client.siteBasePath}/history/snapshots`;
21703
+ }
21704
+ async list(limit) {
21705
+ const query = limit === void 0 ? "" : `?limit=${encodeURIComponent(String(limit))}`;
21706
+ return (await this.client.get(`${this.basePath}${query}`)).data;
21707
+ }
21708
+ async get(snapshotId) {
21709
+ return (await this.client.get(`${this.basePath}/${snapshotId}`)).data;
21710
+ }
21711
+ async restore(snapshotId) {
21712
+ return (await this.client.post(`${this.basePath}/${snapshotId}/restore`)).data;
21713
+ }
21714
+ };
21715
+ //#endregion
21580
21716
  //#region ../sdk/src/client.ts
21581
21717
  /**
21582
21718
  * @neopress/sdk — API Client
@@ -21601,6 +21737,11 @@ var NeopressClient = class {
21601
21737
  templates;
21602
21738
  headshots;
21603
21739
  logos;
21740
+ domains;
21741
+ searchConsole;
21742
+ billing;
21743
+ team;
21744
+ history;
21604
21745
  constructor(options) {
21605
21746
  this.baseUrl = (options.baseUrl || "https://app.neopress.ai").replace(/\/$/, "");
21606
21747
  this.accessToken = options.accessToken || "";
@@ -21619,6 +21760,11 @@ var NeopressClient = class {
21619
21760
  this.templates = new TemplatesEndpoint(this);
21620
21761
  this.headshots = new HeadshotsEndpoint(this);
21621
21762
  this.logos = new LogosEndpoint(this);
21763
+ this.domains = new DomainsEndpoint(this);
21764
+ this.searchConsole = new SearchConsoleConnectionEndpoint(this);
21765
+ this.billing = new BillingEndpoint(this);
21766
+ this.team = new TeamEndpoint(this);
21767
+ this.history = new HistoryEndpoint(this);
21622
21768
  }
21623
21769
  get siteBasePath() {
21624
21770
  return `/api/v1/sites/${this.siteId}`;
@@ -21668,8 +21814,8 @@ var NeopressClient = class {
21668
21814
  async patch(path, body) {
21669
21815
  return this.request("PATCH", path, body);
21670
21816
  }
21671
- async delete(path) {
21672
- return this.request("DELETE", path);
21817
+ async delete(path, body) {
21818
+ return this.request("DELETE", path, body);
21673
21819
  }
21674
21820
  };
21675
21821
  //#endregion
@@ -21804,9 +21950,8 @@ Use these rules before generating pages, collection schemas, entries, forms, or
21804
21950
 
21805
21951
  ## Operating boundary
21806
21952
 
21807
- - Authentication is OAuth bearer token based. Use \`NEOPRESS_ACCESS_TOKEN\` or the OAuth session created by \`neopress login\`.
21808
- - API keys and API-key based public integrations are not part of this surface.
21809
- - MCP is available as local stdio and remote Streamable HTTP over the first-party SDK/API.
21953
+ - Connect the remote MCP server and sign in with your Neopress account through OAuth.
21954
+ - MCP is available on Launch and above. Your site role controls which actions you can perform.
21810
21955
  - MCP is a Neopress contract adapter, not a reference crawler or managed page generator.
21811
21956
  - 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.
21812
21957
  - 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.
@@ -21820,13 +21965,15 @@ Use these rules before generating pages, collection schemas, entries, forms, or
21820
21965
 
21821
21966
  ## Cache
21822
21967
 
21823
- - Site publish invalidates site/layout/collection reader cache tags in the API environment that handled the request.
21968
+ - Site publish invalidates site/layout/collection reader cache tags in the environment connected to MCP.
21824
21969
  - Entry publish/unpublish invalidates entry reader cache when production visibility changes.
21825
- - A localhost publish does not invalidate production reader cache. For production validation, publish through the production API and verify the live URL.
21970
+ - A localhost publish does not invalidate production reader cache. For production validation, publish through the production MCP server and verify the live URL.
21826
21971
 
21827
21972
  ## Analytics and autopilot
21828
21973
 
21829
- - Analytics tools are read-only OAuth-authenticated queries for traffic, forms, AI crawler reach, and Search Console.
21974
+ - 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.
21975
+ - 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.
21976
+ - 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.
21830
21977
  - Generated page TSX must not call analytics APIs, Tinybird, Search Console, Supabase, or server resources directly.
21831
21978
  - Search Console can return connected=false. Do not claim query-level SEO evidence unless connected data is returned.
21832
21979
  - Analytics may justify the next draft change, but mutations still follow the compile, publish, entry publish, form publish, and production verification contracts.
@@ -21835,7 +21982,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
21835
21982
 
21836
21983
  - Layout owns header, footer, global CSS, and 404. Page TSX starts at page content.
21837
21984
  - Generated page TSX is sandboxed. Do not import Supabase, create API clients, read env vars, use filesystem/process APIs, or assume arbitrary npm packages.
21838
- - 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.
21985
+ - 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.
21839
21986
  - 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.
21840
21987
  - @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.
21841
21988
  - 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.
@@ -21857,7 +22004,9 @@ Use these rules before generating pages, collection schemas, entries, forms, or
21857
22004
  - \`queryConfig\` is stored in page \`draftMeta.queryConfig\`.
21858
22005
  - Query labels become React props. Entry query results are flattened, so use \`post.body\` instead of \`post.data.body\`.
21859
22006
  - 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.
21860
- - 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.
22007
+ - 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\`.
22008
+ - 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).
22009
+ - 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.
21861
22010
  - Use numeric \`collection_id\` filters. Runtime controls site, status, locale, deleted state, and published snapshots.
21862
22011
 
21863
22012
  ## Collections and entries
@@ -21871,7 +22020,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
21871
22020
 
21872
22021
  - Reference fields require a schema field with \`type: "references"\` and target \`collection_id\`.
21873
22022
  - Links live in \`entry_references\`, not only in raw entry \`data\`.
21874
- - \`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 flattened object or null.
22023
+ - \`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.
21875
22024
  - After changing references, publish the source entry again.
21876
22025
 
21877
22026
  ## Forms
@@ -21884,7 +22033,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
21884
22033
  ## Unsupported visitor features
21885
22034
 
21886
22035
  Generated Neopress pages do not support visitor login/accounts, member areas, carts, checkout, payments, subscriptions, or order management.`;
21887
- const SERVER_INSTRUCTIONS = `Use Neopress MCP tools to manage a selected Neopress site through the first-party OAuth API.
22036
+ const SERVER_INSTRUCTIONS = `Use Neopress MCP tools to manage a selected Neopress site through an authenticated MCP connection.
21888
22037
 
21889
22038
  Before generating TSX or schema-backed pages, call neopress_get_runtime_contract or read neopress://runtime-contract.
21890
22039
  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.
@@ -22167,6 +22316,7 @@ const READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
22167
22316
  "neopress_forms_list",
22168
22317
  "neopress_form_get",
22169
22318
  "neopress_form_responses_list",
22319
+ "neopress_form_response_get",
22170
22320
  "neopress_analytics_query",
22171
22321
  "neopress_analytics_pageviews",
22172
22322
  "neopress_analytics_summary",
@@ -22183,6 +22333,13 @@ const READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
22183
22333
  "neopress_assets_list",
22184
22334
  "neopress_asset_get",
22185
22335
  "neopress_publish_preview",
22336
+ "neopress_domain_status",
22337
+ "neopress_search_console_connection_status",
22338
+ "neopress_billing_status",
22339
+ "neopress_team_list",
22340
+ "neopress_history_snapshots_list",
22341
+ "neopress_history_snapshot_get",
22342
+ "neopress_analytics_funnel_results",
22186
22343
  "neopress_template_get"
22187
22344
  ]);
22188
22345
  const DESTRUCTIVE_TOOLS = /* @__PURE__ */ new Set([
@@ -22208,15 +22365,48 @@ const DESTRUCTIVE_TOOLS = /* @__PURE__ */ new Set([
22208
22365
  "neopress_analytics_event_delete",
22209
22366
  "neopress_analytics_funnel_create",
22210
22367
  "neopress_analytics_funnel_update",
22211
- "neopress_analytics_funnel_delete"
22368
+ "neopress_analytics_funnel_delete",
22369
+ "neopress_domain_connect",
22370
+ "neopress_domain_remove",
22371
+ "neopress_search_console_disconnect",
22372
+ "neopress_billing_cancel",
22373
+ "neopress_team_member_update_role",
22374
+ "neopress_team_member_remove",
22375
+ "neopress_team_transfer_ownership",
22376
+ "neopress_form_response_delete",
22377
+ "neopress_history_snapshot_restore",
22378
+ "neopress_unpublish_pages",
22379
+ "neopress_undeploy_site"
22212
22380
  ]);
22213
- const PUBLICATION_TOOLS = /* @__PURE__ */ new Set([
22381
+ const OPEN_WORLD_TOOLS = /* @__PURE__ */ new Set([
22214
22382
  "neopress_entry_publish",
22215
22383
  "neopress_entry_unpublish",
22216
22384
  "neopress_form_publish",
22217
- "neopress_publish_site"
22385
+ "neopress_publish_site",
22386
+ "neopress_unpublish_pages",
22387
+ "neopress_undeploy_site",
22388
+ "neopress_domain_connect",
22389
+ "neopress_domain_refresh",
22390
+ "neopress_domain_remove",
22391
+ "neopress_search_console_authorize",
22392
+ "neopress_search_console_disconnect",
22393
+ "neopress_billing_checkout",
22394
+ "neopress_billing_portal",
22395
+ "neopress_billing_cancel",
22396
+ "neopress_billing_resume",
22397
+ "neopress_team_invite",
22398
+ "neopress_team_member_update_role",
22399
+ "neopress_team_member_remove",
22400
+ "neopress_team_transfer_ownership",
22401
+ "neopress_history_snapshot_restore"
22402
+ ]);
22403
+ const IDEMPOTENT_TOOLS = /* @__PURE__ */ new Set([
22404
+ "neopress_site_select",
22405
+ "neopress_page_compile",
22406
+ "neopress_domain_refresh",
22407
+ "neopress_form_response_mark_read",
22408
+ "neopress_billing_resume"
22218
22409
  ]);
22219
- const IDEMPOTENT_TOOLS = /* @__PURE__ */ new Set(["neopress_site_select", "neopress_page_compile"]);
22220
22410
  function getToolAnnotations(tool) {
22221
22411
  const readOnly = READ_ONLY_TOOLS.has(tool.name);
22222
22412
  return {
@@ -22224,7 +22414,7 @@ function getToolAnnotations(tool) {
22224
22414
  readOnlyHint: readOnly,
22225
22415
  destructiveHint: readOnly ? false : DESTRUCTIVE_TOOLS.has(tool.name),
22226
22416
  idempotentHint: readOnly || IDEMPOTENT_TOOLS.has(tool.name),
22227
- openWorldHint: PUBLICATION_TOOLS.has(tool.name)
22417
+ openWorldHint: OPEN_WORLD_TOOLS.has(tool.name)
22228
22418
  };
22229
22419
  }
22230
22420
  function getToolMeta(tool) {
@@ -22307,7 +22497,7 @@ const toolDefinitions = [
22307
22497
  {
22308
22498
  name: "neopress_site_select",
22309
22499
  title: "Select Active Site",
22310
- description: "Verify access to a site and store it as the active site for future MCP/CLI operations.",
22500
+ description: "Verify access to a site and store it as the active site for future MCP operations.",
22311
22501
  inputSchema: { siteId: number().int().positive() },
22312
22502
  handler: async (input, context, extra) => {
22313
22503
  const selectedSiteId = asNumber(input, "siteId");
@@ -22971,7 +23161,7 @@ const toolDefinitions = [
22971
23161
  {
22972
23162
  name: "neopress_analytics_event_create",
22973
23163
  title: "Create Analytics Event",
22974
- description: "Create a saved analytics event definition. Discover pages/forms with neopress_analytics_targets_list. Click/visibility require an existing stable [data-np-track=\"...\"] selector; page views reuse PAGE_VIEW. Optional id is a client UUID: reuse the same id and payload after an uncertain response.",
23164
+ 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.",
22975
23165
  inputSchema: {
22976
23166
  ...siteIdShape,
22977
23167
  id: string().uuid().optional(),
@@ -22982,8 +23172,8 @@ const toolDefinitions = [
22982
23172
  "click",
22983
23173
  "form",
22984
23174
  "scroll",
22985
- "visibility",
22986
- "dwell"
23175
+ "dwell",
23176
+ "outbound"
22987
23177
  ]),
22988
23178
  eventName: string().optional(),
22989
23179
  path: string().optional(),
@@ -23020,8 +23210,8 @@ const toolDefinitions = [
23020
23210
  "click",
23021
23211
  "form",
23022
23212
  "scroll",
23023
- "visibility",
23024
- "dwell"
23213
+ "dwell",
23214
+ "outbound"
23025
23215
  ]).optional(),
23026
23216
  eventName: string().optional(),
23027
23217
  path: string().optional(),
@@ -23518,6 +23708,247 @@ const toolDefinitions = [
23518
23708
  return { ok: true };
23519
23709
  }
23520
23710
  },
23711
+ {
23712
+ name: "neopress_domain_status",
23713
+ title: "Get Custom Domain Status",
23714
+ description: "Get the active site's connected custom domain and verification status.",
23715
+ inputSchema: siteIdShape,
23716
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).domains.status()
23717
+ },
23718
+ {
23719
+ name: "neopress_domain_connect",
23720
+ title: "Connect Custom Domain",
23721
+ description: "Connect a custom domain. Changes public routing and may require DNS updates.",
23722
+ inputSchema: {
23723
+ ...siteIdShape,
23724
+ domain: string().min(1)
23725
+ },
23726
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).domains.connect(asString(input, "domain"))
23727
+ },
23728
+ {
23729
+ name: "neopress_domain_refresh",
23730
+ title: "Refresh Custom Domain",
23731
+ description: "Refresh DNS and verification status for the currently connected domain.",
23732
+ inputSchema: siteIdShape,
23733
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).domains.refresh()
23734
+ },
23735
+ {
23736
+ name: "neopress_domain_remove",
23737
+ title: "Remove Custom Domain",
23738
+ description: "Remove the exact currently connected domain. Call the status tool first and pass that exact domain.",
23739
+ inputSchema: {
23740
+ ...siteIdShape,
23741
+ domain: string().min(1)
23742
+ },
23743
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).domains.remove(asString(input, "domain"))
23744
+ },
23745
+ {
23746
+ name: "neopress_search_console_connection_status",
23747
+ title: "Get Search Console Connection",
23748
+ description: "Get Google Search Console authorization and property connection status.",
23749
+ inputSchema: siteIdShape,
23750
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).searchConsole.status()
23751
+ },
23752
+ {
23753
+ name: "neopress_search_console_authorize",
23754
+ title: "Authorize Search Console",
23755
+ description: "Create a Google OAuth URL that the user must open and complete.",
23756
+ inputSchema: {
23757
+ ...siteIdShape,
23758
+ locale: string().optional()
23759
+ },
23760
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).searchConsole.authorize(asOptionalString(input, "locale"))
23761
+ },
23762
+ {
23763
+ name: "neopress_search_console_disconnect",
23764
+ title: "Disconnect Search Console",
23765
+ description: "Disconnect the site's Google Search Console integration.",
23766
+ inputSchema: siteIdShape,
23767
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).searchConsole.disconnect()
23768
+ },
23769
+ {
23770
+ name: "neopress_billing_status",
23771
+ title: "Get Billing Status",
23772
+ description: "Get owner-only plan and subscription status for the active site.",
23773
+ inputSchema: siteIdShape,
23774
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).billing.status()
23775
+ },
23776
+ {
23777
+ name: "neopress_billing_checkout",
23778
+ title: "Create Billing Checkout",
23779
+ description: "Create a checkout URL for the user to open. Does not itself complete payment.",
23780
+ inputSchema: {
23781
+ ...siteIdShape,
23782
+ plan: _enum(["launch", "growth"])
23783
+ },
23784
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).billing.checkout(input.plan)
23785
+ },
23786
+ {
23787
+ name: "neopress_billing_portal",
23788
+ title: "Create Billing Portal",
23789
+ description: "Create a customer-portal URL for the owner to open.",
23790
+ inputSchema: siteIdShape,
23791
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).billing.portal()
23792
+ },
23793
+ {
23794
+ name: "neopress_billing_cancel",
23795
+ title: "Cancel Subscription",
23796
+ description: "Schedule the site's subscription to cancel at the end of the billing period.",
23797
+ inputSchema: siteIdShape,
23798
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).billing.cancel()
23799
+ },
23800
+ {
23801
+ name: "neopress_billing_resume",
23802
+ title: "Resume Subscription",
23803
+ description: "Remove a scheduled end-of-period subscription cancellation.",
23804
+ inputSchema: siteIdShape,
23805
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).billing.resume()
23806
+ },
23807
+ {
23808
+ name: "neopress_team_list",
23809
+ title: "List Project Team",
23810
+ description: "List active members and pending invitations. Requires owner or admin.",
23811
+ inputSchema: siteIdShape,
23812
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).team.list()
23813
+ },
23814
+ {
23815
+ name: "neopress_team_invite",
23816
+ title: "Invite Project Member",
23817
+ description: "Invite a member. Seat limits and owner-only admin invitation rules apply.",
23818
+ inputSchema: {
23819
+ ...siteIdShape,
23820
+ email: string().email(),
23821
+ role: _enum([
23822
+ "admin",
23823
+ "editor",
23824
+ "viewer"
23825
+ ]),
23826
+ locale: string().optional()
23827
+ },
23828
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).team.invite({
23829
+ email: asString(input, "email"),
23830
+ role: input.role,
23831
+ locale: asOptionalString(input, "locale")
23832
+ })
23833
+ },
23834
+ {
23835
+ name: "neopress_team_member_update_role",
23836
+ title: "Update Project Member Role",
23837
+ description: "Change an active member's role preset. Owner and seat rules apply.",
23838
+ inputSchema: {
23839
+ ...siteIdShape,
23840
+ profileId: string().uuid(),
23841
+ role: _enum([
23842
+ "admin",
23843
+ "editor",
23844
+ "viewer"
23845
+ ])
23846
+ },
23847
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).team.updateRole(asString(input, "profileId"), input.role)
23848
+ },
23849
+ {
23850
+ name: "neopress_team_member_remove",
23851
+ title: "Remove Project Member",
23852
+ description: "Remove an active member. The owner cannot be removed.",
23853
+ inputSchema: {
23854
+ ...siteIdShape,
23855
+ profileId: string().uuid()
23856
+ },
23857
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).team.remove(asString(input, "profileId"))
23858
+ },
23859
+ {
23860
+ name: "neopress_team_transfer_ownership",
23861
+ title: "Transfer Project Ownership",
23862
+ description: "Transfer ownership atomically to an active member. Owner-only.",
23863
+ inputSchema: {
23864
+ ...siteIdShape,
23865
+ profileId: string().uuid()
23866
+ },
23867
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).team.transferOwnership(asString(input, "profileId"))
23868
+ },
23869
+ {
23870
+ name: "neopress_form_response_get",
23871
+ title: "Get Form Response",
23872
+ description: "Get one form response by form and response ID.",
23873
+ inputSchema: {
23874
+ ...siteIdShape,
23875
+ formId: number().int().positive(),
23876
+ responseId: number().int().positive()
23877
+ },
23878
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).forms.getResponse(asNumber(input, "formId"), asNumber(input, "responseId"))
23879
+ },
23880
+ {
23881
+ name: "neopress_form_response_mark_read",
23882
+ title: "Mark Form Response Read",
23883
+ description: "Mark one form response as read.",
23884
+ inputSchema: {
23885
+ ...siteIdShape,
23886
+ formId: number().int().positive(),
23887
+ responseId: number().int().positive()
23888
+ },
23889
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).forms.markResponseRead(asNumber(input, "formId"), asNumber(input, "responseId"))
23890
+ },
23891
+ {
23892
+ name: "neopress_form_response_delete",
23893
+ title: "Delete Form Response",
23894
+ description: "Soft-delete one form response.",
23895
+ inputSchema: {
23896
+ ...siteIdShape,
23897
+ formId: number().int().positive(),
23898
+ responseId: number().int().positive()
23899
+ },
23900
+ handler: async (input, context, extra) => {
23901
+ await (await context.createClient({ siteId: siteId(input) }, extra)).forms.deleteResponse(asNumber(input, "formId"), asNumber(input, "responseId"));
23902
+ return { ok: true };
23903
+ }
23904
+ },
23905
+ {
23906
+ name: "neopress_history_snapshots_list",
23907
+ title: "List Site Snapshots",
23908
+ description: "List restorable page, layout, collection, and form snapshots.",
23909
+ inputSchema: {
23910
+ ...siteIdShape,
23911
+ limit: number().int().positive().max(100).optional()
23912
+ },
23913
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).history.list(asOptionalNumber(input, "limit"))
23914
+ },
23915
+ {
23916
+ name: "neopress_history_snapshot_get",
23917
+ title: "Get Site Snapshot",
23918
+ description: "Get one exact restorable snapshot and its stored data.",
23919
+ inputSchema: {
23920
+ ...siteIdShape,
23921
+ snapshotId: number().int().positive()
23922
+ },
23923
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).history.get(asNumber(input, "snapshotId"))
23924
+ },
23925
+ {
23926
+ name: "neopress_history_snapshot_restore",
23927
+ title: "Restore Site Snapshot",
23928
+ description: "Restore one exact page, layout, collection, or form snapshot. Draft state changes; page visibility and form settings may affect live behavior immediately.",
23929
+ inputSchema: {
23930
+ ...siteIdShape,
23931
+ snapshotId: number().int().positive()
23932
+ },
23933
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).history.restore(asNumber(input, "snapshotId"))
23934
+ },
23935
+ {
23936
+ name: "neopress_analytics_funnel_results",
23937
+ title: "Get Saved Funnel Results",
23938
+ description: "Get aggregate results for a saved funnel. Steps and filters are resolved from the tenant-owned definition.",
23939
+ inputSchema: {
23940
+ ...siteIdShape,
23941
+ funnelId: string().uuid(),
23942
+ dateFrom: string().optional(),
23943
+ dateTo: string().optional(),
23944
+ timezone: string().optional()
23945
+ },
23946
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).analytics.funnels.results(asString(input, "funnelId"), {
23947
+ dateFrom: asOptionalString(input, "dateFrom"),
23948
+ dateTo: asOptionalString(input, "dateTo"),
23949
+ timezone: asOptionalString(input, "timezone")
23950
+ })
23951
+ },
23521
23952
  {
23522
23953
  name: "neopress_publish_preview",
23523
23954
  title: "Preview Site Publish",
@@ -23531,10 +23962,35 @@ const toolDefinitions = [
23531
23962
  name: "neopress_publish_site",
23532
23963
  title: "Publish Site",
23533
23964
  description: "Publish layout, pages, collections, and forms from draft to production. Does not publish draft entry rows.",
23534
- inputSchema: siteIdShape,
23965
+ inputSchema: {
23966
+ ...siteIdShape,
23967
+ selection: object$1({
23968
+ pageIds: array(number().int().positive()).optional(),
23969
+ collectionIds: array(number().int().positive()).optional(),
23970
+ formIds: array(number().int().positive()).optional(),
23971
+ includeLayout: boolean().optional()
23972
+ }).optional()
23973
+ },
23535
23974
  handler: async (input, context, extra) => {
23536
- return (await context.createClient({ siteId: siteId(input) }, extra)).publish.site();
23975
+ return (await context.createClient({ siteId: siteId(input) }, extra)).publish.site(input.selection);
23537
23976
  }
23977
+ },
23978
+ {
23979
+ name: "neopress_unpublish_pages",
23980
+ title: "Unpublish Site Pages",
23981
+ description: "Remove exact page IDs from production without deleting their draft state.",
23982
+ inputSchema: {
23983
+ ...siteIdShape,
23984
+ pageIds: array(number().int().positive()).min(1)
23985
+ },
23986
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).publish.unpublishPages(input.pageIds)
23987
+ },
23988
+ {
23989
+ name: "neopress_undeploy_site",
23990
+ title: "Undeploy Site",
23991
+ description: "Take the whole site offline while preserving draft state.",
23992
+ inputSchema: siteIdShape,
23993
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).publish.undeploy()
23538
23994
  }
23539
23995
  ];
23540
23996
  function registerNeopressTools(server, context = createDefaultToolContext(), options = {}) {