@neopress/mcp 1.6.0 → 1.6.1

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/bin.cjs CHANGED
@@ -20421,9 +20421,8 @@ Use these rules before generating pages, collection schemas, entries, forms, or
20421
20421
 
20422
20422
  ## Operating boundary
20423
20423
 
20424
- - Authentication is OAuth bearer token based. Use \`NEOPRESS_ACCESS_TOKEN\` or the OAuth session created by \`neopress login\`.
20425
- - API keys and API-key based public integrations are not part of this surface.
20426
- - MCP is available as local stdio and remote Streamable HTTP over the first-party SDK/API.
20424
+ - Connect the remote MCP server and sign in with your Neopress account through OAuth.
20425
+ - MCP is available on Launch and above. Your site role controls which actions you can perform.
20427
20426
  - MCP is a Neopress contract adapter, not a reference crawler or managed page generator.
20428
20427
  - 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.
20429
20428
  - 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.
@@ -20437,9 +20436,9 @@ Use these rules before generating pages, collection schemas, entries, forms, or
20437
20436
 
20438
20437
  ## Cache
20439
20438
 
20440
- - Site publish invalidates site/layout/collection reader cache tags in the API environment that handled the request.
20439
+ - Site publish invalidates site/layout/collection reader cache tags in the environment connected to MCP.
20441
20440
  - Entry publish/unpublish invalidates entry reader cache when production visibility changes.
20442
- - A localhost publish does not invalidate production reader cache. For production validation, publish through the production API and verify the live URL.
20441
+ - A localhost publish does not invalidate production reader cache. For production validation, publish through the production MCP server and verify the live URL.
20443
20442
 
20444
20443
  ## Analytics and autopilot
20445
20444
 
@@ -20452,7 +20451,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
20452
20451
 
20453
20452
  - Layout owns header, footer, global CSS, and 404. Page TSX starts at page content.
20454
20453
  - Generated page TSX is sandboxed. Do not import Supabase, create API clients, read env vars, use filesystem/process APIs, or assume arbitrary npm packages.
20455
- - 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.
20454
+ - 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.
20456
20455
  - 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.
20457
20456
  - @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.
20458
20457
  - 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.
@@ -20474,7 +20473,9 @@ Use these rules before generating pages, collection schemas, entries, forms, or
20474
20473
  - \`queryConfig\` is stored in page \`draftMeta.queryConfig\`.
20475
20474
  - Query labels become React props. Entry query results are flattened, so use \`post.body\` instead of \`post.data.body\`.
20476
20475
  - 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.
20477
- - 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.
20476
+ - 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\`.
20477
+ - 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).
20478
+ - 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.
20478
20479
  - Use numeric \`collection_id\` filters. Runtime controls site, status, locale, deleted state, and published snapshots.
20479
20480
 
20480
20481
  ## Collections and entries
@@ -20488,7 +20489,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
20488
20489
 
20489
20490
  - Reference fields require a schema field with \`type: "references"\` and target \`collection_id\`.
20490
20491
  - Links live in \`entry_references\`, not only in raw entry \`data\`.
20491
- - \`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.
20492
+ - \`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.
20492
20493
  - After changing references, publish the source entry again.
20493
20494
 
20494
20495
  ## Forms
@@ -20501,7 +20502,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
20501
20502
  ## Unsupported visitor features
20502
20503
 
20503
20504
  Generated Neopress pages do not support visitor login/accounts, member areas, carts, checkout, payments, subscriptions, or order management.`;
20504
- const SERVER_INSTRUCTIONS = `Use Neopress MCP tools to manage a selected Neopress site through the first-party OAuth API.
20505
+ const SERVER_INSTRUCTIONS = `Use Neopress MCP tools to manage a selected Neopress site through an authenticated MCP connection.
20505
20506
 
20506
20507
  Before generating TSX or schema-backed pages, call neopress_get_runtime_contract or read neopress://runtime-contract.
20507
20508
  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.
