@neopress/mcp 1.6.1 → 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 CHANGED
@@ -22,7 +22,10 @@ Stdio MCP can use `neopress_asset_upload_file` because it runs on the same
22
22
  machine as the agent and can read local file paths.
23
23
 
24
24
  The tool surface includes site/layout/page/collection/entry/form/asset/publish
25
- operations plus analytics queries and saved event/funnel configuration. Use
25
+ operations, analytics queries and saved event/funnel configuration, plus custom
26
+ domains, Search Console connection, billing handoffs, team management, form
27
+ responses, entity history, saved-funnel results, selective publish, unpublish,
28
+ and undeploy. Use
26
29
  `neopress_analytics_event_update` with `eventId` and `name` to rename an existing
27
30
  event without changing its historical tracking behavior; display changes use a
28
31
  separate call. Create a new event when tracking conditions need to change. Use
@@ -30,6 +33,15 @@ separate call. Create a new event when tracking conditions need to change. Use
30
33
  page and form targets. Event and funnel creation accepts the same camelCase
31
34
  definition inputs as the dashboard; reads preserve stored snake_case fields.
32
35
 
36
+ The first-party API is the authorization boundary: all MCP calls re-check the
37
+ current site membership, action-level work access, and plan entitlements. MCP
38
+ access starts at Launch; Growth is required for deep analytics such as saved
39
+ funnel results. Billing is Owner-only, while team and domain management require
40
+ Owner/Admin. Consequential public, account, billing, team, delete, and restore
41
+ tools advertise destructive/open-world annotations so supporting hosts can put
42
+ them behind user approval. OAuth, DNS-provider credentials, checkout, and the
43
+ billing portal remain user-completed handoffs.
44
+
33
45
  ## Remote HTTP
34
46
 
35
47
  Use this for hosted MCP clients that connect over Streamable HTTP.
package/dist/bin.cjs CHANGED
@@ -19750,6 +19750,12 @@ var FormsEndpoint = class {
19750
19750
  async deleteResponse(formId, responseId) {
19751
19751
  await this.client.delete(`${this.basePath}/${formId}/responses/${responseId}`);
19752
19752
  }
19753
+ async getResponse(formId, responseId) {
19754
+ return (await this.client.get(`${this.basePath}/${formId}/responses/${responseId}`)).data;
19755
+ }
19756
+ async markResponseRead(formId, responseId) {
19757
+ return (await this.client.patch(`${this.basePath}/${formId}/responses/${responseId}`, { read: true })).data;
19758
+ }
19753
19759
  };
19754
19760
  //#endregion
19755
19761
  //#region ../sdk/src/endpoints/assets.ts
@@ -19897,8 +19903,14 @@ var PublishEndpoint = class {
19897
19903
  async preview() {
19898
19904
  return (await this.client.get(`${this.client.siteBasePath}/publish`)).data;
19899
19905
  }
19900
- async site() {
19901
- return (await this.client.post(`${this.client.siteBasePath}/publish`)).data;
19906
+ async site(selection) {
19907
+ return (await this.client.post(`${this.client.siteBasePath}/publish`, selection ? { selection } : void 0)).data;
19908
+ }
19909
+ async unpublishPages(pageIds) {
19910
+ return (await this.client.patch(`${this.client.siteBasePath}/publish`, { pageIds })).data;
19911
+ }
19912
+ async undeploy() {
19913
+ return (await this.client.delete(`${this.client.siteBasePath}/publish`)).data;
19902
19914
  }
19903
19915
  };
19904
19916
  //#endregion
@@ -20066,6 +20078,14 @@ var AnalyticsFunnelsEndpoint = class {
20066
20078
  async delete(funnelId) {
20067
20079
  await this.client.delete(`${this.basePath}/${funnelId}`);
20068
20080
  }
20081
+ async results(funnelId, params) {
20082
+ const query = new URLSearchParams();
20083
+ if (params?.dateFrom) query.set("dateFrom", params.dateFrom);
20084
+ if (params?.dateTo) query.set("dateTo", params.dateTo);
20085
+ if (params?.timezone) query.set("timezone", params.timezone);
20086
+ const suffix = query.size > 0 ? `?${query.toString()}` : "";
20087
+ return (await this.client.get(`${this.basePath}/${funnelId}/results${suffix}`)).data;
20088
+ }
20069
20089
  };
20070
20090
  //#endregion
20071
20091
  //#region ../sdk/src/endpoints/templates.ts
@@ -20194,6 +20214,122 @@ var LogosEndpoint = class {
20194
20214
  }
20195
20215
  };
