@contentful/mcp-tools 0.12.3 → 0.12.5

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +5290 -1145
  2. package/dist/index.js +2570 -199
  3. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -335,7 +335,12 @@ var RESOURCE_DISPLAY_NAME = {
335
335
  aiAction: "AI action",
336
336
  locale: "locale",
337
337
  concept: "concept",
338
- conceptScheme: "concept scheme"
338
+ conceptScheme: "concept scheme",
339
+ component: "component",
340
+ experience: "experience",
341
+ experienceFragment: "experience fragment",
342
+ experienceTemplate: "experience template",
343
+ dataAssembly: "data assembly"
339
344
  };
340
345
  function buildConfirmationPreview(resource, id, details, confirmToken) {
341
346
  const displayName = RESOURCE_DISPLAY_NAME[resource];
@@ -2303,141 +2308,61 @@ var ContextStore = class {
2303
2308
  var contextStore = new ContextStore();
2304
2309
 
2305
2310
  // src/tools/context/instructions.ts
2306
- var MCP_INSTRUCTIONS = `You are a helpful assistant integrated with Contentful through the Model Context Protocol (MCP).
2307
-
2308
- # Core Agent Principles
2309
-
2310
- ## IMPORTANT FIRST STEP:
2311
- - Always call get_initial_context first to initialize your connection before using any other tools
2312
- - This is required for all operations and will give you essential information about the current Contentful environment
2313
-
2314
- ## Key Principles:
2315
- - **Persistence**: Keep going until the user's query is completely resolved. Only end your turn when you are sure the problem is solved.
2316
- - **Tool Usage**: If you are not sure about content or schema structure, use your tools to gather relevant information. Do NOT guess or make up answers.
2317
- - **Planning**: Plan your approach before each tool call, and reflect on the outcomes of previous tool calls.
2318
- - **Resource Clarification**: ALWAYS ask the user which resource to work with if there are multiple resources available. Never assume or guess which resource to use.
2319
- - **Error Handling**: NEVER apologize for errors when making tool calls. Instead, immediately try a different approach or tool call. You may briefly inform the user what you're doing, but never say sorry.
2320
-
2321
- # Content Handling
2322
-
2323
- ## Content-Type-First Approach:
2324
- - **ALWAYS check the content type first** when users ask about finding or editing specific content types (e.g., "Where can I edit our pricing page?")
2325
- - Use get_content_types proactively to understand what content types exist before attempting queries
2326
- - This prevents failed queries and immediately reveals relevant content types (e.g., discovering a \`pricingPage\` type when asked about pricing)
2327
- - Match user requests to the appropriate content types in the entry
2328
- - If a user asks to create a field that doesn't match the content type (e.g., "writer" when the content type has "author"), suggest the correct type
2329
-
2330
- ## entry Creation Limits:
2331
- - A user is only allowed to create/edit/mutate a maximum of 5 (five) entries at a time
2332
- - For multiple entry creation, use the 'async' parameter (set to true) for better performance
2333
- - Only use async=true when creating more than one entry in a single conversation
2334
-
2335
- # Searching for Content
2336
-
2337
- ## Content-Type-First Search Strategy:
2338
- - **Content-Type-first approach**: When users ask about specific content (e.g., "pricing page", "blog posts"), use get_content_type first to discover relevant content types
2339
- - This immediately reveals the correct content types and prevents wasted time on failed queries
2340
- - After understanding the content type, use search_entries to search for content based on the correct content types and field names
2341
- - If a query returns no results, retry 2-3 times with modified queries by adjusting filters, relaxing constraints, or trying alternative field names
2342
- - When retrying queries, consider using more general terms, removing specific filters, or checking for typos in field names
2343
-
2344
- ## Handling Multi-Step Queries:
2345
- - For requests involving related entities (e.g., "Find blog posts by Magnus"), use a multi-step approach
2346
- - ALWAYS check the content type structure first to understand fields and references
2347
- - First, query for the referenced entity (e.g., author) to find its ID or confirm its existence
2348
- - If multiple entities match (e.g., several authors named "Magnus"), query them all and display them to the user
2349
- - Then use the found ID(s) to query for the primary content (e.g., blog posts referencing that author)
2350
- - For references in Contentful, remember to use the proper reference format
2351
- - Verify fields in the content type before constructing queries (single reference vs. array of references)
2352
-
2353
- ## Entry Management:
2354
- - For entry creation, use create_entry with clear instructions
2355
- - Use entry_action for operations like publishing, unpublishing, deleting, or discarding entries
2356
- - Use update_entry for content modifications with AI assistance. Always call get_entry first and pass the returned sys.version to update_entry; this is required and prevents overwriting concurrent changes.
2357
- - Use patch_entry for precise, direct modifications without AI generation (one operation at a time)
2358
- - Use transform_entry when preserving rich text formatting is crucial
2359
- - Use translate_entry specifically for language translation tasks
2360
- - Use transform_image for AI-powered image operations
2361
- - Always verify entry existence before attempting to modify it
2362
-
2363
- # Migration Strategies
2364
- - Use the space_to_space migration workflow to help a user when they want to migrate content from one space to another. Start this workflow by calling the start_space_to_space_migration tool.
2365
- - You do not need to fetch content types (ex. list_content_types tool) or entries (ex. search_entries tool) prior to starting the migration workflow. Once the user states they want to start the migration workflow, you simply need to call the start_space_to_space_migration tool.
2366
-
2367
- # Error Handling and Debugging
2368
-
2369
- ## Error Response Strategy:
2370
- - If you encounter an error, explain what went wrong clearly
2371
- - Suggest potential solutions or alternatives
2372
- - Make sure to check entry existence, field requirements, and permission issues
2373
- - Try different approaches immediately rather than stopping at the first error
2374
-
2375
- ## Common Issues to Check:
2376
- - entry existence and permissions
2377
- - Required field validation
2378
- - Correct field types (array vs single reference)
2379
-
2380
- # Response Format and Communication
2381
-
2382
- ## General Guidelines:
2383
- - Keep your responses concise but thorough
2384
- - Format complex data for readability using markdown
2385
- - Focus on completing the requested tasks efficiently
2386
- - Provide context from entries when relevant
2387
- - When displaying entries, show the most important fields first
2388
-
2389
- ## Before Using Tools:
2390
- Before running a tool:
2391
- 1. Think about what information you need to gather
2392
- 2. Determine the right tool and parameters to use
2393
- 3. Briefly communicate to the user what you're about to do in a conversational tone
2394
-
2395
- ## Problem-Solving Strategy:
2396
- 1. **Understand the request**: Analyze what the user is asking for and identify necessary entry types and fields
2397
- 2. **Resource identification**: If multiple resources are available, ALWAYS ask which resource to work with
2398
- 3. **Plan your approach**: Determine which tools you'll need and in which order
2399
- 4. **Execute with tools**: Use appropriate tools to query, create, or update entries
2400
- 5. **Verify results**: Check if results match what the user requested and make adjustments if needed
2401
- 6. **Respond clearly**: Present results in a clear, concise format
2402
-
2403
- # Best Practices
2404
-
2405
- ## Content Management:
2406
- - When creating content, follow the content type structure exactly
2407
- - Always verify entry existence before attempting to modify it
2408
- - Remind users that entry operations can affect live content
2409
-
2410
- ## Efficiency Tips:
2411
- - Suggest appropriate entry types based on user needs
2412
- - Recommend efficient ways to structure content
2413
- - Explain how Contentful features like content types, entries, and references work
2414
- - Help users understand the relationship between spaces, environments, and content types
2415
-
2416
- ## Bulk Actions:
2417
- - If making multiple calls to the same tool, ALWAYS check and see whether that tool supports bulk operations first, and condense them into a single call if possible.
2418
-
2419
- You have access to powerful tools that can help you work with Contentful effectively. Always start with get_initial_context, check the schema when needed, clarify resources when multiple exist, and take action to complete user requests fully.`;
2311
+ var CORE_INVARIANTS = `# Core operating rules
2312
+
2313
+ - **Schema first.** Before creating or finding content, inspect the environment's schema: list available types and inspect their fields. This prevents failed operations and ensures you use the right type and field names.
2314
+ - **Edit safely.** Before updating any item, fetch it first to get the current \`sys.version\`, then pass that version to the update call. The version is required and prevents overwriting concurrent changes.
2315
+ - **Bulk cap.** Bulk publish/unpublish/archive/unarchive operations accept at most 10 IDs per call by default. This cap does not apply to creating or updating items.
2316
+ - **Ask when ambiguous.** If multiple spaces or environments are available, ask the user which to use. Do not guess.`;
2317
+ var SEARCHING_GUIDANCE = `# Searching for content
2318
+
2319
+ - **Schema first.** When users ask about specific content, discover the relevant schema before searching: list the environment's available types and inspect a type's fields so you query on real field names. This prevents wasted queries. Use whichever primitives the environment exposes \u2014 classic content types and entries, or Experience Orchestration components and experiences.
2320
+ - **Then search.** Query using the correct type and field names. Prefer semantic search when the request is conceptual rather than an exact field match.
2321
+ - **Retry thoughtfully.** If a query returns no results, retry 2-3 times: relax filters, use more general terms, or check for typos in field names.
2322
+ - **Multi-step reference queries.** For requests that span references (e.g. "posts by Magnus"), first inspect the schema to confirm the reference field, then query for the referenced item to get its ID, then filter the primary query on that ID. If several items match, show them all and ask.`;
2323
+ var CONVENTIONS_GUIDANCE = `# Response and workflow conventions
2324
+
2325
+ - **Plan, then act.** Before a tool call, think about what you need, pick the right tool, and briefly tell the user what you are about to do.
2326
+ - **Persist.** Keep going until the request is fully resolved; do not stop at the first error. On failure, explain what went wrong and immediately try a different approach \u2014 never apologize for tool errors.
2327
+ - **Clarify resources.** If multiple spaces or environments exist, always ask which to use before acting.
2328
+ - **Format for readability.** Use markdown for complex data; show the most important fields of an entry first; keep responses concise but complete.
2329
+ - **Prefer bulk.** If you would call the same tool many times, check whether it supports multiple IDs and condense into one call (respecting the 10-ID cap on publish-family operations).`;
2330
+ var EXO_DISPOSITION = `# Tool disposition: Experience Orchestration by default
2331
+
2332
+ Experience Orchestration (ExO) tools are enabled. Use ExO primitives \u2014 Components, Experiences, Experience Templates, Experience Fragments, and Data Assemblies \u2014 for all content modeling and authoring. Do not create classic content types or entries unless the user explicitly instructs you to. If you are unsure how to model something with ExO, inspect the tool schemas and proceed with ExO.`;
2420
2333
 
2421
2334
  // src/tools/context/getInitialContextTool.ts
2422
2335
  var GetInitialContextToolParams = z35.object({});
2423
2336
  function getInitialContextTool(config) {
2424
2337
  async function tool2(_params) {
2425
- const configInfo = `Current Contentful Configuration:
2426
- - Space ID: ${config.spaceId || "Not set"}
2427
- - Environment ID: ${config.environmentId || "master"}
2428
- - Organization ID: ${config.organizationId || "Not set"}`;
2429
- const todaysDate = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US");
2338
+ const today = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", {
2339
+ weekday: "long",
2340
+ year: "numeric",
2341
+ month: "long",
2342
+ day: "numeric"
2343
+ });
2344
+ const sessionFacts = outdent`
2345
+ Current Contentful session:
2346
+ - Today's date: ${today}
2347
+ - Space ID: ${config.spaceId || "Not set"}
2348
+ - Environment ID: ${config.environmentId || "master"}
2349
+ - Organization ID: ${config.organizationId || "Not set"}`;
2350
+ const exoBlock = config.exoToolsRegistered ? `
2351
+
2352
+ ${EXO_DISPOSITION}` : "";
2430
2353
  const message = outdent`
2431
- ${MCP_INSTRUCTIONS}
2354
+ You are an assistant integrated with Contentful through the Model Context Protocol (MCP). Always call this tool first.
2355
+
2356
+ ${sessionFacts}
2357
+ ` + exoBlock + `
2432
2358
 
2433
- This is the initial context for your Contentful instance:
2359
+ ` + outdent`
2360
+ ${CORE_INVARIANTS}
2434
2361
 
2435
- <context>
2436
- ${configInfo}
2437
- </content>
2362
+ ${SEARCHING_GUIDANCE}
2438
2363
 
2439
- <todaysDate>${todaysDate}</todaysDate>
2440
- `;
2364
+ ${CONVENTIONS_GUIDANCE}
2365
+ `;
2441
2366
  contextStore.setInitialContextLoaded();
2442
2367
  return {
2443
2368
  content: [
@@ -5786,85 +5711,2481 @@ function createJobTools(config) {
5786
5711
  };
5787
5712
  }
5788
5713
 
5789
- // src/ContentfulMcpTools.ts
5790
- var ContentfulMcpTools = class {
5791
- config;
5792
- constructor(config) {
5793
- this.config = {
5794
- ...config,
5795
- host: config.host ?? "api.contentful.com",
5796
- environmentId: config.environmentId ?? "master"
5797
- };
5798
- }
5799
- /**
5800
- * Update the configuration after initialization
5801
- *
5802
- * @param updates - Partial configuration to merge with existing config
5803
- */
5804
- updateConfig(updates) {
5805
- this.config = { ...this.config, ...updates };
5806
- }
5807
- /**
5808
- * Get AI action tools
5809
- */
5810
- getAiActionTools() {
5811
- return createAiActionTools(this.config);
5812
- }
5813
- /**
5814
- * Get asset tools
5815
- */
5816
- getAssetTools() {
5817
- return createAssetTools(this.config);
5818
- }
5819
- /**
5820
- * Get content type tools
5821
- */
5822
- getContentTypeTools() {
5823
- return createContentTypeTools(this.config);
5714
+ // src/tools/exo/components/getComponent.ts
5715
+ import { z as z83 } from "zod";
5716
+ var GetComponentToolParams = BaseToolSchema.extend({
5717
+ componentId: z83.string().describe("The ID of the component to retrieve details for")
5718
+ });
5719
+ function getComponentTool(config) {
5720
+ async function tool2(args) {
5721
+ const contentfulClient = createToolClient(config, args);
5722
+ const component = await contentfulClient.component.get({
5723
+ spaceId: args.spaceId,
5724
+ environmentId: args.environmentId,
5725
+ componentId: args.componentId
5726
+ });
5727
+ return createSuccessResponse("Component retrieved successfully", {
5728
+ component
5729
+ });
5824
5730
  }
5825
- /**
5826
- * Get context tools
5827
- */
5828
- getContextTools() {
5829
- return createContextTools(this.config);
5731
+ return withErrorHandling(tool2, "Error retrieving component");
5732
+ }
5733
+
5734
+ // src/tools/exo/components/listComponents.ts
5735
+ import { z as z84 } from "zod";
5736
+ var ListComponentsToolParams = BaseToolSchema.extend({
5737
+ limit: z84.number().optional().describe("Maximum number of components to return (max 10)"),
5738
+ pageNext: z84.string().optional().describe("Cursor token to fetch the next page of results"),
5739
+ pagePrev: z84.string().optional().describe("Cursor token to fetch the previous page of results"),
5740
+ order: z84.string().optional().describe("Order components by this field (e.g. sys.createdAt)")
5741
+ });
5742
+ function listComponentsTool(config) {
5743
+ async function tool2(args) {
5744
+ const contentfulClient = createToolClient(config, args);
5745
+ const cursorParam = args.pageNext ? { pageNext: args.pageNext } : args.pagePrev ? { pagePrev: args.pagePrev } : {};
5746
+ const components = await contentfulClient.component.getMany({
5747
+ spaceId: args.spaceId,
5748
+ environmentId: args.environmentId,
5749
+ query: {
5750
+ limit: Math.min(args.limit || 10, 10),
5751
+ ...args.order && { order: args.order },
5752
+ ...cursorParam
5753
+ }
5754
+ });
5755
+ const summarized = summarizeData(components, {
5756
+ maxItems: 10,
5757
+ remainingMessage: "To see more components, ask me to retrieve the next page using the pageNext cursor."
5758
+ });
5759
+ return createSuccessResponse("Components retrieved successfully", {
5760
+ components: summarized,
5761
+ total: components.total,
5762
+ limit: components.limit,
5763
+ pages: components.pages
5764
+ });
5830
5765
  }
5831
- /**
5832
- * Get editor interface tools
5833
- */
5834
- getEditorInterfaceTools() {
5835
- return createEditorInterfaceTools(this.config);
5766
+ return withErrorHandling(tool2, "Error listing components");
5767
+ }
5768
+
5769
+ // src/tools/exo/components/createComponent.ts
5770
+ import { z as z86 } from "zod";
5771
+
5772
+ // src/types/exoSchemas.ts
5773
+ import { z as z85 } from "zod";
5774
+ var URN_EXAMPLES = {
5775
+ "Contentful:Component": "crn:contentful:::experience:spaces/{spaceId}/environments/{envId}/components/{id}",
5776
+ "Contentful:ExperienceFragment": "crn:contentful:::experience:spaces/{spaceId}/environments/{envId}/experienceFragments/{id}",
5777
+ "Contentful:ExperienceTemplate": "crn:contentful:::experience:spaces/{spaceId}/environments/{envId}/experienceTemplates/{id}",
5778
+ "Contentful:DataAssembly": "crn:contentful:::experience:spaces/{spaceId}/environments/{envId}/dataAssemblies/{id}"
5779
+ };
5780
+ var resourceLinkSchema2 = (linkType) => {
5781
+ const example = URN_EXAMPLES[linkType];
5782
+ const urnDesc = example ? `URN of the linked resource (e.g. "${example}")` : "URN of the linked resource";
5783
+ return z85.object({
5784
+ sys: z85.object({
5785
+ type: z85.literal("ResourceLink"),
5786
+ linkType: z85.literal(linkType),
5787
+ urn: z85.string().describe(urnDesc)
5788
+ })
5789
+ });
5790
+ };
5791
+ var linkSchema2 = (linkType) => z85.object({
5792
+ sys: z85.object({
5793
+ type: z85.literal("Link"),
5794
+ linkType: z85.literal(linkType),
5795
+ id: z85.string()
5796
+ })
5797
+ });
5798
+ var ComponentResourceLinkSchema = resourceLinkSchema2(
5799
+ "Contentful:Component"
5800
+ );
5801
+ var ExperienceFragmentResourceLinkSchema = resourceLinkSchema2(
5802
+ "Contentful:ExperienceFragment"
5803
+ );
5804
+ var ExperienceTemplateResourceLinkSchema = resourceLinkSchema2(
5805
+ "Contentful:ExperienceTemplate"
5806
+ );
5807
+ var ViewportSchema = z85.object({
5808
+ id: z85.string().describe("Viewport identifier"),
5809
+ query: z85.string().describe("CSS media query string"),
5810
+ displayName: z85.string().describe("Human-readable viewport name"),
5811
+ previewSize: z85.string().describe('Preview size (e.g. "1024px")')
5812
+ });
5813
+ var DataTypeDefinitionSchema = z85.lazy(
5814
+ () => z85.discriminatedUnion("type", [
5815
+ z85.object({
5816
+ type: z85.enum(["String", "Number", "Integer", "Boolean"]),
5817
+ name: z85.string().optional(),
5818
+ required: z85.boolean().optional()
5819
+ }),
5820
+ z85.object({
5821
+ type: z85.literal("RichText"),
5822
+ name: z85.string().optional(),
5823
+ required: z85.boolean().optional()
5824
+ }),
5825
+ z85.object({
5826
+ type: z85.literal("Array"),
5827
+ name: z85.string().optional(),
5828
+ required: z85.boolean().optional(),
5829
+ items: DataTypeDefinitionSchema
5830
+ }),
5831
+ z85.object({
5832
+ type: z85.literal("Record"),
5833
+ name: z85.string().optional(),
5834
+ required: z85.boolean().optional(),
5835
+ fields: z85.record(z85.string(), DataTypeDefinitionSchema)
5836
+ }),
5837
+ z85.object({
5838
+ type: z85.literal("TypeRef"),
5839
+ name: z85.string().optional(),
5840
+ required: z85.boolean().optional(),
5841
+ ref: z85.object({
5842
+ sys: z85.object({
5843
+ type: z85.literal("ResourceLink"),
5844
+ linkType: z85.string(),
5845
+ urn: z85.string()
5846
+ })
5847
+ })
5848
+ }),
5849
+ z85.object({
5850
+ type: z85.literal("Literal"),
5851
+ name: z85.string().optional(),
5852
+ required: z85.boolean().optional(),
5853
+ value: z85.custom().describe("JSON literal value"),
5854
+ valueType: DataTypeDefinitionSchema
5855
+ }),
5856
+ z85.object({
5857
+ type: z85.literal("DiscriminatedUnion"),
5858
+ name: z85.string().optional(),
5859
+ required: z85.boolean().optional(),
5860
+ discriminator: z85.string(),
5861
+ members: z85.array(DataTypeDefinitionSchema)
5862
+ })
5863
+ ])
5864
+ );
5865
+ var ContentPropertySchema = z85.intersection(
5866
+ DataTypeDefinitionSchema,
5867
+ z85.object({
5868
+ id: z85.string().describe("Content property identifier"),
5869
+ name: z85.string().describe("Human-readable name"),
5870
+ required: z85.boolean().describe("Whether the property is required"),
5871
+ defaultValue: z85.unknown().optional().describe("Default value")
5872
+ })
5873
+ );
5874
+ var DTCG_DESIGN_PROPERTY_TYPES = [
5875
+ "DTCG.Color",
5876
+ "DTCG.Dimension",
5877
+ "DTCG.FontFamily",
5878
+ "DTCG.FontWeight",
5879
+ "DTCG.Duration",
5880
+ "DTCG.CubicBezier",
5881
+ "DTCG.Number",
5882
+ "DTCG.StrokeStyle",
5883
+ "DTCG.Border",
5884
+ "DTCG.Transition",
5885
+ "DTCG.Shadow",
5886
+ "DTCG.Gradient",
5887
+ "DTCG.Typography"
5888
+ ];
5889
+ var DesignPropertyCommonFieldsSchema = z85.object({
5890
+ id: z85.string().describe("Design property identifier"),
5891
+ name: z85.string().describe("Human-readable name"),
5892
+ description: z85.string().optional().describe("Optional description")
5893
+ });
5894
+ var StringDesignPropertySchema = DesignPropertyCommonFieldsSchema.extend({
5895
+ type: z85.literal("String"),
5896
+ fallbackValue: z85.object({
5897
+ type: z85.literal("ManualDesignValue"),
5898
+ value: z85.string()
5899
+ }).optional().describe("Manual fallback value for this design property"),
5900
+ validations: z85.array(
5901
+ z85.object({
5902
+ regexp: z85.object({
5903
+ pattern: z85.string().describe("Regular expression pattern")
5904
+ })
5905
+ })
5906
+ ).optional().describe("Regexp validations constraining allowed string values")
5907
+ });
5908
+ var BooleanDesignPropertySchema = DesignPropertyCommonFieldsSchema.extend({
5909
+ type: z85.literal("Boolean"),
5910
+ fallbackValue: z85.object({
5911
+ type: z85.literal("ManualDesignValue"),
5912
+ value: z85.boolean()
5913
+ }).optional().describe("Manual fallback value for this design property")
5914
+ });
5915
+ var DesignTokenValueSchema = z85.object({
5916
+ type: z85.literal("DesignToken"),
5917
+ value: z85.string().min(1).describe("Design token reference (non-empty)")
5918
+ });
5919
+ var TokenBackedDesignPropertySchema = DesignPropertyCommonFieldsSchema.extend(
5920
+ {
5921
+ type: z85.enum(DTCG_DESIGN_PROPERTY_TYPES),
5922
+ fallbackValue: DesignTokenValueSchema.optional().describe(
5923
+ "Design-token-backed fallback value for this design property"
5924
+ ),
5925
+ allowedResources: z85.array(
5926
+ z85.object({
5927
+ type: z85.literal("DesignToken"),
5928
+ value: z85.string(),
5929
+ name: z85.string().optional()
5930
+ })
5931
+ ).optional().describe("Allowed design token resources")
5836
5932
  }
5837
- /**
5838
- * Get entry tools
5839
- */
5840
- getEntryTools() {
5841
- return createEntryTools(this.config);
5933
+ );
5934
+ var DesignPropertySchema = z85.union([
5935
+ StringDesignPropertySchema,
5936
+ BooleanDesignPropertySchema,
5937
+ TokenBackedDesignPropertySchema
5938
+ ]);
5939
+ var ManualDesignValueSchema = z85.object({
5940
+ type: z85.literal("ManualDesignValue"),
5941
+ value: z85.union([z85.string(), z85.number(), z85.boolean()])
5942
+ });
5943
+ var DesignPropertyValueSchema = z85.union([
5944
+ ManualDesignValueSchema,
5945
+ DesignTokenValueSchema
5946
+ ]);
5947
+ var DesignPropertyPointerValueSchema = z85.custom(
5948
+ (val) => typeof val === "string" && /^\$designProperties\//.test(val),
5949
+ { message: 'Must be a "$designProperties/..." pointer' }
5950
+ );
5951
+ var DimensionedDesignPropertyValueSchema = z85.record(
5952
+ z85.string(),
5953
+ DesignPropertyValueSchema
5954
+ );
5955
+ var ComponentTreeDesignPropertyValueSchema = z85.union([
5956
+ DesignPropertyValueSchema,
5957
+ DesignPropertyPointerValueSchema,
5958
+ DimensionedDesignPropertyValueSchema
5959
+ ]);
5960
+ var COMPONENT_TYPE_ALLOWED_RESOURCE_SOURCE = "crn:contentful:::experience:spaces/$self/environments/$self";
5961
+ var SlotDefinitionSchema = z85.object({
5962
+ id: z85.string().describe("Slot identifier"),
5963
+ name: z85.string().describe("Human-readable name"),
5964
+ required: z85.boolean().describe("Whether the slot must be filled"),
5965
+ validations: z85.array(
5966
+ z85.object({
5967
+ size: z85.object({
5968
+ min: z85.number().optional(),
5969
+ max: z85.number().optional()
5970
+ }).optional()
5971
+ })
5972
+ ).describe("Slot cardinality validations"),
5973
+ allowedResources: z85.array(
5974
+ z85.object({
5975
+ type: z85.literal("Contentful:Component"),
5976
+ source: z85.literal(COMPONENT_TYPE_ALLOWED_RESOURCE_SOURCE),
5977
+ allowedTypes: z85.array(z85.string()).describe("IDs of components allowed in this slot")
5978
+ })
5979
+ ).optional().describe("Constrains which components may be placed in this slot")
5980
+ });
5981
+ var ExperienceFragmentNodeSchema = z85.object({
5982
+ id: z85.string().describe("Node identifier"),
5983
+ name: z85.string().optional().describe("Optional display name"),
5984
+ nodeType: z85.literal("ExperienceFragment").describe('Must be "ExperienceFragment"'),
5985
+ experienceFragment: ExperienceFragmentResourceLinkSchema.describe(
5986
+ "Resource link to the referenced experience fragment"
5987
+ )
5988
+ });
5989
+ var SlotNodeSchema = z85.object({
5990
+ id: z85.string().describe("Node identifier"),
5991
+ nodeType: z85.literal("Slot").describe('Must be "Slot"'),
5992
+ slotId: z85.string().describe("ID of the slot definition to render")
5993
+ });
5994
+ var TreeNodeSchema = z85.lazy(
5995
+ () => z85.union([ComponentNodeSchema, ExperienceFragmentNodeSchema, SlotNodeSchema])
5996
+ );
5997
+ var ComponentNodeSchema = z85.lazy(
5998
+ () => z85.object({
5999
+ id: z85.string().describe("Node identifier"),
6000
+ name: z85.string().optional().describe("Optional display name"),
6001
+ nodeType: z85.literal("Component").describe('Must be "Component"'),
6002
+ component: ComponentResourceLinkSchema.describe(
6003
+ "Resource link to the component to render"
6004
+ ),
6005
+ contentProperties: z85.union([
6006
+ z85.record(z85.string(), z85.unknown()),
6007
+ z85.string().describe('"$contentProperties/..." pointer')
6008
+ ]).describe(
6009
+ 'Content property bindings \u2014 values or "$contentProperties/..." pointers'
6010
+ ),
6011
+ designProperties: z85.record(z85.string(), ComponentTreeDesignPropertyValueSchema).describe(
6012
+ 'Design property values \u2014 ManualDesignValue, DesignTokenValue, or "$designProperties/..." pointers'
6013
+ ),
6014
+ slots: z85.record(z85.string(), z85.array(TreeNodeSchema)).describe("Child tree nodes keyed by slot ID")
6015
+ })
6016
+ );
6017
+ var TagLinkSchema = linkSchema2("Tag");
6018
+ var ConceptLinkSchema = linkSchema2("TaxonomyConcept");
6019
+ var ExoMetadataSchema = z85.object({
6020
+ tags: z85.array(TagLinkSchema).optional().describe("Tags attached to this entity"),
6021
+ concepts: z85.array(ConceptLinkSchema).optional().describe("Taxonomy concepts attached to this entity")
6022
+ });
6023
+ var ExperienceMetadataSchema = ExoMetadataSchema.extend({
6024
+ name: z85.string().optional().describe("Variant label for this metadata entry")
6025
+ });
6026
+ var DataAssemblyResourceLinkSchema = resourceLinkSchema2(
6027
+ "Contentful:DataAssembly"
6028
+ );
6029
+ var ExperienceContentBindingsSchema = z85.object({
6030
+ sys: DataAssemblyResourceLinkSchema.shape.sys,
6031
+ parameters: z85.record(
6032
+ z85.string(),
6033
+ z85.object({
6034
+ sys: z85.object({
6035
+ type: z85.literal("ResourceLink"),
6036
+ linkType: z85.string(),
6037
+ urn: z85.string()
6038
+ })
6039
+ })
6040
+ ).describe("Parameter bindings keyed by parameter ID")
6041
+ });
6042
+ var InlineExperienceFragmentNodeSchema = z85.lazy(
6043
+ () => z85.object({
6044
+ id: z85.string().describe("Node identifier"),
6045
+ nodeType: z85.literal("InlineExperienceFragment").describe('Must be "InlineExperienceFragment"'),
6046
+ component: ComponentResourceLinkSchema.describe(
6047
+ "Resource link to the component this inline experience fragment renders"
6048
+ ),
6049
+ designProperties: z85.record(z85.string(), DimensionedDesignPropertyValueSchema).describe("Design property values for this inline experience fragment"),
6050
+ contentBindings: ExperienceContentBindingsSchema.optional().describe(
6051
+ "Optional content bindings linking this inline experience fragment to a data assembly"
6052
+ ),
6053
+ slots: z85.record(z85.string(), z85.array(ExperienceSlotNodeSchema)).optional().describe("Child slot contents keyed by slot ID")
6054
+ })
6055
+ );
6056
+ var ExperienceSlotNodeSchema = z85.lazy(
6057
+ () => z85.union([ExperienceFragmentNodeSchema, InlineExperienceFragmentNodeSchema])
6058
+ );
6059
+
6060
+ // src/tools/exo/components/createComponent.ts
6061
+ var CreateComponentToolParams = BaseToolSchema.extend({
6062
+ name: z86.string().describe("The name of the component"),
6063
+ description: z86.string().describe("Description of the component"),
6064
+ viewports: z86.array(ViewportSchema).describe("Viewport definitions for the component (may be empty)"),
6065
+ contentProperties: z86.array(ContentPropertySchema).describe("Content property definitions (may be empty)"),
6066
+ designProperties: z86.array(DesignPropertySchema).describe("Design property definitions (may be empty)"),
6067
+ componentTree: z86.array(TreeNodeSchema).optional().describe("Optional component tree node definitions"),
6068
+ slots: z86.array(SlotDefinitionSchema).optional().describe("Optional slot definitions"),
6069
+ metadata: ExoMetadataSchema.optional().describe(
6070
+ "Optional ExO metadata (tags, concepts)"
6071
+ )
6072
+ });
6073
+ function createComponentTool(config) {
6074
+ async function tool2(args) {
6075
+ assertEnvironmentNotProtected(
6076
+ args.environmentId,
6077
+ config.protectedEnvironments
6078
+ );
6079
+ const contentfulClient = createToolClient(config, args);
6080
+ const component = await contentfulClient.component.create(
6081
+ { spaceId: args.spaceId, environmentId: args.environmentId },
6082
+ {
6083
+ name: args.name,
6084
+ description: args.description,
6085
+ viewports: args.viewports,
6086
+ contentProperties: args.contentProperties,
6087
+ designProperties: args.designProperties,
6088
+ ...args.componentTree && { componentTree: args.componentTree },
6089
+ ...args.slots && { slots: args.slots },
6090
+ ...args.metadata && { metadata: args.metadata }
6091
+ }
6092
+ );
6093
+ return createSuccessResponse("Component created successfully", {
6094
+ component
6095
+ });
5842
6096
  }
5843
- /**
5844
- * Get environment tools
5845
- */
5846
- getEnvironmentTools() {
5847
- return createEnvironmentTools(this.config);
6097
+ return withErrorHandling(tool2, "Error creating component");
6098
+ }
6099
+
6100
+ // src/tools/exo/components/upsertComponent.ts
6101
+ import { z as z87 } from "zod";
6102
+ var UpsertComponentToolParams = BaseToolSchema.extend({
6103
+ componentId: z87.string().describe("The ID of the component to update"),
6104
+ version: z87.number().describe(
6105
+ "REQUIRED. The component's sys.version as returned by get_component. You must call get_component first to read the current state and version. The update is rejected if this does not match the current version, which means the component changed since you read it."
6106
+ ),
6107
+ name: z87.string().optional().describe("The name of the component"),
6108
+ description: z87.string().optional().describe("Description of the component"),
6109
+ viewports: z87.array(ViewportSchema).optional().describe("Viewport definitions; replaces existing viewports if provided"),
6110
+ contentProperties: z87.array(ContentPropertySchema).optional().describe("Content property definitions; replaces existing if provided"),
6111
+ designProperties: z87.array(DesignPropertySchema).optional().describe("Design property definitions; replaces existing if provided"),
6112
+ componentTree: z87.array(TreeNodeSchema).optional().describe("Component tree node definitions; replaces existing if provided"),
6113
+ slots: z87.array(SlotDefinitionSchema).optional().describe("Slot definitions; replaces existing if provided"),
6114
+ metadata: ExoMetadataSchema.optional().describe(
6115
+ "ExO metadata (tags, concepts); replaces existing if provided"
6116
+ )
6117
+ });
6118
+ function upsertComponentTool(config) {
6119
+ async function tool2(args) {
6120
+ assertEnvironmentNotProtected(
6121
+ args.environmentId,
6122
+ config.protectedEnvironments
6123
+ );
6124
+ const params = {
6125
+ spaceId: args.spaceId,
6126
+ environmentId: args.environmentId,
6127
+ componentId: args.componentId
6128
+ };
6129
+ const contentfulClient = createToolClient(config, args);
6130
+ const current = await contentfulClient.component.get(params);
6131
+ if (args.version !== current.sys.version) {
6132
+ throw new Error(
6133
+ `Version conflict: the component has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the component with get_component and retry the update with the latest sys.version.`
6134
+ );
6135
+ }
6136
+ const component = await contentfulClient.component.upsert(params, {
6137
+ sys: {
6138
+ id: current.sys.id,
6139
+ type: "Component",
6140
+ version: current.sys.version
6141
+ },
6142
+ name: args.name ?? current.name,
6143
+ description: args.description ?? current.description,
6144
+ viewports: args.viewports ?? current.viewports,
6145
+ contentProperties: args.contentProperties ?? current.contentProperties,
6146
+ designProperties: args.designProperties ?? current.designProperties,
6147
+ ...args.componentTree ?? current.componentTree ? { componentTree: args.componentTree ?? current.componentTree } : {},
6148
+ ...args.slots ?? current.slots ? { slots: args.slots ?? current.slots } : {},
6149
+ ...args.metadata ?? current.metadata ? { metadata: args.metadata ?? current.metadata } : {},
6150
+ ...current.dataAssemblies ? { dataAssemblies: current.dataAssemblies } : {}
6151
+ });
6152
+ return createSuccessResponse("Component updated successfully", {
6153
+ component
6154
+ });
5848
6155
  }
5849
- /**
5850
- * Get locale tools
5851
- */
5852
- getLocaleTools() {
5853
- return createLocaleTools(this.config);
6156
+ return withErrorHandling(tool2, "Error updating component");
6157
+ }
6158
+
6159
+ // src/tools/exo/components/deleteComponent.ts
6160
+ import { z as z88 } from "zod";
6161
+ var DeleteComponentToolParams = BaseToolSchema.extend({
6162
+ componentId: z88.string().describe("The ID of the component to delete"),
6163
+ confirm: z88.boolean().optional().describe(
6164
+ "Set to true on the second call to actually perform the deletion. Required together with confirmToken."
6165
+ ),
6166
+ confirmToken: z88.string().optional().describe(
6167
+ "Token returned by the preview call; must be supplied with confirm: true."
6168
+ )
6169
+ });
6170
+ function deleteComponentTool(config) {
6171
+ async function tool2(args) {
6172
+ assertEnvironmentNotProtected(
6173
+ args.environmentId,
6174
+ config.protectedEnvironments
6175
+ );
6176
+ const params = {
6177
+ spaceId: args.spaceId,
6178
+ environmentId: args.environmentId,
6179
+ componentId: args.componentId
6180
+ };
6181
+ const contentfulClient = createToolClient(config, args);
6182
+ const component = await contentfulClient.component.get(params);
6183
+ const expectedToken = buildConfirmToken(
6184
+ "component",
6185
+ args.componentId,
6186
+ component.sys.version
6187
+ );
6188
+ if (args.confirm !== true || args.confirmToken !== expectedToken) {
6189
+ return createSuccessResponse(
6190
+ `${CONFIRMATION_MESSAGE_PREFIX} component`,
6191
+ buildConfirmationPreview(
6192
+ "component",
6193
+ args.componentId,
6194
+ { component },
6195
+ expectedToken
6196
+ )
6197
+ );
6198
+ }
6199
+ await contentfulClient.component.delete(params);
6200
+ return createSuccessResponse("Component deleted successfully", {
6201
+ componentId: args.componentId
6202
+ });
5854
6203
  }
5855
- /**
5856
- * Get organization tools
5857
- */
5858
- getOrgTools() {
5859
- return createOrgTools(this.config);
6204
+ return withErrorHandling(tool2, "Error deleting component");
6205
+ }
6206
+
6207
+ // src/tools/exo/components/publishComponent.ts
6208
+ import { z as z89 } from "zod";
6209
+ var PublishComponentToolParams = BaseToolSchema.extend({
6210
+ componentId: z89.string().describe("The ID of the component to publish"),
6211
+ version: z89.number().describe(
6212
+ "REQUIRED. The component's sys.version as returned by get_component. You must call get_component first to read the current state and version. The publish is rejected if this does not match the current version, which means the component changed since you read it."
6213
+ )
6214
+ });
6215
+ function publishComponentTool(config) {
6216
+ async function tool2(args) {
6217
+ assertEnvironmentNotProtected(
6218
+ args.environmentId,
6219
+ config.protectedEnvironments
6220
+ );
6221
+ const params = {
6222
+ spaceId: args.spaceId,
6223
+ environmentId: args.environmentId,
6224
+ componentId: args.componentId
6225
+ };
6226
+ const contentfulClient = createToolClient(config, args);
6227
+ const current = await contentfulClient.component.get(params);
6228
+ if (args.version !== current.sys.version) {
6229
+ throw new Error(
6230
+ `Version conflict: the component has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the component with get_component and retry with the latest sys.version.`
6231
+ );
6232
+ }
6233
+ const component = await contentfulClient.component.publish({
6234
+ ...params,
6235
+ version: args.version
6236
+ });
6237
+ return createSuccessResponse("Component published successfully", {
6238
+ component
6239
+ });
5860
6240
  }
5861
- /**
5862
- * Get space tools
5863
- */
5864
- getSpaceTools() {
5865
- return createSpaceTools(this.config);
6241
+ return withErrorHandling(tool2, "Error publishing component");
6242
+ }
6243
+
6244
+ // src/tools/exo/components/unpublishComponent.ts
6245
+ import { z as z90 } from "zod";
6246
+ var UnpublishComponentToolParams = BaseToolSchema.extend({
6247
+ componentId: z90.string().describe("The ID of the component to unpublish"),
6248
+ version: z90.number().describe(
6249
+ "REQUIRED. The component's sys.version as returned by get_component. You must call get_component first to read the current state and version. The unpublish is rejected if this does not match the current version, which means the component changed since you read it."
6250
+ )
6251
+ });
6252
+ function unpublishComponentTool(config) {
6253
+ async function tool2(args) {
6254
+ assertEnvironmentNotProtected(
6255
+ args.environmentId,
6256
+ config.protectedEnvironments
6257
+ );
6258
+ const params = {
6259
+ spaceId: args.spaceId,
6260
+ environmentId: args.environmentId,
6261
+ componentId: args.componentId
6262
+ };
6263
+ const contentfulClient = createToolClient(config, args);
6264
+ const current = await contentfulClient.component.get(params);
6265
+ if (args.version !== current.sys.version) {
6266
+ throw new Error(
6267
+ `Version conflict: the component has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the component with get_component and retry with the latest sys.version.`
6268
+ );
6269
+ }
6270
+ const component = await contentfulClient.component.unpublish({
6271
+ ...params,
6272
+ version: args.version
6273
+ });
6274
+ return createSuccessResponse("Component unpublished successfully", {
6275
+ component
6276
+ });
5866
6277
  }
5867
- /**
6278
+ return withErrorHandling(tool2, "Error unpublishing component");
6279
+ }
6280
+
6281
+ // src/tools/exo/components/register.ts
6282
+ function createComponentTools(config) {
6283
+ const getComponent = getComponentTool(config);
6284
+ const listComponents = listComponentsTool(config);
6285
+ const createComponent = createComponentTool(config);
6286
+ const upsertComponent = upsertComponentTool(config);
6287
+ const deleteComponent = deleteComponentTool(config);
6288
+ const publishComponent = publishComponentTool(config);
6289
+ const unpublishComponent = unpublishComponentTool(config);
6290
+ return {
6291
+ getComponent: {
6292
+ title: "get_component",
6293
+ description: "Get details about a specific ExO component (a reusable section/pattern template defining slots, content properties, and design properties).",
6294
+ inputParams: GetComponentToolParams.shape,
6295
+ annotations: {
6296
+ readOnlyHint: true,
6297
+ destructiveHint: false,
6298
+ openWorldHint: false
6299
+ },
6300
+ tool: getComponent
6301
+ },
6302
+ listComponents: {
6303
+ title: "list_components",
6304
+ description: "List ExO components in a space and environment. Returns a maximum of 10 items per request; use the pageNext cursor (returned in pages.next) to paginate.",
6305
+ inputParams: ListComponentsToolParams.shape,
6306
+ annotations: {
6307
+ readOnlyHint: true,
6308
+ destructiveHint: false,
6309
+ openWorldHint: false
6310
+ },
6311
+ tool: listComponents
6312
+ },
6313
+ createComponent: {
6314
+ title: "create_component",
6315
+ description: "Create a new ExO component.",
6316
+ inputParams: CreateComponentToolParams.shape,
6317
+ annotations: {
6318
+ readOnlyHint: false,
6319
+ destructiveHint: false,
6320
+ idempotentHint: false,
6321
+ openWorldHint: false
6322
+ },
6323
+ tool: createComponent
6324
+ },
6325
+ upsertComponent: {
6326
+ title: "upsert_component",
6327
+ description: "Update an existing ExO component. You MUST call get_component first to read the current state, then pass the sys.version you received as the version parameter. The handler merges your updates with the existing component fields, so you only need to provide the fields you want to change. If the version is stale (the component changed since you read it), the update is rejected and you must re-fetch with get_component.",
6328
+ inputParams: UpsertComponentToolParams.shape,
6329
+ annotations: {
6330
+ readOnlyHint: false,
6331
+ destructiveHint: false,
6332
+ idempotentHint: false,
6333
+ openWorldHint: false
6334
+ },
6335
+ tool: upsertComponent
6336
+ },
6337
+ deleteComponent: {
6338
+ title: "delete_component",
6339
+ description: "Delete an ExO component. Two-phase: the first call (without confirm/confirmToken) returns a preview and a confirmToken. To complete the deletion, call again with the same componentId, confirm: true, and the confirmToken from the preview.",
6340
+ inputParams: DeleteComponentToolParams.shape,
6341
+ annotations: {
6342
+ readOnlyHint: false,
6343
+ destructiveHint: true,
6344
+ idempotentHint: false,
6345
+ openWorldHint: false
6346
+ },
6347
+ tool: deleteComponent
6348
+ },
6349
+ publishComponent: {
6350
+ title: "publish_component",
6351
+ description: "Publish an ExO component. You MUST call get_component first and pass the returned sys.version as the version parameter. If the version is stale the operation is rejected and you must re-fetch with get_component.",
6352
+ inputParams: PublishComponentToolParams.shape,
6353
+ annotations: {
6354
+ readOnlyHint: false,
6355
+ destructiveHint: true,
6356
+ idempotentHint: true,
6357
+ openWorldHint: false
6358
+ },
6359
+ tool: publishComponent
6360
+ },
6361
+ unpublishComponent: {
6362
+ title: "unpublish_component",
6363
+ description: "Unpublish an ExO component. You MUST call get_component first and pass the returned sys.version as the version parameter. If the version is stale the operation is rejected and you must re-fetch with get_component.",
6364
+ inputParams: UnpublishComponentToolParams.shape,
6365
+ annotations: {
6366
+ readOnlyHint: false,
6367
+ destructiveHint: true,
6368
+ idempotentHint: true,
6369
+ openWorldHint: false
6370
+ },
6371
+ tool: unpublishComponent
6372
+ }
6373
+ };
6374
+ }
6375
+
6376
+ // src/tools/exo/experience-fragments/getExperienceFragment.ts
6377
+ import { z as z91 } from "zod";
6378
+ var GetExperienceFragmentToolParams = BaseToolSchema.extend({
6379
+ experienceFragmentId: z91.string().describe("The ID of the experience fragment to retrieve details for")
6380
+ });
6381
+ function getExperienceFragmentTool(config) {
6382
+ async function tool2(args) {
6383
+ const contentfulClient = createToolClient(config, args);
6384
+ const experienceFragment = await contentfulClient.experienceFragment.get({
6385
+ spaceId: args.spaceId,
6386
+ environmentId: args.environmentId,
6387
+ experienceFragmentId: args.experienceFragmentId
6388
+ });
6389
+ return createSuccessResponse("Experience fragment retrieved successfully", {
6390
+ experienceFragment
6391
+ });
6392
+ }
6393
+ return withErrorHandling(tool2, "Error retrieving experience fragment");
6394
+ }
6395
+
6396
+ // src/tools/exo/experience-fragments/listExperienceFragments.ts
6397
+ import { z as z92 } from "zod";
6398
+ var ListExperienceFragmentsToolParams = BaseToolSchema.extend({
6399
+ limit: z92.number().optional().describe("Maximum number of experience fragments to return (max 10)"),
6400
+ pageNext: z92.string().optional().describe("Cursor token to fetch the next page of results"),
6401
+ pagePrev: z92.string().optional().describe("Cursor token to fetch the previous page of results"),
6402
+ order: z92.string().optional().describe("Order experience fragments by this field (e.g. sys.createdAt)")
6403
+ });
6404
+ function listExperienceFragmentsTool(config) {
6405
+ async function tool2(args) {
6406
+ const contentfulClient = createToolClient(config, args);
6407
+ const experienceFragments = await contentfulClient.experienceFragment.getMany({
6408
+ spaceId: args.spaceId,
6409
+ environmentId: args.environmentId,
6410
+ query: {
6411
+ limit: Math.min(args.limit || 10, 10),
6412
+ ...args.pageNext && { pageNext: args.pageNext },
6413
+ ...args.pagePrev && { pagePrev: args.pagePrev },
6414
+ ...args.order && { order: args.order }
6415
+ }
6416
+ });
6417
+ const summarized = summarizeData(experienceFragments, {
6418
+ maxItems: 10,
6419
+ remainingMessage: "To see more experience fragments, ask me to retrieve the next page using the pageNext cursor."
6420
+ });
6421
+ return createSuccessResponse("ExperienceFragments retrieved successfully", {
6422
+ experienceFragments: summarized,
6423
+ total: experienceFragments.total,
6424
+ limit: experienceFragments.limit,
6425
+ pages: experienceFragments.pages
6426
+ });
6427
+ }
6428
+ return withErrorHandling(tool2, "Error listing experience fragments");
6429
+ }
6430
+
6431
+ // src/tools/exo/experience-fragments/createExperienceFragment.ts
6432
+ import { z as z93 } from "zod";
6433
+ var CreateExperienceFragmentToolParams = BaseToolSchema.extend({
6434
+ name: z93.string().describe("The name of the experience fragment"),
6435
+ description: z93.string().describe("Description of the experience fragment"),
6436
+ component: ComponentResourceLinkSchema.describe(
6437
+ "Resource link to the component this experience fragment is based on"
6438
+ ),
6439
+ viewports: z93.array(ViewportSchema).describe("Viewport definitions (may be empty)"),
6440
+ designProperties: z93.record(z93.string(), DimensionedDesignPropertyValueSchema).describe(
6441
+ "Design property values keyed by property ID (may be empty object)"
6442
+ ),
6443
+ contentBindings: ExperienceContentBindingsSchema.optional().describe(
6444
+ "Optional content bindings for the experience fragment"
6445
+ ),
6446
+ slots: z93.record(z93.string(), z93.array(ExperienceSlotNodeSchema)).optional().describe("Optional slot node definitions keyed by slot ID"),
6447
+ metadata: ExperienceMetadataSchema.optional().describe(
6448
+ "Optional ExO metadata (tags, concepts)"
6449
+ )
6450
+ });
6451
+ function createExperienceFragmentTool(config) {
6452
+ async function tool2(args) {
6453
+ assertEnvironmentNotProtected(
6454
+ args.environmentId,
6455
+ config.protectedEnvironments
6456
+ );
6457
+ const contentfulClient = createToolClient(config, args);
6458
+ const experienceFragment = await contentfulClient.experienceFragment.create(
6459
+ { spaceId: args.spaceId, environmentId: args.environmentId },
6460
+ {
6461
+ name: args.name,
6462
+ description: args.description,
6463
+ component: args.component,
6464
+ viewports: args.viewports,
6465
+ designProperties: args.designProperties,
6466
+ ...args.contentBindings && { contentBindings: args.contentBindings },
6467
+ ...args.slots && { slots: args.slots },
6468
+ ...args.metadata && { metadata: args.metadata }
6469
+ }
6470
+ );
6471
+ return createSuccessResponse("Experience fragment created successfully", {
6472
+ experienceFragment
6473
+ });
6474
+ }
6475
+ return withErrorHandling(tool2, "Error creating experience fragment");
6476
+ }
6477
+
6478
+ // src/tools/exo/experience-fragments/updateExperienceFragment.ts
6479
+ import { z as z94 } from "zod";
6480
+ var UpdateExperienceFragmentToolParams = BaseToolSchema.extend({
6481
+ experienceFragmentId: z94.string().describe("The ID of the experience fragment to update"),
6482
+ version: z94.number().describe(
6483
+ "REQUIRED. The experience fragment's sys.version as returned by get_experience_fragment. You must call get_experience_fragment first to read the current state and version. The update is rejected if this does not match the current version, which means the experience fragment changed since you read it."
6484
+ ),
6485
+ name: z94.string().optional().describe("The name of the experience fragment"),
6486
+ description: z94.string().optional().describe("Description of the experience fragment"),
6487
+ viewports: z94.array(ViewportSchema).optional().describe("Viewport definitions; replaces existing viewports if provided"),
6488
+ designProperties: z94.record(z94.string(), DimensionedDesignPropertyValueSchema).optional().describe("Design property values; replaces existing if provided"),
6489
+ contentBindings: ExperienceContentBindingsSchema.optional().describe(
6490
+ "Content bindings; replaces existing if provided"
6491
+ ),
6492
+ slots: z94.record(z94.string(), z94.array(ExperienceSlotNodeSchema)).optional().describe("Slot node definitions; replaces existing if provided"),
6493
+ metadata: ExperienceMetadataSchema.optional().describe(
6494
+ "ExO metadata (tags, concepts); replaces existing if provided"
6495
+ )
6496
+ });
6497
+ function updateExperienceFragmentTool(config) {
6498
+ async function tool2(args) {
6499
+ assertEnvironmentNotProtected(
6500
+ args.environmentId,
6501
+ config.protectedEnvironments
6502
+ );
6503
+ const params = {
6504
+ spaceId: args.spaceId,
6505
+ environmentId: args.environmentId,
6506
+ experienceFragmentId: args.experienceFragmentId
6507
+ };
6508
+ const contentfulClient = createToolClient(config, args);
6509
+ const current = await contentfulClient.experienceFragment.get(params);
6510
+ if (args.version !== current.sys.version) {
6511
+ throw new Error(
6512
+ `Version conflict: the experience fragment has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the experience fragment with get_experience_fragment and retry the update with the latest sys.version.`
6513
+ );
6514
+ }
6515
+ const experienceFragment = await contentfulClient.experienceFragment.upsert(
6516
+ params,
6517
+ {
6518
+ sys: {
6519
+ id: current.sys.id,
6520
+ type: "ExperienceFragment",
6521
+ version: current.sys.version
6522
+ },
6523
+ name: args.name ?? current.name,
6524
+ description: args.description ?? current.description,
6525
+ viewports: args.viewports ?? current.viewports,
6526
+ designProperties: args.designProperties ?? current.designProperties,
6527
+ ...args.contentBindings ?? current.contentBindings ? { contentBindings: args.contentBindings ?? current.contentBindings } : {},
6528
+ ...args.slots ?? current.slots ? { slots: args.slots ?? current.slots } : {},
6529
+ ...args.metadata ?? current.metadata ? { metadata: args.metadata ?? current.metadata } : {}
6530
+ }
6531
+ );
6532
+ return createSuccessResponse("Experience fragment updated successfully", {
6533
+ experienceFragment
6534
+ });
6535
+ }
6536
+ return withErrorHandling(tool2, "Error updating experience fragment");
6537
+ }
6538
+
6539
+ // src/tools/exo/experience-fragments/deleteExperienceFragment.ts
6540
+ import { z as z95 } from "zod";
6541
+ var DeleteExperienceFragmentToolParams = BaseToolSchema.extend({
6542
+ experienceFragmentId: z95.string().describe("The ID of the experience fragment to delete"),
6543
+ confirm: z95.boolean().optional().describe(
6544
+ "Set to true on the second call to actually perform the deletion. Required together with confirmToken."
6545
+ ),
6546
+ confirmToken: z95.string().optional().describe(
6547
+ "Token returned by the preview call; must be supplied with confirm: true."
6548
+ )
6549
+ });
6550
+ function deleteExperienceFragmentTool(config) {
6551
+ async function tool2(args) {
6552
+ assertEnvironmentNotProtected(
6553
+ args.environmentId,
6554
+ config.protectedEnvironments
6555
+ );
6556
+ const params = {
6557
+ spaceId: args.spaceId,
6558
+ environmentId: args.environmentId,
6559
+ experienceFragmentId: args.experienceFragmentId
6560
+ };
6561
+ const contentfulClient = createToolClient(config, args);
6562
+ const experienceFragment = await contentfulClient.experienceFragment.get(params);
6563
+ const expectedToken = buildConfirmToken(
6564
+ "experienceFragment",
6565
+ args.experienceFragmentId,
6566
+ experienceFragment.sys.version
6567
+ );
6568
+ if (args.confirm !== true || args.confirmToken !== expectedToken) {
6569
+ return createSuccessResponse(
6570
+ `${CONFIRMATION_MESSAGE_PREFIX} experience fragment`,
6571
+ buildConfirmationPreview(
6572
+ "experienceFragment",
6573
+ args.experienceFragmentId,
6574
+ { experienceFragment },
6575
+ expectedToken
6576
+ )
6577
+ );
6578
+ }
6579
+ await contentfulClient.experienceFragment.delete(params);
6580
+ return createSuccessResponse("Experience fragment deleted successfully", {
6581
+ experienceFragmentId: args.experienceFragmentId
6582
+ });
6583
+ }
6584
+ return withErrorHandling(tool2, "Error deleting experience fragment");
6585
+ }
6586
+
6587
+ // src/tools/exo/experience-fragments/publishExperienceFragment.ts
6588
+ import { z as z96 } from "zod";
6589
+ var PublishExperienceFragmentToolParams = BaseToolSchema.extend({
6590
+ experienceFragmentId: z96.string().describe("The ID of the experience fragment to publish"),
6591
+ version: z96.number().describe(
6592
+ "REQUIRED. The experience fragment's sys.version as returned by get_experience_fragment. You must call get_experience_fragment first to read the current state and version. The publish is rejected if this does not match the current version, which means the experience fragment changed since you read it."
6593
+ )
6594
+ });
6595
+ function publishExperienceFragmentTool(config) {
6596
+ async function tool2(args) {
6597
+ assertEnvironmentNotProtected(
6598
+ args.environmentId,
6599
+ config.protectedEnvironments
6600
+ );
6601
+ const params = {
6602
+ spaceId: args.spaceId,
6603
+ environmentId: args.environmentId,
6604
+ experienceFragmentId: args.experienceFragmentId
6605
+ };
6606
+ const contentfulClient = createToolClient(config, args);
6607
+ const current = await contentfulClient.experienceFragment.get(params);
6608
+ if (args.version !== current.sys.version) {
6609
+ throw new Error(
6610
+ `Version conflict: the experience fragment has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the experience fragment with get_experience_fragment and retry with the latest sys.version.`
6611
+ );
6612
+ }
6613
+ const experienceFragment = await contentfulClient.experienceFragment.publish({
6614
+ ...params,
6615
+ version: args.version
6616
+ });
6617
+ return createSuccessResponse("Experience fragment published successfully", {
6618
+ experienceFragment
6619
+ });
6620
+ }
6621
+ return withErrorHandling(tool2, "Error publishing experience fragment");
6622
+ }
6623
+
6624
+ // src/tools/exo/experience-fragments/unpublishExperienceFragment.ts
6625
+ import { z as z97 } from "zod";
6626
+ var UnpublishExperienceFragmentToolParams = BaseToolSchema.extend({
6627
+ experienceFragmentId: z97.string().describe("The ID of the experience fragment to unpublish"),
6628
+ version: z97.number().describe(
6629
+ "REQUIRED. The experience fragment's sys.version as returned by get_experience_fragment. You must call get_experience_fragment first to read the current state and version. The unpublish is rejected if this does not match the current version, which means the experience fragment changed since you read it."
6630
+ )
6631
+ });
6632
+ function unpublishExperienceFragmentTool(config) {
6633
+ async function tool2(args) {
6634
+ assertEnvironmentNotProtected(
6635
+ args.environmentId,
6636
+ config.protectedEnvironments
6637
+ );
6638
+ const params = {
6639
+ spaceId: args.spaceId,
6640
+ environmentId: args.environmentId,
6641
+ experienceFragmentId: args.experienceFragmentId
6642
+ };
6643
+ const contentfulClient = createToolClient(config, args);
6644
+ const current = await contentfulClient.experienceFragment.get(params);
6645
+ if (args.version !== current.sys.version) {
6646
+ throw new Error(
6647
+ `Version conflict: the experience fragment has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the experience fragment with get_experience_fragment and retry with the latest sys.version.`
6648
+ );
6649
+ }
6650
+ const experienceFragment = await contentfulClient.experienceFragment.unpublish({
6651
+ ...params,
6652
+ version: args.version
6653
+ });
6654
+ return createSuccessResponse(
6655
+ "Experience fragment unpublished successfully",
6656
+ {
6657
+ experienceFragment
6658
+ }
6659
+ );
6660
+ }
6661
+ return withErrorHandling(tool2, "Error unpublishing experience fragment");
6662
+ }
6663
+
6664
+ // src/tools/exo/experience-fragments/register.ts
6665
+ function createExperienceFragmentTools(config) {
6666
+ const getExperienceFragment = getExperienceFragmentTool(config);
6667
+ const listExperienceFragments = listExperienceFragmentsTool(config);
6668
+ const createExperienceFragment = createExperienceFragmentTool(config);
6669
+ const updateExperienceFragment = updateExperienceFragmentTool(config);
6670
+ const deleteExperienceFragment = deleteExperienceFragmentTool(config);
6671
+ const publishExperienceFragment = publishExperienceFragmentTool(config);
6672
+ const unpublishExperienceFragment = unpublishExperienceFragmentTool(config);
6673
+ return {
6674
+ getExperienceFragment: {
6675
+ title: "get_experience_fragment",
6676
+ description: "Get details about a specific ExO experience fragment (a reusable content unit that can be referenced across multiple Experiences and Components).",
6677
+ inputParams: GetExperienceFragmentToolParams.shape,
6678
+ annotations: {
6679
+ readOnlyHint: true,
6680
+ destructiveHint: false,
6681
+ openWorldHint: false
6682
+ },
6683
+ tool: getExperienceFragment
6684
+ },
6685
+ listExperienceFragments: {
6686
+ title: "list_experience_fragments",
6687
+ description: "List ExO experience fragments in a space and environment. Returns a maximum of 10 items per request; use the pageNext cursor (returned in pages.next) to paginate.",
6688
+ inputParams: ListExperienceFragmentsToolParams.shape,
6689
+ annotations: {
6690
+ readOnlyHint: true,
6691
+ destructiveHint: false,
6692
+ openWorldHint: false
6693
+ },
6694
+ tool: listExperienceFragments
6695
+ },
6696
+ createExperienceFragment: {
6697
+ title: "create_experience_fragment",
6698
+ description: "Create a new ExO experience fragment.",
6699
+ inputParams: CreateExperienceFragmentToolParams.shape,
6700
+ annotations: {
6701
+ readOnlyHint: false,
6702
+ destructiveHint: false,
6703
+ idempotentHint: false,
6704
+ openWorldHint: false
6705
+ },
6706
+ tool: createExperienceFragment
6707
+ },
6708
+ updateExperienceFragment: {
6709
+ title: "update_experience_fragment",
6710
+ description: "Update an existing ExO experience fragment. You MUST call get_experience_fragment first to read the current state, then pass the sys.version you received as the version parameter. The handler merges your updates with the existing experience fragment fields, so you only need to provide the fields you want to change. If the version is stale (the experience fragment changed since you read it), the update is rejected and you must re-fetch with get_experience_fragment.",
6711
+ inputParams: UpdateExperienceFragmentToolParams.shape,
6712
+ annotations: {
6713
+ readOnlyHint: false,
6714
+ destructiveHint: false,
6715
+ idempotentHint: false,
6716
+ openWorldHint: false
6717
+ },
6718
+ tool: updateExperienceFragment
6719
+ },
6720
+ deleteExperienceFragment: {
6721
+ title: "delete_experience_fragment",
6722
+ description: "Delete an ExO experience fragment. Two-phase: the first call (without confirm/confirmToken) returns a preview and a confirmToken. To complete the deletion, call again with the same experienceFragmentId, confirm: true, and the confirmToken from the preview.",
6723
+ inputParams: DeleteExperienceFragmentToolParams.shape,
6724
+ annotations: {
6725
+ readOnlyHint: false,
6726
+ destructiveHint: true,
6727
+ idempotentHint: false,
6728
+ openWorldHint: false
6729
+ },
6730
+ tool: deleteExperienceFragment
6731
+ },
6732
+ publishExperienceFragment: {
6733
+ title: "publish_experience_fragment",
6734
+ description: "Publish an ExO experience fragment. You MUST call get_experience_fragment first and pass the returned sys.version as the version parameter. If the version is stale the operation is rejected and you must re-fetch with get_experience_fragment.",
6735
+ inputParams: PublishExperienceFragmentToolParams.shape,
6736
+ annotations: {
6737
+ readOnlyHint: false,
6738
+ destructiveHint: true,
6739
+ idempotentHint: true,
6740
+ openWorldHint: false
6741
+ },
6742
+ tool: publishExperienceFragment
6743
+ },
6744
+ unpublishExperienceFragment: {
6745
+ title: "unpublish_experience_fragment",
6746
+ description: "Unpublish an ExO experience fragment. You MUST call get_experience_fragment first and pass the returned sys.version as the version parameter. If the version is stale the operation is rejected and you must re-fetch with get_experience_fragment.",
6747
+ inputParams: UnpublishExperienceFragmentToolParams.shape,
6748
+ annotations: {
6749
+ readOnlyHint: false,
6750
+ destructiveHint: true,
6751
+ idempotentHint: true,
6752
+ openWorldHint: false
6753
+ },
6754
+ tool: unpublishExperienceFragment
6755
+ }
6756
+ };
6757
+ }
6758
+
6759
+ // src/tools/exo/experience-templates/getExperienceTemplate.ts
6760
+ import { z as z98 } from "zod";
6761
+ var GetExperienceTemplateToolParams = BaseToolSchema.extend({
6762
+ experienceTemplateId: z98.string().describe("The ID of the experience template to retrieve details for")
6763
+ });
6764
+ function getExperienceTemplateTool(config) {
6765
+ async function tool2(args) {
6766
+ const contentfulClient = createToolClient(config, args);
6767
+ const experienceTemplate = await contentfulClient.experienceTemplate.get({
6768
+ spaceId: args.spaceId,
6769
+ environmentId: args.environmentId,
6770
+ experienceTemplateId: args.experienceTemplateId
6771
+ });
6772
+ return createSuccessResponse("Experience template retrieved successfully", {
6773
+ experienceTemplate
6774
+ });
6775
+ }
6776
+ return withErrorHandling(tool2, "Error retrieving experience template");
6777
+ }
6778
+
6779
+ // src/tools/exo/experience-templates/listExperienceTemplates.ts
6780
+ import { z as z99 } from "zod";
6781
+ var ListExperienceTemplatesToolParams = BaseToolSchema.extend({
6782
+ limit: z99.number().optional().describe("Maximum number of experience templates to return (max 10)"),
6783
+ pageNext: z99.string().optional().describe("Cursor token to fetch the next page of results"),
6784
+ pagePrev: z99.string().optional().describe("Cursor token to fetch the previous page of results"),
6785
+ order: z99.string().optional().describe("Order experience templates by this field (e.g. sys.createdAt)")
6786
+ });
6787
+ function listExperienceTemplatesTool(config) {
6788
+ async function tool2(args) {
6789
+ const contentfulClient = createToolClient(config, args);
6790
+ const experienceTemplates = await contentfulClient.experienceTemplate.getMany({
6791
+ spaceId: args.spaceId,
6792
+ environmentId: args.environmentId,
6793
+ query: {
6794
+ limit: Math.min(args.limit || 10, 10),
6795
+ ...args.pageNext && { pageNext: args.pageNext },
6796
+ ...args.pagePrev && { pagePrev: args.pagePrev },
6797
+ ...args.order && { order: args.order }
6798
+ }
6799
+ });
6800
+ const summarized = summarizeData(experienceTemplates, {
6801
+ maxItems: 10,
6802
+ remainingMessage: "To see more experience templates, ask me to retrieve the next page using the pageNext cursor."
6803
+ });
6804
+ return createSuccessResponse("ExperienceTemplates retrieved successfully", {
6805
+ experienceTemplates: summarized,
6806
+ total: experienceTemplates.total,
6807
+ limit: experienceTemplates.limit,
6808
+ pages: experienceTemplates.pages
6809
+ });
6810
+ }
6811
+ return withErrorHandling(tool2, "Error listing experience templates");
6812
+ }
6813
+
6814
+ // src/tools/exo/experience-templates/createExperienceTemplate.ts
6815
+ import { z as z100 } from "zod";
6816
+ var CreateExperienceTemplateToolParams = BaseToolSchema.extend({
6817
+ name: z100.string().describe("The name of the experience template"),
6818
+ description: z100.string().describe("Description of the experience template"),
6819
+ viewports: z100.array(ViewportSchema).describe(
6820
+ "Viewport definitions for the experience template (may be empty)"
6821
+ ),
6822
+ contentProperties: z100.array(ContentPropertySchema).describe("Content property definitions (may be empty)"),
6823
+ designProperties: z100.array(DesignPropertySchema).describe("Design property definitions (may be empty)"),
6824
+ componentTree: z100.array(TreeNodeSchema).optional().describe("Optional component tree node definitions"),
6825
+ slots: z100.array(SlotDefinitionSchema).optional().describe("Optional slot definitions"),
6826
+ metadata: ExoMetadataSchema.optional().describe(
6827
+ "Optional ExO metadata (tags, concepts)"
6828
+ )
6829
+ });
6830
+ function createExperienceTemplateTool(config) {
6831
+ async function tool2(args) {
6832
+ assertEnvironmentNotProtected(
6833
+ args.environmentId,
6834
+ config.protectedEnvironments
6835
+ );
6836
+ const contentfulClient = createToolClient(config, args);
6837
+ const experienceTemplate = await contentfulClient.experienceTemplate.create(
6838
+ { spaceId: args.spaceId, environmentId: args.environmentId },
6839
+ {
6840
+ name: args.name,
6841
+ description: args.description,
6842
+ viewports: args.viewports,
6843
+ contentProperties: args.contentProperties,
6844
+ designProperties: args.designProperties,
6845
+ ...args.componentTree && { componentTree: args.componentTree },
6846
+ ...args.slots && { slots: args.slots },
6847
+ ...args.metadata && { metadata: args.metadata }
6848
+ }
6849
+ );
6850
+ return createSuccessResponse("Experience template created successfully", {
6851
+ experienceTemplate
6852
+ });
6853
+ }
6854
+ return withErrorHandling(tool2, "Error creating experience template");
6855
+ }
6856
+
6857
+ // src/tools/exo/experience-templates/upsertExperienceTemplate.ts
6858
+ import { z as z101 } from "zod";
6859
+ var UpsertExperienceTemplateToolParams = BaseToolSchema.extend({
6860
+ experienceTemplateId: z101.string().describe("The ID of the experience template to update"),
6861
+ version: z101.number().describe(
6862
+ "REQUIRED. The experience template's sys.version as returned by get_experience_template. You must call get_experience_template first to read the current state and version. The update is rejected if this does not match the current version, which means the experience template changed since you read it."
6863
+ ),
6864
+ name: z101.string().optional().describe("The name of the experience template"),
6865
+ description: z101.string().optional().describe("Description of the experience template"),
6866
+ viewports: z101.array(ViewportSchema).optional().describe("Viewport definitions; replaces existing viewports if provided"),
6867
+ contentProperties: z101.array(ContentPropertySchema).optional().describe("Content property definitions; replaces existing if provided"),
6868
+ designProperties: z101.array(DesignPropertySchema).optional().describe("Design property definitions; replaces existing if provided"),
6869
+ componentTree: z101.array(TreeNodeSchema).optional().describe("Component tree node definitions; replaces existing if provided"),
6870
+ slots: z101.array(SlotDefinitionSchema).optional().describe("Slot definitions; replaces existing if provided"),
6871
+ metadata: ExoMetadataSchema.optional().describe(
6872
+ "ExO metadata (tags, concepts); replaces existing if provided"
6873
+ )
6874
+ });
6875
+ function upsertExperienceTemplateTool(config) {
6876
+ async function tool2(args) {
6877
+ assertEnvironmentNotProtected(
6878
+ args.environmentId,
6879
+ config.protectedEnvironments
6880
+ );
6881
+ const params = {
6882
+ spaceId: args.spaceId,
6883
+ environmentId: args.environmentId,
6884
+ experienceTemplateId: args.experienceTemplateId
6885
+ };
6886
+ const contentfulClient = createToolClient(config, args);
6887
+ const current = await contentfulClient.experienceTemplate.get(params);
6888
+ if (args.version !== current.sys.version) {
6889
+ throw new Error(
6890
+ `Version conflict: the experience template has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the experience template with get_experience_template and retry the update with the latest sys.version.`
6891
+ );
6892
+ }
6893
+ const experienceTemplate = await contentfulClient.experienceTemplate.upsert(
6894
+ params,
6895
+ {
6896
+ sys: {
6897
+ id: current.sys.id,
6898
+ type: "ExperienceTemplate",
6899
+ version: current.sys.version
6900
+ },
6901
+ name: args.name ?? current.name,
6902
+ description: args.description ?? current.description,
6903
+ viewports: args.viewports ?? current.viewports,
6904
+ contentProperties: args.contentProperties ?? current.contentProperties,
6905
+ designProperties: args.designProperties ?? current.designProperties,
6906
+ ...args.componentTree ?? current.componentTree ? { componentTree: args.componentTree ?? current.componentTree } : {},
6907
+ ...args.slots ?? current.slots ? { slots: args.slots ?? current.slots } : {},
6908
+ ...args.metadata ?? current.metadata ? { metadata: args.metadata ?? current.metadata } : {},
6909
+ ...current.dataAssemblies ? { dataAssemblies: current.dataAssemblies } : {}
6910
+ }
6911
+ );
6912
+ return createSuccessResponse("Experience template updated successfully", {
6913
+ experienceTemplate
6914
+ });
6915
+ }
6916
+ return withErrorHandling(tool2, "Error updating experience template");
6917
+ }
6918
+
6919
+ // src/tools/exo/experience-templates/deleteExperienceTemplate.ts
6920
+ import { z as z102 } from "zod";
6921
+ var DeleteExperienceTemplateToolParams = BaseToolSchema.extend({
6922
+ experienceTemplateId: z102.string().describe("The ID of the experience template to delete"),
6923
+ confirm: z102.boolean().optional().describe(
6924
+ "Set to true on the second call to actually perform the deletion. Required together with confirmToken."
6925
+ ),
6926
+ confirmToken: z102.string().optional().describe(
6927
+ "Token returned by the preview call; must be supplied with confirm: true."
6928
+ )
6929
+ });
6930
+ function deleteExperienceTemplateTool(config) {
6931
+ async function tool2(args) {
6932
+ assertEnvironmentNotProtected(
6933
+ args.environmentId,
6934
+ config.protectedEnvironments
6935
+ );
6936
+ const params = {
6937
+ spaceId: args.spaceId,
6938
+ environmentId: args.environmentId,
6939
+ experienceTemplateId: args.experienceTemplateId
6940
+ };
6941
+ const contentfulClient = createToolClient(config, args);
6942
+ const experienceTemplate = await contentfulClient.experienceTemplate.get(params);
6943
+ const expectedToken = buildConfirmToken(
6944
+ "experienceTemplate",
6945
+ args.experienceTemplateId,
6946
+ experienceTemplate.sys.version
6947
+ );
6948
+ if (args.confirm !== true || args.confirmToken !== expectedToken) {
6949
+ return createSuccessResponse(
6950
+ `${CONFIRMATION_MESSAGE_PREFIX} experience template`,
6951
+ buildConfirmationPreview(
6952
+ "experienceTemplate",
6953
+ args.experienceTemplateId,
6954
+ { experienceTemplate },
6955
+ expectedToken
6956
+ )
6957
+ );
6958
+ }
6959
+ await contentfulClient.experienceTemplate.delete(params);
6960
+ return createSuccessResponse("Experience template deleted successfully", {
6961
+ experienceTemplateId: args.experienceTemplateId
6962
+ });
6963
+ }
6964
+ return withErrorHandling(tool2, "Error deleting experience template");
6965
+ }
6966
+
6967
+ // src/tools/exo/experience-templates/publishExperienceTemplate.ts
6968
+ import { z as z103 } from "zod";
6969
+ var PublishExperienceTemplateToolParams = BaseToolSchema.extend({
6970
+ experienceTemplateId: z103.string().describe("The ID of the experience template to publish"),
6971
+ version: z103.number().describe(
6972
+ "REQUIRED. The experience template's sys.version as returned by get_experience_template. You must call get_experience_template first to read the current state and version. The publish is rejected if this does not match the current version, which means the experience template changed since you read it."
6973
+ )
6974
+ });
6975
+ function publishExperienceTemplateTool(config) {
6976
+ async function tool2(args) {
6977
+ assertEnvironmentNotProtected(
6978
+ args.environmentId,
6979
+ config.protectedEnvironments
6980
+ );
6981
+ const params = {
6982
+ spaceId: args.spaceId,
6983
+ environmentId: args.environmentId,
6984
+ experienceTemplateId: args.experienceTemplateId
6985
+ };
6986
+ const contentfulClient = createToolClient(config, args);
6987
+ const current = await contentfulClient.experienceTemplate.get(params);
6988
+ if (args.version !== current.sys.version) {
6989
+ throw new Error(
6990
+ `Version conflict: the experience template has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the experience template with get_experience_template and retry with the latest sys.version.`
6991
+ );
6992
+ }
6993
+ const experienceTemplate = await contentfulClient.experienceTemplate.publish({
6994
+ ...params,
6995
+ version: args.version
6996
+ });
6997
+ return createSuccessResponse("Experience template published successfully", {
6998
+ experienceTemplate
6999
+ });
7000
+ }
7001
+ return withErrorHandling(tool2, "Error publishing experience template");
7002
+ }
7003
+
7004
+ // src/tools/exo/experience-templates/unpublishExperienceTemplate.ts
7005
+ import { z as z104 } from "zod";
7006
+ var UnpublishExperienceTemplateToolParams = BaseToolSchema.extend({
7007
+ experienceTemplateId: z104.string().describe("The ID of the experience template to unpublish"),
7008
+ version: z104.number().describe(
7009
+ "REQUIRED. The experience template's sys.version as returned by get_experience_template. You must call get_experience_template first to read the current state and version. The unpublish is rejected if this does not match the current version, which means the experience template changed since you read it."
7010
+ )
7011
+ });
7012
+ function unpublishExperienceTemplateTool(config) {
7013
+ async function tool2(args) {
7014
+ assertEnvironmentNotProtected(
7015
+ args.environmentId,
7016
+ config.protectedEnvironments
7017
+ );
7018
+ const params = {
7019
+ spaceId: args.spaceId,
7020
+ environmentId: args.environmentId,
7021
+ experienceTemplateId: args.experienceTemplateId
7022
+ };
7023
+ const contentfulClient = createToolClient(config, args);
7024
+ const current = await contentfulClient.experienceTemplate.get(params);
7025
+ if (args.version !== current.sys.version) {
7026
+ throw new Error(
7027
+ `Version conflict: the experience template has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the experience template with get_experience_template and retry with the latest sys.version.`
7028
+ );
7029
+ }
7030
+ const experienceTemplate = await contentfulClient.experienceTemplate.unpublish({
7031
+ ...params,
7032
+ version: args.version
7033
+ });
7034
+ return createSuccessResponse(
7035
+ "Experience template unpublished successfully",
7036
+ {
7037
+ experienceTemplate
7038
+ }
7039
+ );
7040
+ }
7041
+ return withErrorHandling(tool2, "Error unpublishing experience template");
7042
+ }
7043
+
7044
+ // src/tools/exo/experience-templates/register.ts
7045
+ function createExperienceTemplateTools(config) {
7046
+ const getExperienceTemplate = getExperienceTemplateTool(config);
7047
+ const listExperienceTemplates = listExperienceTemplatesTool(config);
7048
+ const createExperienceTemplate = createExperienceTemplateTool(config);
7049
+ const upsertExperienceTemplate = upsertExperienceTemplateTool(config);
7050
+ const deleteExperienceTemplate = deleteExperienceTemplateTool(config);
7051
+ const publishExperienceTemplate = publishExperienceTemplateTool(config);
7052
+ const unpublishExperienceTemplate = unpublishExperienceTemplateTool(config);
7053
+ return {
7054
+ getExperienceTemplate: {
7055
+ title: "get_experience_template",
7056
+ description: "Get details about a specific ExO experience template (a layout definition that backs experience-template-based Experiences).",
7057
+ inputParams: GetExperienceTemplateToolParams.shape,
7058
+ annotations: {
7059
+ readOnlyHint: true,
7060
+ destructiveHint: false,
7061
+ openWorldHint: false
7062
+ },
7063
+ tool: getExperienceTemplate
7064
+ },
7065
+ listExperienceTemplates: {
7066
+ title: "list_experience_templates",
7067
+ description: "List ExO experience templates in a space and environment. Returns a maximum of 10 items per request; use the pageNext cursor (returned in pages.next) to paginate.",
7068
+ inputParams: ListExperienceTemplatesToolParams.shape,
7069
+ annotations: {
7070
+ readOnlyHint: true,
7071
+ destructiveHint: false,
7072
+ openWorldHint: false
7073
+ },
7074
+ tool: listExperienceTemplates
7075
+ },
7076
+ createExperienceTemplate: {
7077
+ title: "create_experience_template",
7078
+ description: "Create a new ExO experience template.",
7079
+ inputParams: CreateExperienceTemplateToolParams.shape,
7080
+ annotations: {
7081
+ readOnlyHint: false,
7082
+ destructiveHint: false,
7083
+ idempotentHint: false,
7084
+ openWorldHint: false
7085
+ },
7086
+ tool: createExperienceTemplate
7087
+ },
7088
+ upsertExperienceTemplate: {
7089
+ title: "upsert_experience_template",
7090
+ description: "Update an existing ExO experience template. You MUST call get_experience_template first to read the current state, then pass the sys.version you received as the version parameter. The handler merges your updates with the existing experience template fields, so you only need to provide the fields you want to change. If the version is stale (the experience template changed since you read it), the update is rejected and you must re-fetch with get_experience_template.",
7091
+ inputParams: UpsertExperienceTemplateToolParams.shape,
7092
+ annotations: {
7093
+ readOnlyHint: false,
7094
+ destructiveHint: false,
7095
+ idempotentHint: false,
7096
+ openWorldHint: false
7097
+ },
7098
+ tool: upsertExperienceTemplate
7099
+ },
7100
+ deleteExperienceTemplate: {
7101
+ title: "delete_experience_template",
7102
+ description: "Delete an ExO experience template. Two-phase: the first call (without confirm/confirmToken) returns a preview and a confirmToken. To complete the deletion, call again with the same experienceTemplateId, confirm: true, and the confirmToken from the preview.",
7103
+ inputParams: DeleteExperienceTemplateToolParams.shape,
7104
+ annotations: {
7105
+ readOnlyHint: false,
7106
+ destructiveHint: true,
7107
+ idempotentHint: false,
7108
+ openWorldHint: false
7109
+ },
7110
+ tool: deleteExperienceTemplate
7111
+ },
7112
+ publishExperienceTemplate: {
7113
+ title: "publish_experience_template",
7114
+ description: "Publish an ExO experience template. You MUST call get_experience_template first and pass the returned sys.version as the version parameter. If the version is stale the operation is rejected and you must re-fetch with get_experience_template.",
7115
+ inputParams: PublishExperienceTemplateToolParams.shape,
7116
+ annotations: {
7117
+ readOnlyHint: false,
7118
+ destructiveHint: true,
7119
+ idempotentHint: true,
7120
+ openWorldHint: false
7121
+ },
7122
+ tool: publishExperienceTemplate
7123
+ },
7124
+ unpublishExperienceTemplate: {
7125
+ title: "unpublish_experience_template",
7126
+ description: "Unpublish an ExO experience template. You MUST call get_experience_template first and pass the returned sys.version as the version parameter. If the version is stale the operation is rejected and you must re-fetch with get_experience_template.",
7127
+ inputParams: UnpublishExperienceTemplateToolParams.shape,
7128
+ annotations: {
7129
+ readOnlyHint: false,
7130
+ destructiveHint: true,
7131
+ idempotentHint: true,
7132
+ openWorldHint: false
7133
+ },
7134
+ tool: unpublishExperienceTemplate
7135
+ }
7136
+ };
7137
+ }
7138
+
7139
+ // src/tools/exo/experiences/getExperience.ts
7140
+ import { z as z105 } from "zod";
7141
+ var GetExperienceToolParams = BaseToolSchema.extend({
7142
+ experienceId: z105.string().describe("The ID of the experience to retrieve")
7143
+ });
7144
+ function getExperienceTool(config) {
7145
+ async function tool2(args) {
7146
+ const contentfulClient = createToolClient(config, args);
7147
+ const experience = await contentfulClient.experience.get({
7148
+ spaceId: args.spaceId,
7149
+ environmentId: args.environmentId,
7150
+ experienceId: args.experienceId
7151
+ });
7152
+ return createSuccessResponse("Experience retrieved successfully", {
7153
+ experience
7154
+ });
7155
+ }
7156
+ return withErrorHandling(tool2, "Error retrieving experience");
7157
+ }
7158
+
7159
+ // src/tools/exo/experiences/listExperiences.ts
7160
+ import { z as z106 } from "zod";
7161
+ var ListExperiencesToolParams = BaseToolSchema.extend({
7162
+ limit: z106.number().optional().describe("Maximum number of experiences to return (max 10)"),
7163
+ pageNext: z106.string().optional().describe("Cursor token to fetch the next page of results"),
7164
+ pagePrev: z106.string().optional().describe("Cursor token to fetch the previous page of results"),
7165
+ order: z106.string().optional().describe("Order experiences by this field (e.g. sys.createdAt)")
7166
+ });
7167
+ function listExperiencesTool(config) {
7168
+ async function tool2(args) {
7169
+ const contentfulClient = createToolClient(config, args);
7170
+ const experiences = await contentfulClient.experience.getMany({
7171
+ spaceId: args.spaceId,
7172
+ environmentId: args.environmentId,
7173
+ query: {
7174
+ limit: Math.min(args.limit || 10, 10),
7175
+ ...args.pageNext && { pageNext: args.pageNext },
7176
+ ...args.pagePrev && { pagePrev: args.pagePrev },
7177
+ ...args.order && { order: args.order }
7178
+ }
7179
+ });
7180
+ const summarized = summarizeData(experiences, {
7181
+ maxItems: 10,
7182
+ remainingMessage: "To see more experiences, ask me to retrieve the next page using the pageNext cursor."
7183
+ });
7184
+ return createSuccessResponse("Experiences retrieved successfully", {
7185
+ experiences: summarized,
7186
+ total: experiences.total,
7187
+ limit: experiences.limit,
7188
+ pages: experiences.pages
7189
+ });
7190
+ }
7191
+ return withErrorHandling(tool2, "Error listing experiences");
7192
+ }
7193
+
7194
+ // src/tools/exo/experiences/createExperience.ts
7195
+ import { z as z107 } from "zod";
7196
+ var CreateExperienceToolParams = BaseToolSchema.extend({
7197
+ name: z107.string().describe("The name of the experience"),
7198
+ description: z107.string().describe("Description of the experience"),
7199
+ experienceTemplate: ExperienceTemplateResourceLinkSchema.describe(
7200
+ "Resource link to the ExperienceTemplate this experience is backed by"
7201
+ ),
7202
+ viewports: z107.array(ViewportSchema).describe("Viewport definitions for the experience (may be empty)"),
7203
+ designProperties: z107.record(z107.string(), DimensionedDesignPropertyValueSchema).describe(
7204
+ "Design property values keyed by property ID. Each value is a dimensioned map (viewport ID \u2192 design value). May be an empty object."
7205
+ ),
7206
+ contentBindings: ExperienceContentBindingsSchema.optional().describe(
7207
+ "Optional content bindings linking this experience to a data assembly"
7208
+ ),
7209
+ slots: z107.record(z107.string(), z107.array(ExperienceSlotNodeSchema)).optional().describe(
7210
+ "Optional slot contents keyed by slot ID. Each value is an array of ExperienceFragmentNode or InlineExperienceFragmentNode."
7211
+ ),
7212
+ metadata: ExperienceMetadataSchema.optional().describe(
7213
+ "Optional ExO metadata (tags, concepts)"
7214
+ )
7215
+ });
7216
+ function createExperienceTool(config) {
7217
+ async function tool2(args) {
7218
+ assertEnvironmentNotProtected(
7219
+ args.environmentId,
7220
+ config.protectedEnvironments
7221
+ );
7222
+ const contentfulClient = createToolClient(config, args);
7223
+ const experience = await contentfulClient.experience.create(
7224
+ { spaceId: args.spaceId, environmentId: args.environmentId },
7225
+ {
7226
+ name: args.name,
7227
+ description: args.description,
7228
+ experienceTemplate: args.experienceTemplate,
7229
+ viewports: args.viewports,
7230
+ designProperties: args.designProperties,
7231
+ ...args.contentBindings && { contentBindings: args.contentBindings },
7232
+ ...args.slots && { slots: args.slots },
7233
+ ...args.metadata && { metadata: args.metadata }
7234
+ }
7235
+ );
7236
+ return createSuccessResponse("Experience created successfully", {
7237
+ experience
7238
+ });
7239
+ }
7240
+ return withErrorHandling(tool2, "Error creating experience");
7241
+ }
7242
+
7243
+ // src/tools/exo/experiences/upsertExperience.ts
7244
+ import { z as z108 } from "zod";
7245
+ var UpsertExperienceToolParams = BaseToolSchema.extend({
7246
+ experienceId: z108.string().describe("The ID of the experience to update"),
7247
+ version: z108.number().describe(
7248
+ "REQUIRED. The experience's sys.version as returned by get_experience. You must call get_experience first to read the current state and version. The update is rejected if this does not match the current version, which means the experience changed since you read it."
7249
+ ),
7250
+ name: z108.string().optional().describe("The name of the experience"),
7251
+ description: z108.string().optional().describe("Description of the experience"),
7252
+ viewports: z108.array(ViewportSchema).optional().describe("Viewport definitions; replaces existing viewports if provided"),
7253
+ designProperties: z108.record(z108.string(), DimensionedDesignPropertyValueSchema).optional().describe(
7254
+ "Design property values keyed by property ID; replaces existing if provided"
7255
+ ),
7256
+ contentBindings: ExperienceContentBindingsSchema.optional().describe(
7257
+ "Content bindings linking this experience to a data assembly; replaces existing if provided"
7258
+ ),
7259
+ slots: z108.record(z108.string(), z108.array(ExperienceSlotNodeSchema)).optional().describe("Slot contents keyed by slot ID; replaces existing if provided"),
7260
+ metadata: ExperienceMetadataSchema.optional().describe(
7261
+ "ExO metadata (tags, concepts); replaces existing if provided"
7262
+ )
7263
+ });
7264
+ function upsertExperienceTool(config) {
7265
+ async function tool2(args) {
7266
+ assertEnvironmentNotProtected(
7267
+ args.environmentId,
7268
+ config.protectedEnvironments
7269
+ );
7270
+ const params = {
7271
+ spaceId: args.spaceId,
7272
+ environmentId: args.environmentId,
7273
+ experienceId: args.experienceId
7274
+ };
7275
+ const contentfulClient = createToolClient(config, args);
7276
+ const current = await contentfulClient.experience.get(params);
7277
+ if (args.version !== current.sys.version) {
7278
+ throw new Error(
7279
+ `Version conflict: the experience has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the experience with get_experience and retry the update with the latest sys.version.`
7280
+ );
7281
+ }
7282
+ const experience = await contentfulClient.experience.upsert(params, {
7283
+ sys: {
7284
+ id: current.sys.id,
7285
+ type: "Experience",
7286
+ version: current.sys.version
7287
+ },
7288
+ name: args.name ?? current.name,
7289
+ description: args.description ?? current.description,
7290
+ viewports: args.viewports ?? current.viewports,
7291
+ designProperties: args.designProperties ?? current.designProperties,
7292
+ ...args.contentBindings ?? current.contentBindings ? { contentBindings: args.contentBindings ?? current.contentBindings } : {},
7293
+ ...args.slots ?? current.slots ? { slots: args.slots ?? current.slots } : {},
7294
+ ...args.metadata ?? current.metadata ? { metadata: args.metadata ?? current.metadata } : {}
7295
+ });
7296
+ return createSuccessResponse("Experience updated successfully", {
7297
+ experience
7298
+ });
7299
+ }
7300
+ return withErrorHandling(tool2, "Error updating experience");
7301
+ }
7302
+
7303
+ // src/tools/exo/experiences/deleteExperience.ts
7304
+ import { z as z109 } from "zod";
7305
+ var DeleteExperienceToolParams = BaseToolSchema.extend({
7306
+ experienceId: z109.string().describe("The ID of the experience to delete"),
7307
+ confirm: z109.boolean().optional().describe(
7308
+ "Set to true on the second call to actually perform the deletion. Required together with confirmToken."
7309
+ ),
7310
+ confirmToken: z109.string().optional().describe(
7311
+ "Token returned by the preview call; must be supplied with confirm: true."
7312
+ )
7313
+ });
7314
+ function deleteExperienceTool(config) {
7315
+ async function tool2(args) {
7316
+ assertEnvironmentNotProtected(
7317
+ args.environmentId,
7318
+ config.protectedEnvironments
7319
+ );
7320
+ const params = {
7321
+ spaceId: args.spaceId,
7322
+ environmentId: args.environmentId,
7323
+ experienceId: args.experienceId
7324
+ };
7325
+ const contentfulClient = createToolClient(config, args);
7326
+ const experience = await contentfulClient.experience.get(params);
7327
+ const expectedToken = buildConfirmToken(
7328
+ "experience",
7329
+ args.experienceId,
7330
+ experience.sys.version
7331
+ );
7332
+ if (args.confirm !== true || args.confirmToken !== expectedToken) {
7333
+ return createSuccessResponse(
7334
+ `${CONFIRMATION_MESSAGE_PREFIX} experience`,
7335
+ buildConfirmationPreview(
7336
+ "experience",
7337
+ args.experienceId,
7338
+ { experience },
7339
+ expectedToken
7340
+ )
7341
+ );
7342
+ }
7343
+ await contentfulClient.experience.delete(params);
7344
+ return createSuccessResponse("Experience deleted successfully", {
7345
+ experienceId: args.experienceId
7346
+ });
7347
+ }
7348
+ return withErrorHandling(tool2, "Error deleting experience");
7349
+ }
7350
+
7351
+ // src/tools/exo/experiences/publishExperience.ts
7352
+ import { z as z110 } from "zod";
7353
+ var PublishExperienceToolParams = BaseToolSchema.extend({
7354
+ experienceId: z110.string().describe("The ID of the experience to publish"),
7355
+ version: z110.number().describe(
7356
+ "REQUIRED. The experience's sys.version as returned by get_experience. You must call get_experience first to read the current state and version. The publish is rejected if this does not match the current version, which means the experience changed since you read it."
7357
+ )
7358
+ });
7359
+ function publishExperienceTool(config) {
7360
+ async function tool2(args) {
7361
+ assertEnvironmentNotProtected(
7362
+ args.environmentId,
7363
+ config.protectedEnvironments
7364
+ );
7365
+ const params = {
7366
+ spaceId: args.spaceId,
7367
+ environmentId: args.environmentId,
7368
+ experienceId: args.experienceId
7369
+ };
7370
+ const contentfulClient = createToolClient(config, args);
7371
+ const current = await contentfulClient.experience.get(params);
7372
+ if (args.version !== current.sys.version) {
7373
+ throw new Error(
7374
+ `Version conflict: the experience has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the experience with get_experience and retry with the latest sys.version.`
7375
+ );
7376
+ }
7377
+ const experience = await contentfulClient.experience.publish({
7378
+ ...params,
7379
+ version: args.version
7380
+ });
7381
+ return createSuccessResponse("Experience published successfully", {
7382
+ experience
7383
+ });
7384
+ }
7385
+ return withErrorHandling(tool2, "Error publishing experience");
7386
+ }
7387
+
7388
+ // src/tools/exo/experiences/unpublishExperience.ts
7389
+ import { z as z111 } from "zod";
7390
+ var UnpublishExperienceToolParams = BaseToolSchema.extend({
7391
+ experienceId: z111.string().describe("The ID of the experience to unpublish"),
7392
+ version: z111.number().describe(
7393
+ "REQUIRED. The experience's sys.version as returned by get_experience. You must call get_experience first to read the current state and version. The unpublish is rejected if this does not match the current version, which means the experience changed since you read it."
7394
+ )
7395
+ });
7396
+ function unpublishExperienceTool(config) {
7397
+ async function tool2(args) {
7398
+ assertEnvironmentNotProtected(
7399
+ args.environmentId,
7400
+ config.protectedEnvironments
7401
+ );
7402
+ const params = {
7403
+ spaceId: args.spaceId,
7404
+ environmentId: args.environmentId,
7405
+ experienceId: args.experienceId
7406
+ };
7407
+ const contentfulClient = createToolClient(config, args);
7408
+ const current = await contentfulClient.experience.get(params);
7409
+ if (args.version !== current.sys.version) {
7410
+ throw new Error(
7411
+ `Version conflict: the experience has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the experience with get_experience and retry with the latest sys.version.`
7412
+ );
7413
+ }
7414
+ const experience = await contentfulClient.experience.unpublish({
7415
+ ...params,
7416
+ version: args.version
7417
+ });
7418
+ return createSuccessResponse("Experience unpublished successfully", {
7419
+ experience
7420
+ });
7421
+ }
7422
+ return withErrorHandling(tool2, "Error unpublishing experience");
7423
+ }
7424
+
7425
+ // src/tools/exo/experiences/register.ts
7426
+ function createExperienceTools(config) {
7427
+ const getExperience = getExperienceTool(config);
7428
+ const listExperiences = listExperiencesTool(config);
7429
+ const createExperience = createExperienceTool(config);
7430
+ const upsertExperience = upsertExperienceTool(config);
7431
+ const deleteExperience = deleteExperienceTool(config);
7432
+ const publishExperience = publishExperienceTool(config);
7433
+ const unpublishExperience = unpublishExperienceTool(config);
7434
+ return {
7435
+ getExperience: {
7436
+ title: "get_experience",
7437
+ description: "Get details about a specific ExO experience (a concrete page or screen that composes a root Component with content and design settings, backed by an ExperienceTemplate).",
7438
+ inputParams: GetExperienceToolParams.shape,
7439
+ annotations: {
7440
+ readOnlyHint: true,
7441
+ destructiveHint: false,
7442
+ openWorldHint: false
7443
+ },
7444
+ tool: getExperience
7445
+ },
7446
+ listExperiences: {
7447
+ title: "list_experiences",
7448
+ description: "List ExO experiences in a space and environment. Returns a maximum of 10 items per request; use the pageNext cursor (returned in pages.next) to paginate.",
7449
+ inputParams: ListExperiencesToolParams.shape,
7450
+ annotations: {
7451
+ readOnlyHint: true,
7452
+ destructiveHint: false,
7453
+ openWorldHint: false
7454
+ },
7455
+ tool: listExperiences
7456
+ },
7457
+ createExperience: {
7458
+ title: "create_experience",
7459
+ description: "Create a new ExO experience backed by an ExperienceTemplate.",
7460
+ inputParams: CreateExperienceToolParams.shape,
7461
+ annotations: {
7462
+ readOnlyHint: false,
7463
+ destructiveHint: false,
7464
+ idempotentHint: false,
7465
+ openWorldHint: false
7466
+ },
7467
+ tool: createExperience
7468
+ },
7469
+ upsertExperience: {
7470
+ title: "upsert_experience",
7471
+ description: "Update an existing ExO experience. You MUST call get_experience first to read the current state, then pass the sys.version you received as the version parameter. The handler merges your updates with the existing experience fields, so you only need to provide the fields you want to change. If the version is stale (the experience changed since you read it), the update is rejected and you must re-fetch with get_experience.",
7472
+ inputParams: UpsertExperienceToolParams.shape,
7473
+ annotations: {
7474
+ readOnlyHint: false,
7475
+ destructiveHint: false,
7476
+ idempotentHint: false,
7477
+ openWorldHint: false
7478
+ },
7479
+ tool: upsertExperience
7480
+ },
7481
+ deleteExperience: {
7482
+ title: "delete_experience",
7483
+ description: "Delete an ExO experience. Two-phase: the first call (without confirm/confirmToken) returns a preview and a confirmToken. To complete the deletion, call again with the same experienceId, confirm: true, and the confirmToken from the preview.",
7484
+ inputParams: DeleteExperienceToolParams.shape,
7485
+ annotations: {
7486
+ readOnlyHint: false,
7487
+ destructiveHint: true,
7488
+ idempotentHint: false,
7489
+ openWorldHint: false
7490
+ },
7491
+ tool: deleteExperience
7492
+ },
7493
+ publishExperience: {
7494
+ title: "publish_experience",
7495
+ description: "Publish an ExO experience. You MUST call get_experience first and pass the returned sys.version as the version parameter. If the version is stale the operation is rejected and you must re-fetch with get_experience.",
7496
+ inputParams: PublishExperienceToolParams.shape,
7497
+ annotations: {
7498
+ readOnlyHint: false,
7499
+ destructiveHint: true,
7500
+ idempotentHint: true,
7501
+ openWorldHint: false
7502
+ },
7503
+ tool: publishExperience
7504
+ },
7505
+ unpublishExperience: {
7506
+ title: "unpublish_experience",
7507
+ description: "Unpublish an ExO experience. You MUST call get_experience first and pass the returned sys.version as the version parameter. If the version is stale the operation is rejected and you must re-fetch with get_experience.",
7508
+ inputParams: UnpublishExperienceToolParams.shape,
7509
+ annotations: {
7510
+ readOnlyHint: false,
7511
+ destructiveHint: true,
7512
+ idempotentHint: true,
7513
+ openWorldHint: false
7514
+ },
7515
+ tool: unpublishExperience
7516
+ }
7517
+ };
7518
+ }
7519
+
7520
+ // src/tools/exo/data-assemblies/getDataAssembly.ts
7521
+ import { z as z112 } from "zod";
7522
+ var GetDataAssemblyToolParams = BaseToolSchema.extend({
7523
+ dataAssemblyId: z112.string().describe("The ID of the data assembly to retrieve")
7524
+ });
7525
+ function getDataAssemblyTool(config) {
7526
+ async function tool2(args) {
7527
+ const contentfulClient = createToolClient(config, args);
7528
+ const dataAssembly = await contentfulClient.dataAssembly.get({
7529
+ spaceId: args.spaceId,
7530
+ environmentId: args.environmentId,
7531
+ dataAssemblyId: args.dataAssemblyId
7532
+ });
7533
+ return createSuccessResponse("Data assembly retrieved successfully", {
7534
+ dataAssembly
7535
+ });
7536
+ }
7537
+ return withErrorHandling(tool2, "Error retrieving data assembly");
7538
+ }
7539
+
7540
+ // src/tools/exo/data-assemblies/getPublishedDataAssembly.ts
7541
+ import { z as z113 } from "zod";
7542
+ var GetPublishedDataAssemblyToolParams = BaseToolSchema.extend({
7543
+ dataAssemblyId: z113.string().describe("The ID of the published data assembly to retrieve")
7544
+ });
7545
+ function getPublishedDataAssemblyTool(config) {
7546
+ async function tool2(args) {
7547
+ const contentfulClient = createToolClient(config, args);
7548
+ const dataAssembly = await contentfulClient.dataAssembly.getPublished({
7549
+ spaceId: args.spaceId,
7550
+ environmentId: args.environmentId,
7551
+ dataAssemblyId: args.dataAssemblyId
7552
+ });
7553
+ return createSuccessResponse("Published data assembly retrieved successfully", {
7554
+ dataAssembly
7555
+ });
7556
+ }
7557
+ return withErrorHandling(tool2, "Error retrieving published data assembly");
7558
+ }
7559
+
7560
+ // src/tools/exo/data-assemblies/listDataAssemblies.ts
7561
+ import { z as z114 } from "zod";
7562
+ var ListDataAssembliesToolParams = BaseToolSchema.extend({
7563
+ limit: z114.number().optional().describe("Maximum number of data assemblies to return (max 10)"),
7564
+ pageNext: z114.string().optional().describe("Cursor token to fetch the next page of results"),
7565
+ pagePrev: z114.string().optional().describe("Cursor token to fetch the previous page of results"),
7566
+ sysIdIn: z114.string().optional().describe("Comma-separated list of data assembly IDs to filter by")
7567
+ });
7568
+ function listDataAssembliesTool(config) {
7569
+ async function tool2(args) {
7570
+ const contentfulClient = createToolClient(config, args);
7571
+ const dataAssemblies = await contentfulClient.dataAssembly.getMany({
7572
+ spaceId: args.spaceId,
7573
+ environmentId: args.environmentId,
7574
+ query: {
7575
+ limit: Math.min(args.limit || 10, 10),
7576
+ ...args.pageNext && { pageNext: args.pageNext },
7577
+ ...args.pagePrev && { pagePrev: args.pagePrev },
7578
+ ...args.sysIdIn && { "sys.id[in]": args.sysIdIn }
7579
+ }
7580
+ });
7581
+ const summarized = summarizeData(dataAssemblies, {
7582
+ maxItems: 10,
7583
+ remainingMessage: "To see more data assemblies, ask me to retrieve the next page using the pageNext cursor."
7584
+ });
7585
+ return createSuccessResponse("Data assemblies retrieved successfully", {
7586
+ dataAssemblies: summarized,
7587
+ total: dataAssemblies.total,
7588
+ pages: dataAssemblies.pages
7589
+ });
7590
+ }
7591
+ return withErrorHandling(tool2, "Error listing data assemblies");
7592
+ }
7593
+
7594
+ // src/tools/exo/data-assemblies/listPublishedDataAssemblies.ts
7595
+ import { z as z115 } from "zod";
7596
+ var ListPublishedDataAssembliesToolParams = BaseToolSchema.extend({
7597
+ limit: z115.number().optional().describe("Maximum number of published data assemblies to return (max 10)"),
7598
+ pageNext: z115.string().optional().describe("Cursor token to fetch the next page of results"),
7599
+ pagePrev: z115.string().optional().describe("Cursor token to fetch the previous page of results"),
7600
+ sysIdIn: z115.string().optional().describe("Comma-separated list of data assembly IDs to filter by")
7601
+ });
7602
+ function listPublishedDataAssembliesTool(config) {
7603
+ async function tool2(args) {
7604
+ const contentfulClient = createToolClient(config, args);
7605
+ const dataAssemblies = await contentfulClient.dataAssembly.getManyPublished({
7606
+ spaceId: args.spaceId,
7607
+ environmentId: args.environmentId,
7608
+ query: {
7609
+ limit: Math.min(args.limit || 10, 10),
7610
+ ...args.pageNext && { pageNext: args.pageNext },
7611
+ ...args.pagePrev && { pagePrev: args.pagePrev },
7612
+ ...args.sysIdIn && { "sys.id[in]": args.sysIdIn }
7613
+ }
7614
+ });
7615
+ const summarized = summarizeData(dataAssemblies, {
7616
+ maxItems: 10,
7617
+ remainingMessage: "To see more published data assemblies, ask me to retrieve the next page using the pageNext cursor."
7618
+ });
7619
+ return createSuccessResponse("Published data assemblies retrieved successfully", {
7620
+ dataAssemblies: summarized,
7621
+ total: dataAssemblies.total,
7622
+ pages: dataAssemblies.pages
7623
+ });
7624
+ }
7625
+ return withErrorHandling(tool2, "Error listing published data assemblies");
7626
+ }
7627
+
7628
+ // src/tools/exo/data-assemblies/createDataAssembly.ts
7629
+ import { z as z117 } from "zod";
7630
+
7631
+ // src/types/dataAssemblySchemas.ts
7632
+ import { z as z116 } from "zod";
7633
+ var PointerExpressionValueSchema = z116.lazy(
7634
+ () => z116.union([
7635
+ z116.string(),
7636
+ z116.object({
7637
+ $from: z116.union([
7638
+ z116.string(),
7639
+ z116.object({
7640
+ source: z116.string(),
7641
+ select: PointerExpressionValueSchema.optional()
7642
+ })
7643
+ ])
7644
+ }),
7645
+ z116.object({ $literal: z116.custom() }),
7646
+ z116.object({ $object: z116.record(z116.string(), PointerExpressionValueSchema) }),
7647
+ z116.object({
7648
+ $on: z116.object({
7649
+ type: z116.record(z116.string(), PointerExpressionValueSchema),
7650
+ default: PointerExpressionValueSchema.optional()
7651
+ })
7652
+ }),
7653
+ z116.record(z116.string(), PointerExpressionValueSchema)
7654
+ ])
7655
+ );
7656
+ var CanonicalDataTypeArmSchema = z116.object({
7657
+ type: z116.enum([
7658
+ "String",
7659
+ "Number",
7660
+ "Integer",
7661
+ "Boolean",
7662
+ "RichText",
7663
+ "Array",
7664
+ "Record",
7665
+ "TypeRef",
7666
+ "Literal",
7667
+ "DiscriminatedUnion"
7668
+ ]),
7669
+ id: z116.string().describe("Data type field identifier"),
7670
+ name: z116.string().describe("Human-readable name"),
7671
+ required: z116.boolean().optional()
7672
+ }).catchall(z116.unknown());
7673
+ var LegacyDataTypeArmSchema = z116.object({
7674
+ id: z116.string().describe("Data type field identifier"),
7675
+ name: z116.string().describe("Human-readable name"),
7676
+ type: z116.string(),
7677
+ required: z116.boolean().optional(),
7678
+ source: z116.string().optional(),
7679
+ ref: z116.unknown().optional()
7680
+ });
7681
+ var DataAssemblyDataTypeFieldSchema = z116.union([
7682
+ CanonicalDataTypeArmSchema,
7683
+ LegacyDataTypeArmSchema
7684
+ ]);
7685
+ var SAME_SPACE_CONTENT_SOURCE = "crn:contentful:::content:spaces/$self/environments/$self";
7686
+ var DataAssemblyResourceLinkParameterSchema = z116.object({
7687
+ name: z116.string().optional(),
7688
+ description: z116.string().optional(),
7689
+ type: z116.literal("ResourceLink"),
7690
+ linkType: z116.literal("Contentful:Entry"),
7691
+ allowedResources: z116.array(
7692
+ z116.object({
7693
+ type: z116.literal("Contentful:Entry"),
7694
+ source: z116.literal(SAME_SPACE_CONTENT_SOURCE),
7695
+ allowedTypes: z116.array(z116.string())
7696
+ })
7697
+ )
7698
+ });
7699
+ var DataAssemblyParameterConfigSchema = z116.record(
7700
+ z116.string(),
7701
+ DataAssemblyResourceLinkParameterSchema
7702
+ );
7703
+ var DataAssemblyGraphQLResolverSchema = z116.object({
7704
+ source: z116.literal("Contentful:GraphQL"),
7705
+ query: z116.string().describe("GraphQL query string"),
7706
+ parameters: PointerExpressionValueSchema.optional()
7707
+ });
7708
+ var DataAssemblyNestedResolverSchema = z116.object({
7709
+ source: z116.literal("Contentful:DataAssembly"),
7710
+ dataAssembly: z116.object({
7711
+ sys: z116.object({
7712
+ type: z116.literal("ResourceLink"),
7713
+ linkType: z116.literal("Contentful:DataAssembly"),
7714
+ urn: z116.string()
7715
+ })
7716
+ }),
7717
+ parameters: PointerExpressionValueSchema.optional()
7718
+ });
7719
+ var DataAssemblyResolverDefinitionSchema = z116.union([
7720
+ DataAssemblyGraphQLResolverSchema,
7721
+ DataAssemblyNestedResolverSchema
7722
+ ]);
7723
+ var DataAssemblyResolverConfigSchema = z116.record(
7724
+ z116.string(),
7725
+ DataAssemblyResolverDefinitionSchema
7726
+ );
7727
+ var DataAssemblyReturnMappingConfigSchema = PointerExpressionValueSchema;
7728
+ var DataAssemblyMetadataSchema = z116.object({
7729
+ tags: z116.array(
7730
+ z116.object({
7731
+ sys: z116.object({
7732
+ type: z116.literal("Link"),
7733
+ linkType: z116.literal("Tag"),
7734
+ id: z116.string()
7735
+ })
7736
+ })
7737
+ )
7738
+ });
7739
+
7740
+ // src/tools/exo/data-assemblies/createDataAssembly.ts
7741
+ var CreateDataAssemblyToolParams = BaseToolSchema.extend({
7742
+ name: z117.string().describe("The name of the data assembly"),
7743
+ description: z117.string().describe("Description of the data assembly"),
7744
+ parameters: DataAssemblyParameterConfigSchema.describe(
7745
+ "Parameter definitions keyed by parameter name (may be empty object)"
7746
+ ),
7747
+ resolvers: DataAssemblyResolverConfigSchema.describe(
7748
+ "Resolver definitions keyed by resolver name (may be empty object)"
7749
+ ),
7750
+ return: DataAssemblyReturnMappingConfigSchema.describe(
7751
+ "Return mapping configuration specifying how to map resolved data"
7752
+ ),
7753
+ dataType: z117.array(DataAssemblyDataTypeFieldSchema).describe("Data type field definitions for this data assembly (may be empty array)"),
7754
+ variant: z117.string().optional().describe("Optional variant identifier for this data assembly"),
7755
+ metadata: DataAssemblyMetadataSchema.optional().describe("Optional metadata (tags)")
7756
+ });
7757
+ function createDataAssemblyTool(config) {
7758
+ async function tool2(args) {
7759
+ assertEnvironmentNotProtected(
7760
+ args.environmentId,
7761
+ config.protectedEnvironments
7762
+ );
7763
+ const contentfulClient = createToolClient(config, args);
7764
+ const dataAssembly = await contentfulClient.dataAssembly.create(
7765
+ { spaceId: args.spaceId, environmentId: args.environmentId },
7766
+ {
7767
+ sys: {
7768
+ type: "DataAssembly",
7769
+ dataType: args.dataType,
7770
+ ...args.variant && { variant: args.variant }
7771
+ },
7772
+ name: args.name,
7773
+ description: args.description,
7774
+ parameters: args.parameters,
7775
+ resolvers: args.resolvers,
7776
+ return: args.return,
7777
+ metadata: args.metadata ?? { tags: [] }
7778
+ }
7779
+ );
7780
+ return createSuccessResponse("Data assembly created successfully", {
7781
+ dataAssembly
7782
+ });
7783
+ }
7784
+ return withErrorHandling(tool2, "Error creating data assembly");
7785
+ }
7786
+
7787
+ // src/tools/exo/data-assemblies/updateDataAssembly.ts
7788
+ import { z as z118 } from "zod";
7789
+ var UpdateDataAssemblyToolParams = BaseToolSchema.extend({
7790
+ dataAssemblyId: z118.string().describe("The ID of the data assembly to update"),
7791
+ version: z118.number().describe(
7792
+ "REQUIRED. The data assembly's sys.version as returned by get_data_assembly. You must call get_data_assembly first to read the current state and version. The update is rejected if this does not match the current version, which means the data assembly changed since you read it."
7793
+ ),
7794
+ name: z118.string().optional().describe("The name of the data assembly"),
7795
+ description: z118.string().optional().describe("Description of the data assembly"),
7796
+ parameters: DataAssemblyParameterConfigSchema.optional().describe(
7797
+ "Parameter definitions; replaces existing if provided"
7798
+ ),
7799
+ resolvers: DataAssemblyResolverConfigSchema.optional().describe(
7800
+ "Resolver definitions; replaces existing if provided"
7801
+ ),
7802
+ return: DataAssemblyReturnMappingConfigSchema.optional().describe(
7803
+ "Return mapping configuration; replaces existing if provided"
7804
+ ),
7805
+ dataType: z118.array(DataAssemblyDataTypeFieldSchema).optional().describe("Data type field definitions; replaces existing if provided"),
7806
+ variant: z118.string().optional().describe("Optional variant identifier; replaces existing if provided"),
7807
+ metadata: DataAssemblyMetadataSchema.optional().describe(
7808
+ "Metadata (tags); replaces existing if provided"
7809
+ )
7810
+ });
7811
+ function updateDataAssemblyTool(config) {
7812
+ async function tool2(args) {
7813
+ assertEnvironmentNotProtected(
7814
+ args.environmentId,
7815
+ config.protectedEnvironments
7816
+ );
7817
+ const params = {
7818
+ spaceId: args.spaceId,
7819
+ environmentId: args.environmentId,
7820
+ dataAssemblyId: args.dataAssemblyId
7821
+ };
7822
+ const contentfulClient = createToolClient(config, args);
7823
+ const current = await contentfulClient.dataAssembly.get(params);
7824
+ if (args.version !== current.sys.version) {
7825
+ throw new Error(
7826
+ `Version conflict: the data assembly has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the data assembly with get_data_assembly and retry the update with the latest sys.version.`
7827
+ );
7828
+ }
7829
+ const dataAssembly = await contentfulClient.dataAssembly.update(params, {
7830
+ sys: {
7831
+ id: current.sys.id,
7832
+ type: "DataAssembly",
7833
+ version: current.sys.version,
7834
+ dataType: args.dataType ?? current.sys.dataType,
7835
+ ...args.variant !== void 0 ? { variant: args.variant } : current.sys.variant !== void 0 ? { variant: current.sys.variant } : {}
7836
+ },
7837
+ name: args.name ?? current.name,
7838
+ description: args.description ?? current.description,
7839
+ parameters: args.parameters ?? current.parameters,
7840
+ resolvers: args.resolvers ?? current.resolvers,
7841
+ return: args.return ?? current.return,
7842
+ metadata: args.metadata ?? current.metadata
7843
+ });
7844
+ return createSuccessResponse("Data assembly updated successfully", {
7845
+ dataAssembly
7846
+ });
7847
+ }
7848
+ return withErrorHandling(tool2, "Error updating data assembly");
7849
+ }
7850
+
7851
+ // src/tools/exo/data-assemblies/deleteDataAssembly.ts
7852
+ import { z as z119 } from "zod";
7853
+ var DeleteDataAssemblyToolParams = BaseToolSchema.extend({
7854
+ dataAssemblyId: z119.string().describe("The ID of the data assembly to delete"),
7855
+ confirm: z119.boolean().optional().describe(
7856
+ "Set to true on the second call to actually perform the deletion. Required together with confirmToken."
7857
+ ),
7858
+ confirmToken: z119.string().optional().describe(
7859
+ "Token returned by the preview call; must be supplied with confirm: true."
7860
+ )
7861
+ });
7862
+ function deleteDataAssemblyTool(config) {
7863
+ async function tool2(args) {
7864
+ assertEnvironmentNotProtected(
7865
+ args.environmentId,
7866
+ config.protectedEnvironments
7867
+ );
7868
+ const params = {
7869
+ spaceId: args.spaceId,
7870
+ environmentId: args.environmentId,
7871
+ dataAssemblyId: args.dataAssemblyId
7872
+ };
7873
+ const contentfulClient = createToolClient(config, args);
7874
+ const dataAssembly = await contentfulClient.dataAssembly.get(params);
7875
+ const expectedToken = buildConfirmToken(
7876
+ "dataAssembly",
7877
+ args.dataAssemblyId,
7878
+ dataAssembly.sys.version
7879
+ );
7880
+ if (args.confirm !== true || args.confirmToken !== expectedToken) {
7881
+ return createSuccessResponse(
7882
+ `${CONFIRMATION_MESSAGE_PREFIX} data assembly`,
7883
+ buildConfirmationPreview(
7884
+ "dataAssembly",
7885
+ args.dataAssemblyId,
7886
+ { dataAssembly },
7887
+ expectedToken
7888
+ )
7889
+ );
7890
+ }
7891
+ await contentfulClient.dataAssembly.delete(params);
7892
+ return createSuccessResponse("Data assembly deleted successfully", {
7893
+ dataAssemblyId: args.dataAssemblyId
7894
+ });
7895
+ }
7896
+ return withErrorHandling(tool2, "Error deleting data assembly");
7897
+ }
7898
+
7899
+ // src/tools/exo/data-assemblies/publishDataAssembly.ts
7900
+ import { z as z120 } from "zod";
7901
+ var PublishDataAssemblyToolParams = BaseToolSchema.extend({
7902
+ dataAssemblyId: z120.string().describe("The ID of the data assembly to publish"),
7903
+ version: z120.number().describe(
7904
+ "REQUIRED. The data assembly's sys.version as returned by get_data_assembly. You must call get_data_assembly first to read the current state and version. The publish is rejected if this does not match the current version, which means the data assembly changed since you read it."
7905
+ )
7906
+ });
7907
+ function publishDataAssemblyTool(config) {
7908
+ async function tool2(args) {
7909
+ assertEnvironmentNotProtected(
7910
+ args.environmentId,
7911
+ config.protectedEnvironments
7912
+ );
7913
+ const params = {
7914
+ spaceId: args.spaceId,
7915
+ environmentId: args.environmentId,
7916
+ dataAssemblyId: args.dataAssemblyId
7917
+ };
7918
+ const contentfulClient = createToolClient(config, args);
7919
+ const current = await contentfulClient.dataAssembly.get(params);
7920
+ if (args.version !== current.sys.version) {
7921
+ throw new Error(
7922
+ `Version conflict: the data assembly has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the data assembly with get_data_assembly and retry with the latest sys.version.`
7923
+ );
7924
+ }
7925
+ const dataAssembly = await contentfulClient.dataAssembly.publish({
7926
+ ...params,
7927
+ version: args.version
7928
+ });
7929
+ return createSuccessResponse("Data assembly published successfully", {
7930
+ dataAssembly
7931
+ });
7932
+ }
7933
+ return withErrorHandling(tool2, "Error publishing data assembly");
7934
+ }
7935
+
7936
+ // src/tools/exo/data-assemblies/unpublishDataAssembly.ts
7937
+ import { z as z121 } from "zod";
7938
+ var UnpublishDataAssemblyToolParams = BaseToolSchema.extend({
7939
+ dataAssemblyId: z121.string().describe("The ID of the data assembly to unpublish"),
7940
+ version: z121.number().describe(
7941
+ "REQUIRED. The data assembly's sys.version as returned by get_data_assembly. You must call get_data_assembly first to read the current state and version. The unpublish is rejected if this does not match the current version, which means the data assembly changed since you read it."
7942
+ )
7943
+ });
7944
+ function unpublishDataAssemblyTool(config) {
7945
+ async function tool2(args) {
7946
+ assertEnvironmentNotProtected(
7947
+ args.environmentId,
7948
+ config.protectedEnvironments
7949
+ );
7950
+ const params = {
7951
+ spaceId: args.spaceId,
7952
+ environmentId: args.environmentId,
7953
+ dataAssemblyId: args.dataAssemblyId
7954
+ };
7955
+ const contentfulClient = createToolClient(config, args);
7956
+ const current = await contentfulClient.dataAssembly.get(params);
7957
+ if (args.version !== current.sys.version) {
7958
+ throw new Error(
7959
+ `Version conflict: the data assembly has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the data assembly with get_data_assembly and retry with the latest sys.version.`
7960
+ );
7961
+ }
7962
+ const dataAssembly = await contentfulClient.dataAssembly.unpublish({
7963
+ ...params,
7964
+ version: args.version
7965
+ });
7966
+ return createSuccessResponse("Data assembly unpublished successfully", {
7967
+ dataAssembly
7968
+ });
7969
+ }
7970
+ return withErrorHandling(tool2, "Error unpublishing data assembly");
7971
+ }
7972
+
7973
+ // src/tools/exo/data-assemblies/register.ts
7974
+ function createDataAssemblyTools(config) {
7975
+ const getDataAssembly = getDataAssemblyTool(config);
7976
+ const getPublishedDataAssembly = getPublishedDataAssemblyTool(config);
7977
+ const listDataAssemblies = listDataAssembliesTool(config);
7978
+ const listPublishedDataAssemblies = listPublishedDataAssembliesTool(config);
7979
+ const createDataAssembly = createDataAssemblyTool(config);
7980
+ const updateDataAssembly = updateDataAssemblyTool(config);
7981
+ const deleteDataAssembly = deleteDataAssemblyTool(config);
7982
+ const publishDataAssembly = publishDataAssemblyTool(config);
7983
+ const unpublishDataAssembly = unpublishDataAssemblyTool(config);
7984
+ return {
7985
+ getDataAssembly: {
7986
+ title: "get_data_assembly",
7987
+ description: "Get details about a specific ExO DataAssembly (a smart data recipe that specifies how to fetch and reshape data for a component or page in a single operation).",
7988
+ inputParams: GetDataAssemblyToolParams.shape,
7989
+ annotations: {
7990
+ readOnlyHint: true,
7991
+ destructiveHint: false,
7992
+ openWorldHint: false
7993
+ },
7994
+ tool: getDataAssembly
7995
+ },
7996
+ getPublishedDataAssembly: {
7997
+ title: "get_published_data_assembly",
7998
+ description: "Get details about a specific published ExO DataAssembly by ID.",
7999
+ inputParams: GetPublishedDataAssemblyToolParams.shape,
8000
+ annotations: {
8001
+ readOnlyHint: true,
8002
+ destructiveHint: false,
8003
+ openWorldHint: false
8004
+ },
8005
+ tool: getPublishedDataAssembly
8006
+ },
8007
+ listDataAssemblies: {
8008
+ title: "list_data_assemblies",
8009
+ description: "List ExO DataAssemblies in a space and environment. Returns a maximum of 10 items per request; use the pageNext cursor (returned in pages.next) to paginate.",
8010
+ inputParams: ListDataAssembliesToolParams.shape,
8011
+ annotations: {
8012
+ readOnlyHint: true,
8013
+ destructiveHint: false,
8014
+ openWorldHint: false
8015
+ },
8016
+ tool: listDataAssemblies
8017
+ },
8018
+ listPublishedDataAssemblies: {
8019
+ title: "list_published_data_assemblies",
8020
+ description: "List published ExO DataAssemblies in a space and environment. Returns a maximum of 10 items per request; use the pageNext cursor (returned in pages.next) to paginate.",
8021
+ inputParams: ListPublishedDataAssembliesToolParams.shape,
8022
+ annotations: {
8023
+ readOnlyHint: true,
8024
+ destructiveHint: false,
8025
+ openWorldHint: false
8026
+ },
8027
+ tool: listPublishedDataAssemblies
8028
+ },
8029
+ createDataAssembly: {
8030
+ title: "create_data_assembly",
8031
+ description: "Create a new ExO DataAssembly.",
8032
+ inputParams: CreateDataAssemblyToolParams.shape,
8033
+ annotations: {
8034
+ readOnlyHint: false,
8035
+ destructiveHint: false,
8036
+ idempotentHint: false,
8037
+ openWorldHint: false
8038
+ },
8039
+ tool: createDataAssembly
8040
+ },
8041
+ updateDataAssembly: {
8042
+ title: "update_data_assembly",
8043
+ description: "Update an existing ExO DataAssembly. You MUST call get_data_assembly first to read the current state, then pass the sys.version you received as the version parameter. The handler merges your updates with the existing data assembly fields, so you only need to provide the fields you want to change. If the version is stale (the data assembly changed since you read it), the update is rejected and you must re-fetch with get_data_assembly.",
8044
+ inputParams: UpdateDataAssemblyToolParams.shape,
8045
+ annotations: {
8046
+ readOnlyHint: false,
8047
+ destructiveHint: false,
8048
+ idempotentHint: false,
8049
+ openWorldHint: false
8050
+ },
8051
+ tool: updateDataAssembly
8052
+ },
8053
+ deleteDataAssembly: {
8054
+ title: "delete_data_assembly",
8055
+ description: "Delete an ExO DataAssembly. Two-phase: the first call (without confirm/confirmToken) returns a preview and a confirmToken. To complete the deletion, call again with the same dataAssemblyId, confirm: true, and the confirmToken from the preview.",
8056
+ inputParams: DeleteDataAssemblyToolParams.shape,
8057
+ annotations: {
8058
+ readOnlyHint: false,
8059
+ destructiveHint: true,
8060
+ idempotentHint: false,
8061
+ openWorldHint: false
8062
+ },
8063
+ tool: deleteDataAssembly
8064
+ },
8065
+ publishDataAssembly: {
8066
+ title: "publish_data_assembly",
8067
+ description: "Publish an ExO DataAssembly. You MUST call get_data_assembly first and pass the returned sys.version as the version parameter. If the version is stale the operation is rejected and you must re-fetch with get_data_assembly.",
8068
+ inputParams: PublishDataAssemblyToolParams.shape,
8069
+ annotations: {
8070
+ readOnlyHint: false,
8071
+ destructiveHint: true,
8072
+ idempotentHint: true,
8073
+ openWorldHint: false
8074
+ },
8075
+ tool: publishDataAssembly
8076
+ },
8077
+ unpublishDataAssembly: {
8078
+ title: "unpublish_data_assembly",
8079
+ description: "Unpublish an ExO DataAssembly. You MUST call get_data_assembly first and pass the returned sys.version as the version parameter. If the version is stale the operation is rejected and you must re-fetch with get_data_assembly.",
8080
+ inputParams: UnpublishDataAssemblyToolParams.shape,
8081
+ annotations: {
8082
+ readOnlyHint: false,
8083
+ destructiveHint: true,
8084
+ idempotentHint: true,
8085
+ openWorldHint: false
8086
+ },
8087
+ tool: unpublishDataAssembly
8088
+ }
8089
+ };
8090
+ }
8091
+
8092
+ // src/ContentfulMcpTools.ts
8093
+ var ContentfulMcpTools = class {
8094
+ config;
8095
+ constructor(config) {
8096
+ this.config = {
8097
+ ...config,
8098
+ host: config.host ?? "api.contentful.com",
8099
+ environmentId: config.environmentId ?? "master"
8100
+ };
8101
+ }
8102
+ /**
8103
+ * Update the configuration after initialization
8104
+ *
8105
+ * @param updates - Partial configuration to merge with existing config
8106
+ */
8107
+ updateConfig(updates) {
8108
+ this.config = { ...this.config, ...updates };
8109
+ }
8110
+ /**
8111
+ * Get AI action tools
8112
+ */
8113
+ getAiActionTools() {
8114
+ return createAiActionTools(this.config);
8115
+ }
8116
+ /**
8117
+ * Get asset tools
8118
+ */
8119
+ getAssetTools() {
8120
+ return createAssetTools(this.config);
8121
+ }
8122
+ /**
8123
+ * Get content type tools
8124
+ */
8125
+ getContentTypeTools() {
8126
+ return createContentTypeTools(this.config);
8127
+ }
8128
+ /**
8129
+ * Get ExO component tools
8130
+ */
8131
+ getComponentTools() {
8132
+ return createComponentTools(this.config);
8133
+ }
8134
+ /**
8135
+ * Get ExO experience template tools
8136
+ */
8137
+ getExperienceTemplateTools() {
8138
+ return createExperienceTemplateTools(this.config);
8139
+ }
8140
+ /**
8141
+ * Get ExO experience tools
8142
+ */
8143
+ getExperienceTools() {
8144
+ return createExperienceTools(this.config);
8145
+ }
8146
+ /**
8147
+ * Get context tools
8148
+ */
8149
+ getContextTools() {
8150
+ return createContextTools(this.config);
8151
+ }
8152
+ /**
8153
+ * Get editor interface tools
8154
+ */
8155
+ getEditorInterfaceTools() {
8156
+ return createEditorInterfaceTools(this.config);
8157
+ }
8158
+ /**
8159
+ * Get entry tools
8160
+ */
8161
+ getEntryTools() {
8162
+ return createEntryTools(this.config);
8163
+ }
8164
+ /**
8165
+ * Get environment tools
8166
+ */
8167
+ getEnvironmentTools() {
8168
+ return createEnvironmentTools(this.config);
8169
+ }
8170
+ /**
8171
+ * Get locale tools
8172
+ */
8173
+ getLocaleTools() {
8174
+ return createLocaleTools(this.config);
8175
+ }
8176
+ /**
8177
+ * Get organization tools
8178
+ */
8179
+ getOrgTools() {
8180
+ return createOrgTools(this.config);
8181
+ }
8182
+ /**
8183
+ * Get space tools
8184
+ */
8185
+ getSpaceTools() {
8186
+ return createSpaceTools(this.config);
8187
+ }
8188
+ /**
5868
8189
  * Get tag tools
5869
8190
  */
5870
8191
  getTagTools() {
@@ -5876,6 +8197,18 @@ var ContentfulMcpTools = class {
5876
8197
  getTaxonomyTools() {
5877
8198
  return createTaxonomyTools(this.config);
5878
8199
  }
8200
+ /**
8201
+ * Get ExO experience fragment tools
8202
+ */
8203
+ getExperienceFragmentTools() {
8204
+ return createExperienceFragmentTools(this.config);
8205
+ }
8206
+ /**
8207
+ * Get ExO data assembly tools
8208
+ */
8209
+ getDataAssemblyTools() {
8210
+ return createDataAssemblyTools(this.config);
8211
+ }
5879
8212
  /**
5880
8213
  * Get job tools (space-to-space migration)
5881
8214
  */
@@ -5883,6 +8216,44 @@ var ContentfulMcpTools = class {
5883
8216
  return createJobTools(this.config);
5884
8217
  }
5885
8218
  };
8219
+
8220
+ // src/utils/entitlements.ts
8221
+ import { createClient as createClient16 } from "contentful-management";
8222
+ var EXO_M1_FEATURE = "exoM1";
8223
+ function createPlainClient(config) {
8224
+ return createClient16(createClientConfig(config), { type: "plain" });
8225
+ }
8226
+ async function orgHasExoM1(client, organizationId) {
8227
+ try {
8228
+ const entitlements = await client.raw.get(
8229
+ `/organizations/${organizationId}/organization_entitlement_set`
8230
+ );
8231
+ return entitlements.features?.[EXO_M1_FEATURE]?.value === true;
8232
+ } catch {
8233
+ return false;
8234
+ }
8235
+ }
8236
+ async function hasExoM1Entitlement(config) {
8237
+ try {
8238
+ const client = createPlainClient(config);
8239
+ const orgs = await client.organization.getAll();
8240
+ if (!orgs.items.length) {
8241
+ return false;
8242
+ }
8243
+ const results = await Promise.all(
8244
+ orgs.items.map((org) => orgHasExoM1(client, org.sys.id))
8245
+ );
8246
+ return results.some(Boolean);
8247
+ } catch {
8248
+ return false;
8249
+ }
8250
+ }
5886
8251
  export {
5887
- ContentfulMcpTools
8252
+ CONVENTIONS_GUIDANCE,
8253
+ CORE_INVARIANTS,
8254
+ ContentfulMcpTools,
8255
+ EXO_DISPOSITION,
8256
+ EXO_M1_FEATURE,
8257
+ SEARCHING_GUIDANCE,
8258
+ hasExoM1Entitlement
5888
8259
  };