@@ -20924,7 +20925,7 @@ const toolDefinitions = [
20924
20925
  {
20925
20926
  name: "neopress_site_select",
20926
20927
  title: "Select Active Site",
20927
- description: "Verify access to a site and store it as the active site for future MCP/CLI operations.",
20928
+ description: "Verify access to a site and store it as the active site for future MCP operations.",
20928
20929
  inputSchema: { siteId: number().int().positive() },
20929
20930
  handler: async (input, context, extra) => {
20930
20931
  const selectedSiteId = asNumber(input, "siteId");
@@ -21588,7 +21589,7 @@ const toolDefinitions = [
21588
21589
  {
21589
21590
  name: "neopress_analytics_event_create",
21590
21591
  title: "Create Analytics Event",
21591
- 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.",
21592
+ 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.",
21592
21593
  inputSchema: {
21593
21594
  ...siteIdShape,
21594
21595
  id: string().uuid().optional(),
@@ -21599,8 +21600,8 @@ const toolDefinitions = [
21599
21600
  "click",
21600
21601
  "form",
21601
21602
  "scroll",
21602
- "visibility",
21603
- "dwell"
21603
+ "dwell",
21604
+ "outbound"
21604
21605
  ]),
21605
21606
  eventName: string().optional(),
21606
21607
  path: string().optional(),
@@ -21637,8 +21638,8 @@ const toolDefinitions = [
21637
21638
  "click",
21638
21639
  "form",
21639
21640
  "scroll",
21640
- "visibility",
21641
- "dwell"
21641
+ "dwell",
21642
+ "outbound"
21642
21643
  ]).optional(),
21643
21644
  eventName: string().optional(),
21644
21645
  path: string().optional(),
package/dist/http-bin.cjs CHANGED
@@ -21804,9 +21804,8 @@ Use these rules before generating pages, collection schemas, entries, forms, or
21804
21804
 
21805
21805
  ## Operating boundary
21806
21806
 
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.
21807
+ - Connect the remote MCP server and sign in with your Neopress account through OAuth.
21808
+ - MCP is available on Launch and above. Your site role controls which actions you can perform.
21810
21809
  - MCP is a Neopress contract adapter, not a reference crawler or managed page generator.
21811
21810
  - 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
21811
  - 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,9 +21819,9 @@ Use these rules before generating pages, collection schemas, entries, forms, or
21820
21819
 
21821
21820
  ## Cache
21822
21821
 
21823
- - Site publish invalidates site/layout/collection reader cache tags in the API environment that handled the request.
21822
+ - Site publish invalidates site/layout/collection reader cache tags in the environment connected to MCP.
21824
21823
  - 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.
21824
+ - A localhost publish does not invalidate production reader cache. For production validation, publish through the production MCP server and verify the live URL.
21826
21825
 
21827
21826
  ## Analytics and autopilot
21828
21827
 
@@ -21835,7 +21834,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
21835
21834
 
21836
21835
  - Layout owns header, footer, global CSS, and 404. Page TSX starts at page content.
21837
21836
  - 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.
21837
+ - 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
21838
  - 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
21839
  - @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
21840
  - 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 +21856,9 @@ Use these rules before generating pages, collection schemas, entries, forms, or
21857
21856
  - \`queryConfig\` is stored in page \`draftMeta.queryConfig\`.
21858
21857
  - Query labels become React props. Entry query results are flattened, so use \`post.body\` instead of \`post.data.body\`.
21859
21858
  - 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.
21859
+ - 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\`.
21860
+ - 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).
21861
+ - 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
21862
  - Use numeric \`collection_id\` filters. Runtime controls site, status, locale, deleted state, and published snapshots.
21862
21863
 
21863
21864
  ## Collections and entries
@@ -21871,7 +21872,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
21871
21872
 
21872
21873
  - Reference fields require a schema field with \`type: "references"\` and target \`collection_id\`.
21873
21874
  - 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.
21875
+ - \`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
21876
  - After changing references, publish the source entry again.
21876
21877
 
21877
21878
  ## Forms
@@ -21884,7 +21885,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
21884
21885
  ## Unsupported visitor features
21885
21886
 
21886
21887
  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.
21888
+ const SERVER_INSTRUCTIONS = `Use Neopress MCP tools to manage a selected Neopress site through an authenticated MCP connection.
21888
21889
 
21889
21890
  Before generating TSX or schema-backed pages, call neopress_get_runtime_contract or read neopress://runtime-contract.
21890
21891
  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.
@@ -22307,7 +22308,7 @@ const toolDefinitions = [
22307
22308
  {
22308
22309
  name: "neopress_site_select",
22309
22310
  title: "Select Active Site",
22310
- description: "Verify access to a site and store it as the active site for future MCP/CLI operations.",
22311
+ description: "Verify access to a site and store it as the active site for future MCP operations.",
22311
22312
  inputSchema: { siteId: number().int().positive() },
22312
22313
  handler: async (input, context, extra) => {
22313
22314
  const selectedSiteId = asNumber(input, "siteId");
@@ -22971,7 +22972,7 @@ const toolDefinitions = [
22971
22972
  {
22972
22973
  name: "neopress_analytics_event_create",
22973
22974
  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.",
22975
+ 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
22976
  inputSchema: {
22976
22977
  ...siteIdShape,
22977
22978
  id: string().uuid().optional(),
@@ -22982,8 +22983,8 @@ const toolDefinitions = [
22982
22983
  "click",
22983
22984
  "form",
22984
22985
  "scroll",
22985
- "visibility",
22986
- "dwell"
22986
+ "dwell",
22987
+ "outbound"
22987
22988
  ]),
22988
22989
  eventName: string().optional(),
22989
22990
  path: string().optional(),
@@ -23020,8 +23021,8 @@ const toolDefinitions = [
23020
23021
  "click",
23021
23022
  "form",
23022
23023
  "scroll",
23023
- "visibility",
23024
- "dwell"
23024
+ "dwell",
23025
+ "outbound"
23025
23026
  ]).optional(),
23026
23027
  eventName: string().optional(),
23027
23028
  path: string().optional(),
package/dist/index.d.ts CHANGED
@@ -198,11 +198,13 @@ interface SiteLayout {
198
198
  draftTsx: string | null;
199
199
  draftGlobalCss: string | null;
200
200
  draftNotFoundTsx: string | null;
201
+ draftI18n: unknown;
201
202
  prodTsx: string | null;
202
203
  prodJs: string | null;
203
204
  prodGlobalCss: string | null;
204
205
  prodNotFoundTsx: string | null;
205
206
  prodNotFoundJs: string | null;
207
+ prodI18n: unknown;
206
208
  }
207
209
  interface Headshot {
208
210
  id: number;
@@ -289,7 +291,9 @@ interface SearchConsoleQueryResult {
289
291
  };
290
292
  error?: string;
291
293
  }
292
- type AnalyticsEventType = "custom" | "page" | "click" | "form" | "scroll" | "visibility" | "dwell";
294
+ type AnalyticsEventType = "custom" | "page" | "click" | "form" | "scroll" | "visibility" | "dwell" | "outbound";
295
+ /** `visibility` remains readable for historical definitions but cannot be created. */
296
+ type AnalyticsEventCreateType = Exclude<AnalyticsEventType, "visibility">;
293
297
  type FunnelFilterField = "event.path" | "event.url" | "event.referrer" | "event.referrer_source" | "event.property" | "session.referrer" | "session.referrer_source" | "session.traffic_category" | "session.utm_source" | "session.utm_medium" | "session.utm_campaign" | "session.utm_content" | "session.utm_term";
294
298
  type FunnelFilterOperator = "eq" | "neq" | "contains" | "not_contains" | "starts_with" | "ends_with" | "exists" | "not_exists" | "gt" | "gte" | "lt" | "lte";
295
299
  type AnalyticsFunnelFilterCondition = {
@@ -315,6 +319,7 @@ interface AnalyticsEventDefinition {
315
319
  name: string;
316
320
  chart_visible: boolean;
317
321
  is_pinned: boolean;
322
+ sort_order?: number | null;
318
323
  event_type: AnalyticsEventType;
319
324
  event_name: string;
320
325
  path: string;
@@ -330,7 +335,7 @@ interface AnalyticsEventDefinitionInput {
330
335
  /** Optional client UUID; reuse it with the same payload after an uncertain create response. */
331
336
  id?: string;
332
337
  name: string;
333
- eventType: AnalyticsEventType;
338
+ eventType: AnalyticsEventCreateType;
334
339
  eventName?: string;
335
340
  path?: string;
336
341
  selector?: string;
@@ -647,6 +652,8 @@ declare class SiteEndpoint {
647
652
  draftTsx?: string;
648
653
  draftNotFoundTsx?: string;
649
654
  draftGlobalCss?: string;
655
+ /** Replaces draft translations; null clears them, omission preserves them. */
656
+ draftI18n?: unknown;
650
657
  }): Promise<SiteLayout>;
651
658
  delete(): Promise<{
652
659
  siteId: number;
package/dist/index.js CHANGED
@@ -923,9 +923,8 @@ Use these rules before generating pages, collection schemas, entries, forms, or
923
923
 
924
924
  ## Operating boundary
925
925
 
926
- - Authentication is OAuth bearer token based. Use \`NEOPRESS_ACCESS_TOKEN\` or the OAuth session created by \`neopress login\`.
927
- - API keys and API-key based public integrations are not part of this surface.
928
- - MCP is available as local stdio and remote Streamable HTTP over the first-party SDK/API.
926
+ - Connect the remote MCP server and sign in with your Neopress account through OAuth.
927
+ - MCP is available on Launch and above. Your site role controls which actions you can perform.
929
928
  - MCP is a Neopress contract adapter, not a reference crawler or managed page generator.
930
929
  - 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
930
  - 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,9 +938,9 @@ Use these rules before generating pages, collection schemas, entries, forms, or
939
938
 
940
939
  ## Cache
941
940
 
942
- - Site publish invalidates site/layout/collection reader cache tags in the API environment that handled the request.
941
+ - Site publish invalidates site/layout/collection reader cache tags in the environment connected to MCP.
943
942
  - 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 API and verify the live URL.
943
+ - A localhost publish does not invalidate production reader cache. For production validation, publish through the production MCP server and verify the live URL.
945
944
 
946
945
  ## Analytics and autopilot
947
946
 
@@ -954,7 +953,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
954
953
 
955
954
  - Layout owns header, footer, global CSS, and 404. Page TSX starts at page content.
956
955
  - 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.
956
+ - 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
957
  - 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
958
  - @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
959
  - 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 +975,9 @@ Use these rules before generating pages, collection schemas, entries, forms, or
976
975
  - \`queryConfig\` is stored in page \`draftMeta.queryConfig\`.
977
976
  - Query labels become React props. Entry query results are flattened, so use \`post.body\` instead of \`post.data.body\`.
978
977
  - 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.
978
+ - 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\`.
979
+ - 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).
980
+ - 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
981
  - Use numeric \`collection_id\` filters. Runtime controls site, status, locale, deleted state, and published snapshots.
981
982
 
982
983
  ## Collections and entries
@@ -990,7 +991,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
990
991
 
991
992
  - Reference fields require a schema field with \`type: "references"\` and target \`collection_id\`.
992
993
  - 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 flattened object or null.
994
+ - \`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
995
  - After changing references, publish the source entry again.
995
996
 
996
997
  ## Forms
@@ -1003,7 +1004,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
1003
1004
  ## Unsupported visitor features
1004
1005
 
1005
1006
  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 the first-party OAuth API.
1007
+ const SERVER_INSTRUCTIONS = `Use Neopress MCP tools to manage a selected Neopress site through an authenticated MCP connection.
1007
1008
 
1008
1009
  Before generating TSX or schema-backed pages, call neopress_get_runtime_contract or read neopress://runtime-contract.
1009
1010
  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.
@@ -1426,7 +1427,7 @@ const toolDefinitions = [
1426
1427
  {
1427
1428
  name: "neopress_site_select",
1428
1429
  title: "Select Active Site",
1429
- description: "Verify access to a site and store it as the active site for future MCP/CLI operations.",
1430
+ description: "Verify access to a site and store it as the active site for future MCP operations.",
1430
1431
  inputSchema: { siteId: z.number().int().positive() },
1431
1432
  handler: async (input, context, extra) => {
1432
1433
  const selectedSiteId = asNumber(input, "siteId");
@@ -2090,7 +2091,7 @@ const toolDefinitions = [
2090
2091
  {
2091
2092
  name: "neopress_analytics_event_create",
2092
2093
  title: "Create Analytics Event",
2093
- 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.",
2094
+ 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
2095
  inputSchema: {
2095
2096
  ...siteIdShape,
2096
2097
  id: z.string().uuid().optional(),
@@ -2101,8 +2102,8 @@ const toolDefinitions = [
2101
2102
  "click",
2102
2103
  "form",
2103
2104
  "scroll",
2104
- "visibility",
2105
- "dwell"
2105
+ "dwell",
2106
+ "outbound"
2106
2107
  ]),
2107
2108
  eventName: z.string().optional(),
2108
2109
  path: z.string().optional(),
@@ -2139,8 +2140,8 @@ const toolDefinitions = [
2139
2140
  "click",
2140
2141
  "form",
2141
2142
  "scroll",
2142
- "visibility",
2143
- "dwell"
2143
+ "dwell",
2144
+ "outbound"
2144
2145
  ]).optional(),
2145
2146
  eventName: z.string().optional(),
2146
2147
  path: z.string().optional(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neopress/mcp",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
4
4
  "description": "Neopress MCP server for first-party AI agents",
5
5
  "type": "module",
6
6
  "bin": {