20196
20216
  //#endregion
20217
+ //#region ../sdk/src/endpoints/domains.ts
20218
+ var DomainsEndpoint = class {
20219
+ client;
20220
+ constructor(client) {
20221
+ this.client = client;
20222
+ }
20223
+ get basePath() {
20224
+ return `${this.client.siteBasePath}/domains`;
20225
+ }
20226
+ async status() {
20227
+ return (await this.client.get(this.basePath)).data;
20228
+ }
20229
+ async connect(domain) {
20230
+ return (await this.client.post(this.basePath, { domain })).data;
20231
+ }
20232
+ async refresh() {
20233
+ return (await this.client.patch(this.basePath, {})).data;
20234
+ }
20235
+ async remove(domain) {
20236
+ return (await this.client.delete(this.basePath, { domain })).data;
20237
+ }
20238
+ };
20239
+ //#endregion
20240
+ //#region ../sdk/src/endpoints/search-console.ts
20241
+ var SearchConsoleConnectionEndpoint = class {
20242
+ client;
20243
+ constructor(client) {
20244
+ this.client = client;
20245
+ }
20246
+ get basePath() {
20247
+ return `${this.client.siteBasePath}/search-console`;
20248
+ }
20249
+ async status() {
20250
+ return (await this.client.get(this.basePath)).data;
20251
+ }
20252
+ async authorize(locale) {
20253
+ return (await this.client.post(this.basePath, locale ? { locale } : {})).data;
20254
+ }
20255
+ async disconnect() {
20256
+ return (await this.client.delete(this.basePath)).data;
20257
+ }
20258
+ };
20259
+ //#endregion
20260
+ //#region ../sdk/src/endpoints/billing.ts
20261
+ var BillingEndpoint = class {
20262
+ client;
20263
+ constructor(client) {
20264
+ this.client = client;
20265
+ }
20266
+ get basePath() {
20267
+ return `${this.client.siteBasePath}/billing`;
20268
+ }
20269
+ async status() {
20270
+ return (await this.client.get(this.basePath)).data;
20271
+ }
20272
+ async checkout(plan) {
20273
+ return (await this.client.post(`${this.basePath}/checkout`, { plan })).data;
20274
+ }
20275
+ async portal() {
20276
+ return (await this.client.post(`${this.basePath}/portal`)).data;
20277
+ }
20278
+ async cancel() {
20279
+ return (await this.client.post(`${this.basePath}/subscription/cancel`)).data;
20280
+ }
20281
+ async resume() {
20282
+ return (await this.client.post(`${this.basePath}/subscription/resume`)).data;
20283
+ }
20284
+ };
20285
+ //#endregion
20286
+ //#region ../sdk/src/endpoints/team.ts
20287
+ var TeamEndpoint = class {
20288
+ client;
20289
+ constructor(client) {
20290
+ this.client = client;
20291
+ }
20292
+ get basePath() {
20293
+ return `${this.client.siteBasePath}/team`;
20294
+ }
20295
+ async list() {
20296
+ return (await this.client.get(this.basePath)).data;
20297
+ }
20298
+ async invite(input) {
20299
+ return (await this.client.post(this.basePath, input)).data;
20300
+ }
20301
+ async updateRole(profileId, role) {
20302
+ return (await this.client.patch(`${this.basePath}/${profileId}`, { role })).data;
20303
+ }
20304
+ async remove(profileId) {
20305
+ return (await this.client.delete(`${this.basePath}/${profileId}`)).data;
20306
+ }
20307
+ async transferOwnership(profileId) {
20308
+ return (await this.client.post(`${this.basePath}/ownership`, { profileId })).data;
20309
+ }
20310
+ };
20311
+ //#endregion
20312
+ //#region ../sdk/src/endpoints/history.ts
20313
+ var HistoryEndpoint = class {
20314
+ client;
20315
+ constructor(client) {
20316
+ this.client = client;
20317
+ }
20318
+ get basePath() {
20319
+ return `${this.client.siteBasePath}/history/snapshots`;
20320
+ }
20321
+ async list(limit) {
20322
+ const query = limit === void 0 ? "" : `?limit=${encodeURIComponent(String(limit))}`;
20323
+ return (await this.client.get(`${this.basePath}${query}`)).data;
20324
+ }
20325
+ async get(snapshotId) {
20326
+ return (await this.client.get(`${this.basePath}/${snapshotId}`)).data;
20327
+ }
20328
+ async restore(snapshotId) {
20329
+ return (await this.client.post(`${this.basePath}/${snapshotId}/restore`)).data;
20330
+ }
20331
+ };
20332
+ //#endregion
20197
20333
  //#region ../sdk/src/client.ts
20198
20334
  /**
20199
20335
  * @neopress/sdk — API Client
@@ -20218,6 +20354,11 @@ var NeopressClient = class {
20218
20354
  templates;
20219
20355
  headshots;
20220
20356
  logos;
20357
+ domains;
20358
+ searchConsole;
20359
+ billing;
20360
+ team;
20361
+ history;
20221
20362
  constructor(options) {
20222
20363
  this.baseUrl = (options.baseUrl || "https://app.neopress.ai").replace(/\/$/, "");
20223
20364
  this.accessToken = options.accessToken || "";
@@ -20236,6 +20377,11 @@ var NeopressClient = class {
20236
20377
  this.templates = new TemplatesEndpoint(this);
20237
20378
  this.headshots = new HeadshotsEndpoint(this);
20238
20379
  this.logos = new LogosEndpoint(this);
20380
+ this.domains = new DomainsEndpoint(this);
20381
+ this.searchConsole = new SearchConsoleConnectionEndpoint(this);
20382
+ this.billing = new BillingEndpoint(this);
20383
+ this.team = new TeamEndpoint(this);
20384
+ this.history = new HistoryEndpoint(this);
20239
20385
  }
20240
20386
  get siteBasePath() {
20241
20387
  return `/api/v1/sites/${this.siteId}`;
@@ -20285,8 +20431,8 @@ var NeopressClient = class {
20285
20431
  async patch(path, body) {
20286
20432
  return this.request("PATCH", path, body);
20287
20433
  }
20288
- async delete(path) {
20289
- return this.request("DELETE", path);
20434
+ async delete(path, body) {
20435
+ return this.request("DELETE", path, body);
20290
20436
  }
20291
20437
  };
20292
20438
  //#endregion
@@ -20442,7 +20588,9 @@ Use these rules before generating pages, collection schemas, entries, forms, or
20442
20588
 
20443
20589
  ## Analytics and autopilot
20444
20590
 
20445
- - Analytics tools are read-only OAuth-authenticated queries for traffic, forms, AI crawler reach, and Search Console.
20591
+ - 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.
20592
+ - 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.
20593
+ - 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.
20446
20594
  - Generated page TSX must not call analytics APIs, Tinybird, Search Console, Supabase, or server resources directly.
20447
20595
  - Search Console can return connected=false. Do not claim query-level SEO evidence unless connected data is returned.
20448
20596
  - Analytics may justify the next draft change, but mutations still follow the compile, publish, entry publish, form publish, and production verification contracts.
@@ -20785,6 +20933,7 @@ const READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
20785
20933
  "neopress_forms_list",
20786
20934
  "neopress_form_get",
20787
20935
  "neopress_form_responses_list",
20936
+ "neopress_form_response_get",
20788
20937
  "neopress_analytics_query",
20789
20938
  "neopress_analytics_pageviews",
20790
20939
  "neopress_analytics_summary",
@@ -20801,6 +20950,13 @@ const READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
20801
20950
  "neopress_assets_list",
20802
20951
  "neopress_asset_get",
20803
20952
  "neopress_publish_preview",
20953
+ "neopress_domain_status",
20954
+ "neopress_search_console_connection_status",
20955
+ "neopress_billing_status",
20956
+ "neopress_team_list",
20957
+ "neopress_history_snapshots_list",
20958
+ "neopress_history_snapshot_get",
20959
+ "neopress_analytics_funnel_results",
20804
20960
  "neopress_template_get"
20805
20961
  ]);
20806
20962
  const DESTRUCTIVE_TOOLS = /* @__PURE__ */ new Set([
@@ -20826,15 +20982,48 @@ const DESTRUCTIVE_TOOLS = /* @__PURE__ */ new Set([
20826
20982
  "neopress_analytics_event_delete",
20827
20983
  "neopress_analytics_funnel_create",
20828
20984
  "neopress_analytics_funnel_update",
20829
- "neopress_analytics_funnel_delete"
20985
+ "neopress_analytics_funnel_delete",
20986
+ "neopress_domain_connect",
20987
+ "neopress_domain_remove",
20988
+ "neopress_search_console_disconnect",
20989
+ "neopress_billing_cancel",
20990
+ "neopress_team_member_update_role",
20991
+ "neopress_team_member_remove",
20992
+ "neopress_team_transfer_ownership",
20993
+ "neopress_form_response_delete",
20994
+ "neopress_history_snapshot_restore",
20995
+ "neopress_unpublish_pages",
20996
+ "neopress_undeploy_site"
20830
20997
  ]);
20831
- const PUBLICATION_TOOLS = /* @__PURE__ */ new Set([
20998
+ const OPEN_WORLD_TOOLS = /* @__PURE__ */ new Set([
20832
20999
  "neopress_entry_publish",
20833
21000
  "neopress_entry_unpublish",
20834
21001
  "neopress_form_publish",
20835
- "neopress_publish_site"
21002
+ "neopress_publish_site",
21003
+ "neopress_unpublish_pages",
21004
+ "neopress_undeploy_site",
21005
+ "neopress_domain_connect",
21006
+ "neopress_domain_refresh",
21007
+ "neopress_domain_remove",
21008
+ "neopress_search_console_authorize",
21009
+ "neopress_search_console_disconnect",
21010
+ "neopress_billing_checkout",
21011
+ "neopress_billing_portal",
21012
+ "neopress_billing_cancel",
21013
+ "neopress_billing_resume",
21014
+ "neopress_team_invite",
21015
+ "neopress_team_member_update_role",
21016
+ "neopress_team_member_remove",
21017
+ "neopress_team_transfer_ownership",
21018
+ "neopress_history_snapshot_restore"
21019
+ ]);
21020
+ const IDEMPOTENT_TOOLS = /* @__PURE__ */ new Set([
21021
+ "neopress_site_select",
21022
+ "neopress_page_compile",
21023
+ "neopress_domain_refresh",
21024
+ "neopress_form_response_mark_read",
21025
+ "neopress_billing_resume"
20836
21026
  ]);
20837
- const IDEMPOTENT_TOOLS = /* @__PURE__ */ new Set(["neopress_site_select", "neopress_page_compile"]);
20838
21027
  function getToolAnnotations(tool) {
20839
21028
  const readOnly = READ_ONLY_TOOLS.has(tool.name);
20840
21029
  return {
@@ -20842,7 +21031,7 @@ function getToolAnnotations(tool) {
20842
21031
  readOnlyHint: readOnly,
20843
21032
  destructiveHint: readOnly ? false : DESTRUCTIVE_TOOLS.has(tool.name),
20844
21033
  idempotentHint: readOnly || IDEMPOTENT_TOOLS.has(tool.name),
20845
- openWorldHint: PUBLICATION_TOOLS.has(tool.name)
21034
+ openWorldHint: OPEN_WORLD_TOOLS.has(tool.name)
20846
21035
  };
20847
21036
  }
20848
21037
  function getToolMeta(tool) {
@@ -22136,6 +22325,247 @@ const toolDefinitions = [
22136
22325
  return { ok: true };
22137
22326
  }
22138
22327
  },
22328
+ {
22329
+ name: "neopress_domain_status",
22330
+ title: "Get Custom Domain Status",
22331
+ description: "Get the active site's connected custom domain and verification status.",
22332
+ inputSchema: siteIdShape,
22333
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).domains.status()
22334
+ },
22335
+ {
22336
+ name: "neopress_domain_connect",
22337
+ title: "Connect Custom Domain",
22338
+ description: "Connect a custom domain. Changes public routing and may require DNS updates.",
22339
+ inputSchema: {
22340
+ ...siteIdShape,
22341
+ domain: string().min(1)
22342
+ },
22343
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).domains.connect(asString(input, "domain"))
22344
+ },
22345
+ {
22346
+ name: "neopress_domain_refresh",
22347
+ title: "Refresh Custom Domain",
22348
+ description: "Refresh DNS and verification status for the currently connected domain.",
22349
+ inputSchema: siteIdShape,
22350
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).domains.refresh()
22351
+ },
22352
+ {
22353
+ name: "neopress_domain_remove",
22354
+ title: "Remove Custom Domain",
22355
+ description: "Remove the exact currently connected domain. Call the status tool first and pass that exact domain.",
22356
+ inputSchema: {
22357
+ ...siteIdShape,
22358
+ domain: string().min(1)
22359
+ },
22360
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).domains.remove(asString(input, "domain"))
22361
+ },
22362
+ {
22363
+ name: "neopress_search_console_connection_status",
22364
+ title: "Get Search Console Connection",
22365
+ description: "Get Google Search Console authorization and property connection status.",
22366
+ inputSchema: siteIdShape,
22367
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).searchConsole.status()
22368
+ },
22369
+ {
22370
+ name: "neopress_search_console_authorize",
22371
+ title: "Authorize Search Console",
22372
+ description: "Create a Google OAuth URL that the user must open and complete.",
22373
+ inputSchema: {
22374
+ ...siteIdShape,
22375
+ locale: string().optional()
22376
+ },
22377
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).searchConsole.authorize(asOptionalString(input, "locale"))
22378
+ },
22379
+ {
22380
+ name: "neopress_search_console_disconnect",
22381
+ title: "Disconnect Search Console",
22382
+ description: "Disconnect the site's Google Search Console integration.",
22383
+ inputSchema: siteIdShape,
22384
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).searchConsole.disconnect()
22385
+ },
22386
+ {
22387
+ name: "neopress_billing_status",
22388
+ title: "Get Billing Status",
22389
+ description: "Get owner-only plan and subscription status for the active site.",
22390
+ inputSchema: siteIdShape,
22391
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).billing.status()
22392
+ },
22393
+ {
22394
+ name: "neopress_billing_checkout",
22395
+ title: "Create Billing Checkout",
22396
+ description: "Create a checkout URL for the user to open. Does not itself complete payment.",
22397
+ inputSchema: {
22398
+ ...siteIdShape,
22399
+ plan: _enum(["launch", "growth"])
22400
+ },
22401
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).billing.checkout(input.plan)
22402
+ },
22403
+ {
22404
+ name: "neopress_billing_portal",
22405
+ title: "Create Billing Portal",
22406
+ description: "Create a customer-portal URL for the owner to open.",
22407
+ inputSchema: siteIdShape,
22408
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).billing.portal()
22409
+ },
22410
+ {
22411
+ name: "neopress_billing_cancel",
22412
+ title: "Cancel Subscription",
22413
+ description: "Schedule the site's subscription to cancel at the end of the billing period.",
22414
+ inputSchema: siteIdShape,
22415
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).billing.cancel()
22416
+ },
22417
+ {
22418
+ name: "neopress_billing_resume",
22419
+ title: "Resume Subscription",
22420
+ description: "Remove a scheduled end-of-period subscription cancellation.",
22421
+ inputSchema: siteIdShape,
22422
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).billing.resume()
22423
+ },
22424
+ {
22425
+ name: "neopress_team_list",
22426
+ title: "List Project Team",
22427
+ description: "List active members and pending invitations. Requires owner or admin.",
22428
+ inputSchema: siteIdShape,
22429
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).team.list()
22430
+ },
22431
+ {
22432
+ name: "neopress_team_invite",
22433
+ title: "Invite Project Member",
22434
+ description: "Invite a member. Seat limits and owner-only admin invitation rules apply.",
22435
+ inputSchema: {
22436
+ ...siteIdShape,
22437
+ email: string().email(),
22438
+ role: _enum([
22439
+ "admin",
22440
+ "editor",
22441
+ "viewer"
22442
+ ]),
22443
+ locale: string().optional()
22444
+ },
22445
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).team.invite({
22446
+ email: asString(input, "email"),
22447
+ role: input.role,
22448
+ locale: asOptionalString(input, "locale")
22449
+ })
22450
+ },
22451
+ {
22452
+ name: "neopress_team_member_update_role",
22453
+ title: "Update Project Member Role",
22454
+ description: "Change an active member's role preset. Owner and seat rules apply.",
22455
+ inputSchema: {
22456
+ ...siteIdShape,
22457
+ profileId: string().uuid(),
22458
+ role: _enum([
22459
+ "admin",
22460
+ "editor",
22461
+ "viewer"
22462
+ ])
22463
+ },
22464
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).team.updateRole(asString(input, "profileId"), input.role)
22465
+ },
22466
+ {
22467
+ name: "neopress_team_member_remove",
22468
+ title: "Remove Project Member",
22469
+ description: "Remove an active member. The owner cannot be removed.",
22470
+ inputSchema: {
22471
+ ...siteIdShape,
22472
+ profileId: string().uuid()
22473
+ },
22474
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).team.remove(asString(input, "profileId"))
22475
+ },
22476
+ {
22477
+ name: "neopress_team_transfer_ownership",
22478
+ title: "Transfer Project Ownership",
22479
+ description: "Transfer ownership atomically to an active member. Owner-only.",
22480
+ inputSchema: {
22481
+ ...siteIdShape,
22482
+ profileId: string().uuid()
22483
+ },
22484
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).team.transferOwnership(asString(input, "profileId"))
22485
+ },
22486
+ {
22487
+ name: "neopress_form_response_get",
22488
+ title: "Get Form Response",
22489
+ description: "Get one form response by form and response ID.",
22490
+ inputSchema: {
22491
+ ...siteIdShape,
22492
+ formId: number().int().positive(),
22493
+ responseId: number().int().positive()
22494
+ },
22495
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).forms.getResponse(asNumber(input, "formId"), asNumber(input, "responseId"))
22496
+ },
22497
+ {
22498
+ name: "neopress_form_response_mark_read",
22499
+ title: "Mark Form Response Read",
22500
+ description: "Mark one form response as read.",
22501
+ inputSchema: {
22502
+ ...siteIdShape,
22503
+ formId: number().int().positive(),
22504
+ responseId: number().int().positive()
22505
+ },
22506
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).forms.markResponseRead(asNumber(input, "formId"), asNumber(input, "responseId"))
22507
+ },
22508
+ {
22509
+ name: "neopress_form_response_delete",
22510
+ title: "Delete Form Response",
22511
+ description: "Soft-delete one form response.",
22512
+ inputSchema: {
22513
+ ...siteIdShape,
22514
+ formId: number().int().positive(),
22515
+ responseId: number().int().positive()
22516
+ },
22517
+ handler: async (input, context, extra) => {
22518
+ await (await context.createClient({ siteId: siteId(input) }, extra)).forms.deleteResponse(asNumber(input, "formId"), asNumber(input, "responseId"));
22519
+ return { ok: true };
22520
+ }
22521
+ },
22522
+ {
22523
+ name: "neopress_history_snapshots_list",
22524
+ title: "List Site Snapshots",
22525
+ description: "List restorable page, layout, collection, and form snapshots.",
22526
+ inputSchema: {
22527
+ ...siteIdShape,
22528
+ limit: number().int().positive().max(100).optional()
22529
+ },
22530
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).history.list(asOptionalNumber(input, "limit"))
22531
+ },
22532
+ {
22533
+ name: "neopress_history_snapshot_get",
22534
+ title: "Get Site Snapshot",
22535
+ description: "Get one exact restorable snapshot and its stored data.",
22536
+ inputSchema: {
22537
+ ...siteIdShape,
22538
+ snapshotId: number().int().positive()
22539
+ },
22540
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).history.get(asNumber(input, "snapshotId"))
22541
+ },
22542
+ {
22543
+ name: "neopress_history_snapshot_restore",
22544
+ title: "Restore Site Snapshot",
22545
+ description: "Restore one exact page, layout, collection, or form snapshot. Draft state changes; page visibility and form settings may affect live behavior immediately.",
22546
+ inputSchema: {
22547
+ ...siteIdShape,
22548
+ snapshotId: number().int().positive()
22549
+ },
22550
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).history.restore(asNumber(input, "snapshotId"))
22551
+ },
22552
+ {
22553
+ name: "neopress_analytics_funnel_results",
22554
+ title: "Get Saved Funnel Results",
22555
+ description: "Get aggregate results for a saved funnel. Steps and filters are resolved from the tenant-owned definition.",
22556
+ inputSchema: {
22557
+ ...siteIdShape,
22558
+ funnelId: string().uuid(),
22559
+ dateFrom: string().optional(),
22560
+ dateTo: string().optional(),
22561
+ timezone: string().optional()
22562
+ },
22563
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).analytics.funnels.results(asString(input, "funnelId"), {
22564
+ dateFrom: asOptionalString(input, "dateFrom"),
22565
+ dateTo: asOptionalString(input, "dateTo"),
22566
+ timezone: asOptionalString(input, "timezone")
22567
+ })
22568
+ },
22139
22569
  {
22140
22570
  name: "neopress_publish_preview",
22141
22571
  title: "Preview Site Publish",
@@ -22149,10 +22579,35 @@ const toolDefinitions = [
22149
22579
  name: "neopress_publish_site",
22150
22580
  title: "Publish Site",
22151
22581
  description: "Publish layout, pages, collections, and forms from draft to production. Does not publish draft entry rows.",
22152
- inputSchema: siteIdShape,
22582
+ inputSchema: {
22583
+ ...siteIdShape,
22584
+ selection: object$1({
22585
+ pageIds: array(number().int().positive()).optional(),
22586
+ collectionIds: array(number().int().positive()).optional(),
22587
+ formIds: array(number().int().positive()).optional(),
22588
+ includeLayout: boolean().optional()
22589
+ }).optional()
22590
+ },
22153
22591
  handler: async (input, context, extra) => {
22154
- return (await context.createClient({ siteId: siteId(input) }, extra)).publish.site();
22592
+ return (await context.createClient({ siteId: siteId(input) }, extra)).publish.site(input.selection);
22155
22593
  }
22594
+ },
22595
+ {
22596
+ name: "neopress_unpublish_pages",
22597
+ title: "Unpublish Site Pages",
22598
+ description: "Remove exact page IDs from production without deleting their draft state.",
22599
+ inputSchema: {
22600
+ ...siteIdShape,
22601
+ pageIds: array(number().int().positive()).min(1)
22602
+ },
22603
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).publish.unpublishPages(input.pageIds)
22604
+ },
22605
+ {
22606
+ name: "neopress_undeploy_site",
22607
+ title: "Undeploy Site",
22608
+ description: "Take the whole site offline while preserving draft state.",
22609
+ inputSchema: siteIdShape,
22610
+ handler: async (input, context, extra) => (await context.createClient({ siteId: siteId(input) }, extra)).publish.undeploy()
22156
22611
  }
22157
22612
  ];
22158
22613
  function registerNeopressTools(server, context = createDefaultToolContext(), options = {}) {