@contentful/mcp-tools 0.12.3 → 0.12.4

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 +2555 -204
  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
+ componentType: "component type",
340
+ experience: "experience",
341
+ fragment: "fragment",
342
+ template: "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 component types 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 Component Types, Experiences, Templates, 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,89 +5711,2465 @@ 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);
5824
- }
5825
- /**
5826
- * Get context tools
5827
- */
5828
- getContextTools() {
5829
- return createContextTools(this.config);
5714
+ // src/tools/exo/component-types/getComponentType.ts
5715
+ import { z as z83 } from "zod";
5716
+ var GetComponentTypeToolParams = BaseToolSchema.extend({
5717
+ componentTypeId: z83.string().describe("The ID of the component type to retrieve details for")
5718
+ });
5719
+ function getComponentTypeTool(config) {
5720
+ async function tool2(args) {
5721
+ const contentfulClient = createToolClient(config, args);
5722
+ const componentType = await contentfulClient.componentType.get({
5723
+ spaceId: args.spaceId,
5724
+ environmentId: args.environmentId,
5725
+ componentTypeId: args.componentTypeId
5726
+ });
5727
+ return createSuccessResponse("Component type retrieved successfully", {
5728
+ componentType
5729
+ });
5830
5730
  }
5831
- /**
5832
- * Get editor interface tools
5833
- */
5834
- getEditorInterfaceTools() {
5835
- return createEditorInterfaceTools(this.config);
5731
+ return withErrorHandling(tool2, "Error retrieving component type");
5732
+ }
5733
+
5734
+ // src/tools/exo/component-types/listComponentTypes.ts
5735
+ import { z as z84 } from "zod";
5736
+ var ListComponentTypesToolParams = BaseToolSchema.extend({
5737
+ limit: z84.number().optional().describe("Maximum number of component types 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 component types by this field (e.g. sys.createdAt)")
5741
+ });
5742
+ function listComponentTypesTool(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 componentTypes = await contentfulClient.componentType.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(componentTypes, {
5756
+ maxItems: 10,
5757
+ remainingMessage: "To see more component types, ask me to retrieve the next page using the pageNext cursor."
5758
+ });
5759
+ return createSuccessResponse("Component types retrieved successfully", {
5760
+ componentTypes: summarized,
5761
+ total: componentTypes.total,
5762
+ limit: componentTypes.limit,
5763
+ pages: componentTypes.pages
5764
+ });
5836
5765
  }
5837
- /**
5838
- * Get entry tools
5839
- */
5840
- getEntryTools() {
5841
- return createEntryTools(this.config);
5766
+ return withErrorHandling(tool2, "Error listing component types");
5767
+ }
5768
+
5769
+ // src/tools/exo/component-types/createComponentType.ts
5770
+ import { z as z86 } from "zod";
5771
+
5772
+ // src/types/componentTypeSchemas.ts
5773
+ import { z as z85 } from "zod";
5774
+ var URN_EXAMPLES = {
5775
+ "Contentful:ComponentType": "crn:contentful:::experience:spaces/{spaceId}/environments/{envId}/componentTypes/{id}",
5776
+ "Contentful:Fragment": "crn:contentful:::experience:spaces/{spaceId}/environments/{envId}/fragments/{id}",
5777
+ "Contentful:Template": "crn:contentful:::experience:spaces/{spaceId}/environments/{envId}/templates/{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 ComponentTypeResourceLinkSchema = resourceLinkSchema2("Contentful:ComponentType");
5799
+ var FragmentResourceLinkSchema = resourceLinkSchema2("Contentful:Fragment");
5800
+ var ViewportSchema = z85.object({
5801
+ id: z85.string().describe("Viewport identifier"),
5802
+ query: z85.string().describe("CSS media query string"),
5803
+ displayName: z85.string().describe("Human-readable viewport name"),
5804
+ previewSize: z85.string().describe('Preview size (e.g. "1024px")')
5805
+ });
5806
+ var DataTypeDefinitionSchema = z85.lazy(
5807
+ () => z85.discriminatedUnion("type", [
5808
+ z85.object({
5809
+ type: z85.enum(["String", "Number", "Integer", "Boolean"]),
5810
+ name: z85.string().optional(),
5811
+ required: z85.boolean().optional()
5812
+ }),
5813
+ z85.object({
5814
+ type: z85.literal("RichText"),
5815
+ name: z85.string().optional(),
5816
+ required: z85.boolean().optional()
5817
+ }),
5818
+ z85.object({
5819
+ type: z85.literal("Array"),
5820
+ name: z85.string().optional(),
5821
+ required: z85.boolean().optional(),
5822
+ items: DataTypeDefinitionSchema
5823
+ }),
5824
+ z85.object({
5825
+ type: z85.literal("Record"),
5826
+ name: z85.string().optional(),
5827
+ required: z85.boolean().optional(),
5828
+ fields: z85.record(z85.string(), DataTypeDefinitionSchema)
5829
+ }),
5830
+ z85.object({
5831
+ type: z85.literal("TypeRef"),
5832
+ name: z85.string().optional(),
5833
+ required: z85.boolean().optional(),
5834
+ ref: z85.object({
5835
+ sys: z85.object({
5836
+ type: z85.literal("ResourceLink"),
5837
+ linkType: z85.string(),
5838
+ urn: z85.string()
5839
+ })
5840
+ })
5841
+ }),
5842
+ z85.object({
5843
+ type: z85.literal("Literal"),
5844
+ name: z85.string().optional(),
5845
+ required: z85.boolean().optional(),
5846
+ value: z85.custom().describe("JSON literal value"),
5847
+ valueType: DataTypeDefinitionSchema
5848
+ }),
5849
+ z85.object({
5850
+ type: z85.literal("DiscriminatedUnion"),
5851
+ name: z85.string().optional(),
5852
+ required: z85.boolean().optional(),
5853
+ discriminator: z85.string(),
5854
+ members: z85.array(DataTypeDefinitionSchema)
5855
+ })
5856
+ ])
5857
+ );
5858
+ var ContentPropertySchema = z85.intersection(
5859
+ DataTypeDefinitionSchema,
5860
+ z85.object({
5861
+ id: z85.string().describe("Content property identifier"),
5862
+ name: z85.string().describe("Human-readable name"),
5863
+ required: z85.boolean().describe("Whether the property is required"),
5864
+ defaultValue: z85.unknown().optional().describe("Default value")
5865
+ })
5866
+ );
5867
+ var DTCG_DESIGN_PROPERTY_TYPES = [
5868
+ "DTCG.Color",
5869
+ "DTCG.Dimension",
5870
+ "DTCG.FontFamily",
5871
+ "DTCG.FontWeight",
5872
+ "DTCG.Duration",
5873
+ "DTCG.CubicBezier",
5874
+ "DTCG.Number",
5875
+ "DTCG.StrokeStyle",
5876
+ "DTCG.Border",
5877
+ "DTCG.Transition",
5878
+ "DTCG.Shadow",
5879
+ "DTCG.Gradient",
5880
+ "DTCG.Typography"
5881
+ ];
5882
+ var DesignPropertyCommonFieldsSchema = z85.object({
5883
+ id: z85.string().describe("Design property identifier"),
5884
+ name: z85.string().describe("Human-readable name"),
5885
+ description: z85.string().optional().describe("Optional description")
5886
+ });
5887
+ var StringDesignPropertySchema = DesignPropertyCommonFieldsSchema.extend({
5888
+ type: z85.literal("String"),
5889
+ fallbackValue: z85.object({
5890
+ type: z85.literal("ManualDesignValue"),
5891
+ value: z85.string()
5892
+ }).optional().describe("Manual fallback value for this design property"),
5893
+ validations: z85.array(
5894
+ z85.object({
5895
+ regexp: z85.object({
5896
+ pattern: z85.string().describe("Regular expression pattern")
5897
+ })
5898
+ })
5899
+ ).optional().describe("Regexp validations constraining allowed string values")
5900
+ });
5901
+ var BooleanDesignPropertySchema = DesignPropertyCommonFieldsSchema.extend({
5902
+ type: z85.literal("Boolean"),
5903
+ fallbackValue: z85.object({
5904
+ type: z85.literal("ManualDesignValue"),
5905
+ value: z85.boolean()
5906
+ }).optional().describe("Manual fallback value for this design property")
5907
+ });
5908
+ var DesignTokenValueSchema = z85.object({
5909
+ type: z85.literal("DesignToken"),
5910
+ value: z85.string().min(1).describe("Design token reference (non-empty)")
5911
+ });
5912
+ var TokenBackedDesignPropertySchema = DesignPropertyCommonFieldsSchema.extend({
5913
+ type: z85.enum(DTCG_DESIGN_PROPERTY_TYPES),
5914
+ fallbackValue: DesignTokenValueSchema.optional().describe(
5915
+ "Design-token-backed fallback value for this design property"
5916
+ ),
5917
+ allowedResources: z85.array(
5918
+ z85.object({
5919
+ type: z85.literal("DesignToken"),
5920
+ value: z85.string(),
5921
+ name: z85.string().optional()
5922
+ })
5923
+ ).optional().describe("Allowed design token resources")
5924
+ });
5925
+ var DesignPropertySchema = z85.union([
5926
+ StringDesignPropertySchema,
5927
+ BooleanDesignPropertySchema,
5928
+ TokenBackedDesignPropertySchema
5929
+ ]);
5930
+ var ManualDesignValueSchema = z85.object({
5931
+ type: z85.literal("ManualDesignValue"),
5932
+ value: z85.union([z85.string(), z85.number(), z85.boolean()])
5933
+ });
5934
+ var DesignPropertyValueSchema = z85.union([
5935
+ ManualDesignValueSchema,
5936
+ DesignTokenValueSchema
5937
+ ]);
5938
+ var DesignPropertyPointerValueSchema = z85.custom(
5939
+ (val) => typeof val === "string" && /^\$designProperties\//.test(val),
5940
+ { message: 'Must be a "$designProperties/..." pointer' }
5941
+ );
5942
+ var DimensionedDesignPropertyValueSchema = z85.record(
5943
+ z85.string(),
5944
+ DesignPropertyValueSchema
5945
+ );
5946
+ var ComponentTreeDesignPropertyValueSchema = z85.union([
5947
+ DesignPropertyValueSchema,
5948
+ DesignPropertyPointerValueSchema,
5949
+ DimensionedDesignPropertyValueSchema
5950
+ ]);
5951
+ var COMPONENT_TYPE_ALLOWED_RESOURCE_SOURCE = "crn:contentful:::experience:spaces/$self/environments/$self";
5952
+ var SlotDefinitionSchema = z85.object({
5953
+ id: z85.string().describe("Slot identifier"),
5954
+ name: z85.string().describe("Human-readable name"),
5955
+ required: z85.boolean().describe("Whether the slot must be filled"),
5956
+ validations: z85.array(
5957
+ z85.object({
5958
+ size: z85.object({
5959
+ min: z85.number().optional(),
5960
+ max: z85.number().optional()
5961
+ }).optional()
5962
+ })
5963
+ ).describe("Slot cardinality validations"),
5964
+ allowedResources: z85.array(
5965
+ z85.object({
5966
+ type: z85.literal("Contentful:ComponentType"),
5967
+ source: z85.literal(COMPONENT_TYPE_ALLOWED_RESOURCE_SOURCE),
5968
+ allowedTypes: z85.array(z85.string()).describe("IDs of component types allowed in this slot")
5969
+ })
5970
+ ).optional().describe("Constrains which component types may be placed in this slot")
5971
+ });
5972
+ var FragmentNodeSchema = z85.object({
5973
+ id: z85.string().describe("Node identifier"),
5974
+ name: z85.string().optional().describe("Optional display name"),
5975
+ nodeType: z85.literal("Fragment").describe('Must be "Fragment"'),
5976
+ fragment: FragmentResourceLinkSchema.describe("Resource link to the referenced fragment")
5977
+ });
5978
+ var SlotNodeSchema = z85.object({
5979
+ id: z85.string().describe("Node identifier"),
5980
+ nodeType: z85.literal("Slot").describe('Must be "Slot"'),
5981
+ slotId: z85.string().describe("ID of the slot definition to render")
5982
+ });
5983
+ var TreeNodeSchema = z85.lazy(
5984
+ () => z85.union([ComponentNodeSchema, FragmentNodeSchema, SlotNodeSchema])
5985
+ );
5986
+ var ComponentNodeSchema = z85.lazy(
5987
+ () => z85.object({
5988
+ id: z85.string().describe("Node identifier"),
5989
+ name: z85.string().optional().describe("Optional display name"),
5990
+ nodeType: z85.literal("Component").describe('Must be "Component"'),
5991
+ componentType: ComponentTypeResourceLinkSchema.describe(
5992
+ "Resource link to the component type to render"
5993
+ ),
5994
+ contentProperties: z85.union([
5995
+ z85.record(z85.string(), z85.unknown()),
5996
+ z85.string().describe('"$contentProperties/..." pointer')
5997
+ ]).describe(
5998
+ 'Content property bindings \u2014 values or "$contentProperties/..." pointers'
5999
+ ),
6000
+ designProperties: z85.record(z85.string(), ComponentTreeDesignPropertyValueSchema).describe(
6001
+ 'Design property values \u2014 ManualDesignValue, DesignTokenValue, or "$designProperties/..." pointers'
6002
+ ),
6003
+ slots: z85.record(z85.string(), z85.array(TreeNodeSchema)).describe("Child tree nodes keyed by slot ID")
6004
+ })
6005
+ );
6006
+ var TagLinkSchema = linkSchema2("Tag");
6007
+ var ConceptLinkSchema = linkSchema2("TaxonomyConcept");
6008
+ var ExoMetadataSchema = z85.object({
6009
+ tags: z85.array(TagLinkSchema).optional().describe("Tags attached to this entity"),
6010
+ concepts: z85.array(ConceptLinkSchema).optional().describe("Taxonomy concepts attached to this entity")
6011
+ });
6012
+ var ExperienceMetadataSchema = ExoMetadataSchema.extend({
6013
+ name: z85.string().optional().describe("Variant label for this metadata entry")
6014
+ });
6015
+ var DataAssemblyResourceLinkSchema = resourceLinkSchema2("Contentful:DataAssembly");
6016
+ var ExperienceContentBindingsSchema = z85.object({
6017
+ sys: DataAssemblyResourceLinkSchema.shape.sys,
6018
+ parameters: z85.record(
6019
+ z85.string(),
6020
+ z85.object({
6021
+ sys: z85.object({
6022
+ type: z85.literal("ResourceLink"),
6023
+ linkType: z85.string(),
6024
+ urn: z85.string()
6025
+ })
6026
+ })
6027
+ ).describe("Parameter bindings keyed by parameter ID")
6028
+ });
6029
+ var InlineFragmentNodeSchema = z85.lazy(
6030
+ () => z85.object({
6031
+ id: z85.string().describe("Node identifier"),
6032
+ nodeType: z85.literal("InlineFragment").describe('Must be "InlineFragment"'),
6033
+ componentType: ComponentTypeResourceLinkSchema.describe(
6034
+ "Resource link to the component type this inline fragment renders"
6035
+ ),
6036
+ designProperties: z85.record(z85.string(), DimensionedDesignPropertyValueSchema).describe("Design property values for this inline fragment"),
6037
+ contentBindings: ExperienceContentBindingsSchema.optional().describe(
6038
+ "Optional content bindings linking this inline fragment to a data assembly"
6039
+ ),
6040
+ slots: z85.record(z85.string(), z85.array(ExperienceSlotNodeSchema)).optional().describe("Child slot contents keyed by slot ID")
6041
+ })
6042
+ );
6043
+ var ExperienceSlotNodeSchema = z85.lazy(
6044
+ () => z85.union([FragmentNodeSchema, InlineFragmentNodeSchema])
6045
+ );
6046
+
6047
+ // src/tools/exo/component-types/createComponentType.ts
6048
+ var CreateComponentTypeToolParams = BaseToolSchema.extend({
6049
+ name: z86.string().describe("The name of the component type"),
6050
+ description: z86.string().describe("Description of the component type"),
6051
+ viewports: z86.array(ViewportSchema).describe("Viewport definitions for the component type (may be empty)"),
6052
+ contentProperties: z86.array(ContentPropertySchema).describe("Content property definitions (may be empty)"),
6053
+ designProperties: z86.array(DesignPropertySchema).describe("Design property definitions (may be empty)"),
6054
+ componentTree: z86.array(TreeNodeSchema).optional().describe("Optional component tree node definitions"),
6055
+ slots: z86.array(SlotDefinitionSchema).optional().describe("Optional slot definitions"),
6056
+ metadata: ExoMetadataSchema.optional().describe(
6057
+ "Optional ExO metadata (tags, concepts)"
6058
+ )
6059
+ });
6060
+ function createComponentTypeTool(config) {
6061
+ async function tool2(args) {
6062
+ assertEnvironmentNotProtected(
6063
+ args.environmentId,
6064
+ config.protectedEnvironments
6065
+ );
6066
+ const contentfulClient = createToolClient(config, args);
6067
+ const componentType = await contentfulClient.componentType.create(
6068
+ { spaceId: args.spaceId, environmentId: args.environmentId },
6069
+ {
6070
+ name: args.name,
6071
+ description: args.description,
6072
+ viewports: args.viewports,
6073
+ contentProperties: args.contentProperties,
6074
+ designProperties: args.designProperties,
6075
+ ...args.componentTree && { componentTree: args.componentTree },
6076
+ ...args.slots && { slots: args.slots },
6077
+ ...args.metadata && { metadata: args.metadata }
6078
+ }
6079
+ );
6080
+ return createSuccessResponse("Component type created successfully", {
6081
+ componentType
6082
+ });
5842
6083
  }
5843
- /**
5844
- * Get environment tools
5845
- */
5846
- getEnvironmentTools() {
5847
- return createEnvironmentTools(this.config);
6084
+ return withErrorHandling(tool2, "Error creating component type");
6085
+ }
6086
+
6087
+ // src/tools/exo/component-types/upsertComponentType.ts
6088
+ import { z as z87 } from "zod";
6089
+ var UpsertComponentTypeToolParams = BaseToolSchema.extend({
6090
+ componentTypeId: z87.string().describe("The ID of the component type to update"),
6091
+ version: z87.number().describe(
6092
+ "REQUIRED. The component type's sys.version as returned by get_component_type. You must call get_component_type first to read the current state and version. The update is rejected if this does not match the current version, which means the component type changed since you read it."
6093
+ ),
6094
+ name: z87.string().optional().describe("The name of the component type"),
6095
+ description: z87.string().optional().describe("Description of the component type"),
6096
+ viewports: z87.array(ViewportSchema).optional().describe("Viewport definitions; replaces existing viewports if provided"),
6097
+ contentProperties: z87.array(ContentPropertySchema).optional().describe("Content property definitions; replaces existing if provided"),
6098
+ designProperties: z87.array(DesignPropertySchema).optional().describe("Design property definitions; replaces existing if provided"),
6099
+ componentTree: z87.array(TreeNodeSchema).optional().describe("Component tree node definitions; replaces existing if provided"),
6100
+ slots: z87.array(SlotDefinitionSchema).optional().describe("Slot definitions; replaces existing if provided"),
6101
+ metadata: ExoMetadataSchema.optional().describe(
6102
+ "ExO metadata (tags, concepts); replaces existing if provided"
6103
+ )
6104
+ });
6105
+ function upsertComponentTypeTool(config) {
6106
+ async function tool2(args) {
6107
+ assertEnvironmentNotProtected(
6108
+ args.environmentId,
6109
+ config.protectedEnvironments
6110
+ );
6111
+ const params = {
6112
+ spaceId: args.spaceId,
6113
+ environmentId: args.environmentId,
6114
+ componentTypeId: args.componentTypeId
6115
+ };
6116
+ const contentfulClient = createToolClient(config, args);
6117
+ const current = await contentfulClient.componentType.get(params);
6118
+ if (args.version !== current.sys.version) {
6119
+ throw new Error(
6120
+ `Version conflict: the component type has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the component type with get_component_type and retry the update with the latest sys.version.`
6121
+ );
6122
+ }
6123
+ const componentType = await contentfulClient.componentType.upsert(params, {
6124
+ sys: {
6125
+ id: current.sys.id,
6126
+ type: "ComponentType",
6127
+ version: current.sys.version
6128
+ },
6129
+ name: args.name ?? current.name,
6130
+ description: args.description ?? current.description,
6131
+ viewports: args.viewports ?? current.viewports,
6132
+ contentProperties: args.contentProperties ?? current.contentProperties,
6133
+ designProperties: args.designProperties ?? current.designProperties,
6134
+ ...args.componentTree ?? current.componentTree ? { componentTree: args.componentTree ?? current.componentTree } : {},
6135
+ ...args.slots ?? current.slots ? { slots: args.slots ?? current.slots } : {},
6136
+ ...args.metadata ?? current.metadata ? { metadata: args.metadata ?? current.metadata } : {},
6137
+ ...current.dataAssemblies ? { dataAssemblies: current.dataAssemblies } : {}
6138
+ });
6139
+ return createSuccessResponse("Component type updated successfully", {
6140
+ componentType
6141
+ });
5848
6142
  }
5849
- /**
5850
- * Get locale tools
5851
- */
5852
- getLocaleTools() {
5853
- return createLocaleTools(this.config);
6143
+ return withErrorHandling(tool2, "Error updating component type");
6144
+ }
6145
+
6146
+ // src/tools/exo/component-types/deleteComponentType.ts
6147
+ import { z as z88 } from "zod";
6148
+ var DeleteComponentTypeToolParams = BaseToolSchema.extend({
6149
+ componentTypeId: z88.string().describe("The ID of the component type to delete"),
6150
+ confirm: z88.boolean().optional().describe(
6151
+ "Set to true on the second call to actually perform the deletion. Required together with confirmToken."
6152
+ ),
6153
+ confirmToken: z88.string().optional().describe(
6154
+ "Token returned by the preview call; must be supplied with confirm: true."
6155
+ )
6156
+ });
6157
+ function deleteComponentTypeTool(config) {
6158
+ async function tool2(args) {
6159
+ assertEnvironmentNotProtected(
6160
+ args.environmentId,
6161
+ config.protectedEnvironments
6162
+ );
6163
+ const params = {
6164
+ spaceId: args.spaceId,
6165
+ environmentId: args.environmentId,
6166
+ componentTypeId: args.componentTypeId
6167
+ };
6168
+ const contentfulClient = createToolClient(config, args);
6169
+ const componentType = await contentfulClient.componentType.get(params);
6170
+ const expectedToken = buildConfirmToken(
6171
+ "componentType",
6172
+ args.componentTypeId,
6173
+ componentType.sys.version
6174
+ );
6175
+ if (args.confirm !== true || args.confirmToken !== expectedToken) {
6176
+ return createSuccessResponse(
6177
+ `${CONFIRMATION_MESSAGE_PREFIX} component type`,
6178
+ buildConfirmationPreview(
6179
+ "componentType",
6180
+ args.componentTypeId,
6181
+ { componentType },
6182
+ expectedToken
6183
+ )
6184
+ );
6185
+ }
6186
+ await contentfulClient.componentType.delete(params);
6187
+ return createSuccessResponse("Component type deleted successfully", {
6188
+ componentTypeId: args.componentTypeId
6189
+ });
5854
6190
  }
5855
- /**
5856
- * Get organization tools
5857
- */
5858
- getOrgTools() {
5859
- return createOrgTools(this.config);
6191
+ return withErrorHandling(tool2, "Error deleting component type");
6192
+ }
6193
+
6194
+ // src/tools/exo/component-types/publishComponentType.ts
6195
+ import { z as z89 } from "zod";
6196
+ var PublishComponentTypeToolParams = BaseToolSchema.extend({
6197
+ componentTypeId: z89.string().describe("The ID of the component type to publish"),
6198
+ version: z89.number().describe(
6199
+ "REQUIRED. The component type's sys.version as returned by get_component_type. You must call get_component_type first to read the current state and version. The publish is rejected if this does not match the current version, which means the component type changed since you read it."
6200
+ )
6201
+ });
6202
+ function publishComponentTypeTool(config) {
6203
+ async function tool2(args) {
6204
+ assertEnvironmentNotProtected(
6205
+ args.environmentId,
6206
+ config.protectedEnvironments
6207
+ );
6208
+ const params = {
6209
+ spaceId: args.spaceId,
6210
+ environmentId: args.environmentId,
6211
+ componentTypeId: args.componentTypeId
6212
+ };
6213
+ const contentfulClient = createToolClient(config, args);
6214
+ const current = await contentfulClient.componentType.get(params);
6215
+ if (args.version !== current.sys.version) {
6216
+ throw new Error(
6217
+ `Version conflict: the component type has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the component type with get_component_type and retry with the latest sys.version.`
6218
+ );
6219
+ }
6220
+ const componentType = await contentfulClient.componentType.publish({
6221
+ ...params,
6222
+ version: args.version
6223
+ });
6224
+ return createSuccessResponse("Component type published successfully", {
6225
+ componentType
6226
+ });
5860
6227
  }
5861
- /**
5862
- * Get space tools
5863
- */
5864
- getSpaceTools() {
5865
- return createSpaceTools(this.config);
6228
+ return withErrorHandling(tool2, "Error publishing component type");
6229
+ }
6230
+
6231
+ // src/tools/exo/component-types/unpublishComponentType.ts
6232
+ import { z as z90 } from "zod";
6233
+ var UnpublishComponentTypeToolParams = BaseToolSchema.extend({
6234
+ componentTypeId: z90.string().describe("The ID of the component type to unpublish"),
6235
+ version: z90.number().describe(
6236
+ "REQUIRED. The component type's sys.version as returned by get_component_type. You must call get_component_type first to read the current state and version. The unpublish is rejected if this does not match the current version, which means the component type changed since you read it."
6237
+ )
6238
+ });
6239
+ function unpublishComponentTypeTool(config) {
6240
+ async function tool2(args) {
6241
+ assertEnvironmentNotProtected(
6242
+ args.environmentId,
6243
+ config.protectedEnvironments
6244
+ );
6245
+ const params = {
6246
+ spaceId: args.spaceId,
6247
+ environmentId: args.environmentId,
6248
+ componentTypeId: args.componentTypeId
6249
+ };
6250
+ const contentfulClient = createToolClient(config, args);
6251
+ const current = await contentfulClient.componentType.get(params);
6252
+ if (args.version !== current.sys.version) {
6253
+ throw new Error(
6254
+ `Version conflict: the component type has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the component type with get_component_type and retry with the latest sys.version.`
6255
+ );
6256
+ }
6257
+ const componentType = await contentfulClient.componentType.unpublish({
6258
+ ...params,
6259
+ version: args.version
6260
+ });
6261
+ return createSuccessResponse("Component type unpublished successfully", {
6262
+ componentType
6263
+ });
5866
6264
  }
5867
- /**
5868
- * Get tag tools
5869
- */
5870
- getTagTools() {
5871
- return createTagTools(this.config);
6265
+ return withErrorHandling(tool2, "Error unpublishing component type");
6266
+ }
6267
+
6268
+ // src/tools/exo/component-types/register.ts
6269
+ function createComponentTypeTools(config) {
6270
+ const getComponentType = getComponentTypeTool(config);
6271
+ const listComponentTypes = listComponentTypesTool(config);
6272
+ const createComponentType = createComponentTypeTool(config);
6273
+ const upsertComponentType = upsertComponentTypeTool(config);
6274
+ const deleteComponentType = deleteComponentTypeTool(config);
6275
+ const publishComponentType = publishComponentTypeTool(config);
6276
+ const unpublishComponentType = unpublishComponentTypeTool(config);
6277
+ return {
6278
+ getComponentType: {
6279
+ title: "get_component_type",
6280
+ description: "Get details about a specific ExO component type (a reusable section/pattern template defining slots, content properties, and design properties).",
6281
+ inputParams: GetComponentTypeToolParams.shape,
6282
+ annotations: {
6283
+ readOnlyHint: true,
6284
+ destructiveHint: false,
6285
+ openWorldHint: false
6286
+ },
6287
+ tool: getComponentType
6288
+ },
6289
+ listComponentTypes: {
6290
+ title: "list_component_types",
6291
+ description: "List ExO component types in a space and environment. Returns a maximum of 10 items per request; use the pageNext cursor (returned in pages.next) to paginate.",
6292
+ inputParams: ListComponentTypesToolParams.shape,
6293
+ annotations: {
6294
+ readOnlyHint: true,
6295
+ destructiveHint: false,
6296
+ openWorldHint: false
6297
+ },
6298
+ tool: listComponentTypes
6299
+ },
6300
+ createComponentType: {
6301
+ title: "create_component_type",
6302
+ description: "Create a new ExO component type.",
6303
+ inputParams: CreateComponentTypeToolParams.shape,
6304
+ annotations: {
6305
+ readOnlyHint: false,
6306
+ destructiveHint: false,
6307
+ idempotentHint: false,
6308
+ openWorldHint: false
6309
+ },
6310
+ tool: createComponentType
6311
+ },
6312
+ upsertComponentType: {
6313
+ title: "upsert_component_type",
6314
+ description: "Update an existing ExO component type. You MUST call get_component_type 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 type fields, so you only need to provide the fields you want to change. If the version is stale (the component type changed since you read it), the update is rejected and you must re-fetch with get_component_type.",
6315
+ inputParams: UpsertComponentTypeToolParams.shape,
6316
+ annotations: {
6317
+ readOnlyHint: false,
6318
+ destructiveHint: false,
6319
+ idempotentHint: false,
6320
+ openWorldHint: false
6321
+ },
6322
+ tool: upsertComponentType
6323
+ },
6324
+ deleteComponentType: {
6325
+ title: "delete_component_type",
6326
+ description: "Delete an ExO component type. Two-phase: the first call (without confirm/confirmToken) returns a preview and a confirmToken. To complete the deletion, call again with the same componentTypeId, confirm: true, and the confirmToken from the preview.",
6327
+ inputParams: DeleteComponentTypeToolParams.shape,
6328
+ annotations: {
6329
+ readOnlyHint: false,
6330
+ destructiveHint: true,
6331
+ idempotentHint: false,
6332
+ openWorldHint: false
6333
+ },
6334
+ tool: deleteComponentType
6335
+ },
6336
+ publishComponentType: {
6337
+ title: "publish_component_type",
6338
+ description: "Publish an ExO component type. You MUST call get_component_type 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_type.",
6339
+ inputParams: PublishComponentTypeToolParams.shape,
6340
+ annotations: {
6341
+ readOnlyHint: false,
6342
+ destructiveHint: true,
6343
+ idempotentHint: true,
6344
+ openWorldHint: false
6345
+ },
6346
+ tool: publishComponentType
6347
+ },
6348
+ unpublishComponentType: {
6349
+ title: "unpublish_component_type",
6350
+ description: "Unpublish an ExO component type. You MUST call get_component_type 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_type.",
6351
+ inputParams: UnpublishComponentTypeToolParams.shape,
6352
+ annotations: {
6353
+ readOnlyHint: false,
6354
+ destructiveHint: true,
6355
+ idempotentHint: true,
6356
+ openWorldHint: false
6357
+ },
6358
+ tool: unpublishComponentType
6359
+ }
6360
+ };
6361
+ }
6362
+
6363
+ // src/tools/exo/fragments/getFragment.ts
6364
+ import { z as z91 } from "zod";
6365
+ var GetFragmentToolParams = BaseToolSchema.extend({
6366
+ fragmentId: z91.string().describe("The ID of the fragment to retrieve details for")
6367
+ });
6368
+ function getFragmentTool(config) {
6369
+ async function tool2(args) {
6370
+ const contentfulClient = createToolClient(config, args);
6371
+ const fragment = await contentfulClient.fragment.get({
6372
+ spaceId: args.spaceId,
6373
+ environmentId: args.environmentId,
6374
+ fragmentId: args.fragmentId
6375
+ });
6376
+ return createSuccessResponse("Fragment retrieved successfully", {
6377
+ fragment
6378
+ });
6379
+ }
6380
+ return withErrorHandling(tool2, "Error retrieving fragment");
6381
+ }
6382
+
6383
+ // src/tools/exo/fragments/listFragments.ts
6384
+ import { z as z92 } from "zod";
6385
+ var ListFragmentsToolParams = BaseToolSchema.extend({
6386
+ limit: z92.number().optional().describe("Maximum number of fragments to return (max 10)"),
6387
+ pageNext: z92.string().optional().describe("Cursor token to fetch the next page of results"),
6388
+ pagePrev: z92.string().optional().describe("Cursor token to fetch the previous page of results"),
6389
+ order: z92.string().optional().describe("Order fragments by this field (e.g. sys.createdAt)")
6390
+ });
6391
+ function listFragmentsTool(config) {
6392
+ async function tool2(args) {
6393
+ const contentfulClient = createToolClient(config, args);
6394
+ const fragments = await contentfulClient.fragment.getMany({
6395
+ spaceId: args.spaceId,
6396
+ environmentId: args.environmentId,
6397
+ query: {
6398
+ limit: Math.min(args.limit || 10, 10),
6399
+ ...args.pageNext && { pageNext: args.pageNext },
6400
+ ...args.pagePrev && { pagePrev: args.pagePrev },
6401
+ ...args.order && { order: args.order }
6402
+ }
6403
+ });
6404
+ const summarized = summarizeData(fragments, {
6405
+ maxItems: 10,
6406
+ remainingMessage: "To see more fragments, ask me to retrieve the next page using the pageNext cursor."
6407
+ });
6408
+ return createSuccessResponse("Fragments retrieved successfully", {
6409
+ fragments: summarized,
6410
+ total: fragments.total,
6411
+ limit: fragments.limit,
6412
+ pages: fragments.pages
6413
+ });
6414
+ }
6415
+ return withErrorHandling(tool2, "Error listing fragments");
6416
+ }
6417
+
6418
+ // src/tools/exo/fragments/createFragment.ts
6419
+ import { z as z93 } from "zod";
6420
+ var CreateFragmentToolParams = BaseToolSchema.extend({
6421
+ name: z93.string().describe("The name of the fragment"),
6422
+ description: z93.string().describe("Description of the fragment"),
6423
+ componentType: ComponentTypeResourceLinkSchema.describe(
6424
+ "Resource link to the component type this fragment is based on"
6425
+ ),
6426
+ viewports: z93.array(ViewportSchema).describe("Viewport definitions (may be empty)"),
6427
+ designProperties: z93.record(z93.string(), DimensionedDesignPropertyValueSchema).describe("Design property values keyed by property ID (may be empty object)"),
6428
+ contentBindings: ExperienceContentBindingsSchema.optional().describe(
6429
+ "Optional content bindings for the fragment"
6430
+ ),
6431
+ slots: z93.record(z93.string(), z93.array(ExperienceSlotNodeSchema)).optional().describe("Optional slot node definitions keyed by slot ID"),
6432
+ metadata: ExperienceMetadataSchema.optional().describe(
6433
+ "Optional ExO metadata (tags, concepts)"
6434
+ )
6435
+ });
6436
+ function createFragmentTool(config) {
6437
+ async function tool2(args) {
6438
+ assertEnvironmentNotProtected(
6439
+ args.environmentId,
6440
+ config.protectedEnvironments
6441
+ );
6442
+ const contentfulClient = createToolClient(config, args);
6443
+ const fragment = await contentfulClient.fragment.create(
6444
+ { spaceId: args.spaceId, environmentId: args.environmentId },
6445
+ {
6446
+ name: args.name,
6447
+ description: args.description,
6448
+ componentType: args.componentType,
6449
+ viewports: args.viewports,
6450
+ designProperties: args.designProperties,
6451
+ ...args.contentBindings && { contentBindings: args.contentBindings },
6452
+ ...args.slots && { slots: args.slots },
6453
+ ...args.metadata && { metadata: args.metadata }
6454
+ }
6455
+ );
6456
+ return createSuccessResponse("Fragment created successfully", {
6457
+ fragment
6458
+ });
6459
+ }
6460
+ return withErrorHandling(tool2, "Error creating fragment");
6461
+ }
6462
+
6463
+ // src/tools/exo/fragments/updateFragment.ts
6464
+ import { z as z94 } from "zod";
6465
+ var UpdateFragmentToolParams = BaseToolSchema.extend({
6466
+ fragmentId: z94.string().describe("The ID of the fragment to update"),
6467
+ version: z94.number().describe(
6468
+ "REQUIRED. The fragment's sys.version as returned by get_fragment. You must call get_fragment first to read the current state and version. The update is rejected if this does not match the current version, which means the fragment changed since you read it."
6469
+ ),
6470
+ name: z94.string().optional().describe("The name of the fragment"),
6471
+ description: z94.string().optional().describe("Description of the fragment"),
6472
+ viewports: z94.array(ViewportSchema).optional().describe("Viewport definitions; replaces existing viewports if provided"),
6473
+ designProperties: z94.record(z94.string(), DimensionedDesignPropertyValueSchema).optional().describe("Design property values; replaces existing if provided"),
6474
+ contentBindings: ExperienceContentBindingsSchema.optional().describe(
6475
+ "Content bindings; replaces existing if provided"
6476
+ ),
6477
+ slots: z94.record(z94.string(), z94.array(ExperienceSlotNodeSchema)).optional().describe("Slot node definitions; replaces existing if provided"),
6478
+ metadata: ExperienceMetadataSchema.optional().describe(
6479
+ "ExO metadata (tags, concepts); replaces existing if provided"
6480
+ )
6481
+ });
6482
+ function updateFragmentTool(config) {
6483
+ async function tool2(args) {
6484
+ assertEnvironmentNotProtected(
6485
+ args.environmentId,
6486
+ config.protectedEnvironments
6487
+ );
6488
+ const params = {
6489
+ spaceId: args.spaceId,
6490
+ environmentId: args.environmentId,
6491
+ fragmentId: args.fragmentId
6492
+ };
6493
+ const contentfulClient = createToolClient(config, args);
6494
+ const current = await contentfulClient.fragment.get(params);
6495
+ if (args.version !== current.sys.version) {
6496
+ throw new Error(
6497
+ `Version conflict: the fragment has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the fragment with get_fragment and retry the update with the latest sys.version.`
6498
+ );
6499
+ }
6500
+ const fragment = await contentfulClient.fragment.upsert(params, {
6501
+ sys: {
6502
+ id: current.sys.id,
6503
+ type: "Fragment",
6504
+ version: current.sys.version
6505
+ },
6506
+ name: args.name ?? current.name,
6507
+ description: args.description ?? current.description,
6508
+ viewports: args.viewports ?? current.viewports,
6509
+ designProperties: args.designProperties ?? current.designProperties,
6510
+ ...args.contentBindings ?? current.contentBindings ? { contentBindings: args.contentBindings ?? current.contentBindings } : {},
6511
+ ...args.slots ?? current.slots ? { slots: args.slots ?? current.slots } : {},
6512
+ ...args.metadata ?? current.metadata ? { metadata: args.metadata ?? current.metadata } : {}
6513
+ });
6514
+ return createSuccessResponse("Fragment updated successfully", {
6515
+ fragment
6516
+ });
6517
+ }
6518
+ return withErrorHandling(tool2, "Error updating fragment");
6519
+ }
6520
+
6521
+ // src/tools/exo/fragments/deleteFragment.ts
6522
+ import { z as z95 } from "zod";
6523
+ var DeleteFragmentToolParams = BaseToolSchema.extend({
6524
+ fragmentId: z95.string().describe("The ID of the fragment to delete"),
6525
+ confirm: z95.boolean().optional().describe(
6526
+ "Set to true on the second call to actually perform the deletion. Required together with confirmToken."
6527
+ ),
6528
+ confirmToken: z95.string().optional().describe(
6529
+ "Token returned by the preview call; must be supplied with confirm: true."
6530
+ )
6531
+ });
6532
+ function deleteFragmentTool(config) {
6533
+ async function tool2(args) {
6534
+ assertEnvironmentNotProtected(
6535
+ args.environmentId,
6536
+ config.protectedEnvironments
6537
+ );
6538
+ const params = {
6539
+ spaceId: args.spaceId,
6540
+ environmentId: args.environmentId,
6541
+ fragmentId: args.fragmentId
6542
+ };
6543
+ const contentfulClient = createToolClient(config, args);
6544
+ const fragment = await contentfulClient.fragment.get(params);
6545
+ const expectedToken = buildConfirmToken(
6546
+ "fragment",
6547
+ args.fragmentId,
6548
+ fragment.sys.version
6549
+ );
6550
+ if (args.confirm !== true || args.confirmToken !== expectedToken) {
6551
+ return createSuccessResponse(
6552
+ `${CONFIRMATION_MESSAGE_PREFIX} fragment`,
6553
+ buildConfirmationPreview(
6554
+ "fragment",
6555
+ args.fragmentId,
6556
+ { fragment },
6557
+ expectedToken
6558
+ )
6559
+ );
6560
+ }
6561
+ await contentfulClient.fragment.delete(params);
6562
+ return createSuccessResponse("Fragment deleted successfully", {
6563
+ fragmentId: args.fragmentId
6564
+ });
6565
+ }
6566
+ return withErrorHandling(tool2, "Error deleting fragment");
6567
+ }
6568
+
6569
+ // src/tools/exo/fragments/publishFragment.ts
6570
+ import { z as z96 } from "zod";
6571
+ var PublishFragmentToolParams = BaseToolSchema.extend({
6572
+ fragmentId: z96.string().describe("The ID of the fragment to publish"),
6573
+ version: z96.number().describe(
6574
+ "REQUIRED. The fragment's sys.version as returned by get_fragment. You must call get_fragment first to read the current state and version. The publish is rejected if this does not match the current version, which means the fragment changed since you read it."
6575
+ )
6576
+ });
6577
+ function publishFragmentTool(config) {
6578
+ async function tool2(args) {
6579
+ assertEnvironmentNotProtected(
6580
+ args.environmentId,
6581
+ config.protectedEnvironments
6582
+ );
6583
+ const params = {
6584
+ spaceId: args.spaceId,
6585
+ environmentId: args.environmentId,
6586
+ fragmentId: args.fragmentId
6587
+ };
6588
+ const contentfulClient = createToolClient(config, args);
6589
+ const current = await contentfulClient.fragment.get(params);
6590
+ if (args.version !== current.sys.version) {
6591
+ throw new Error(
6592
+ `Version conflict: the fragment has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the fragment with get_fragment and retry with the latest sys.version.`
6593
+ );
6594
+ }
6595
+ const fragment = await contentfulClient.fragment.publish({
6596
+ ...params,
6597
+ version: args.version
6598
+ });
6599
+ return createSuccessResponse("Fragment published successfully", {
6600
+ fragment
6601
+ });
6602
+ }
6603
+ return withErrorHandling(tool2, "Error publishing fragment");
6604
+ }
6605
+
6606
+ // src/tools/exo/fragments/unpublishFragment.ts
6607
+ import { z as z97 } from "zod";
6608
+ var UnpublishFragmentToolParams = BaseToolSchema.extend({
6609
+ fragmentId: z97.string().describe("The ID of the fragment to unpublish"),
6610
+ version: z97.number().describe(
6611
+ "REQUIRED. The fragment's sys.version as returned by get_fragment. You must call get_fragment first to read the current state and version. The unpublish is rejected if this does not match the current version, which means the fragment changed since you read it."
6612
+ )
6613
+ });
6614
+ function unpublishFragmentTool(config) {
6615
+ async function tool2(args) {
6616
+ assertEnvironmentNotProtected(
6617
+ args.environmentId,
6618
+ config.protectedEnvironments
6619
+ );
6620
+ const params = {
6621
+ spaceId: args.spaceId,
6622
+ environmentId: args.environmentId,
6623
+ fragmentId: args.fragmentId
6624
+ };
6625
+ const contentfulClient = createToolClient(config, args);
6626
+ const current = await contentfulClient.fragment.get(params);
6627
+ if (args.version !== current.sys.version) {
6628
+ throw new Error(
6629
+ `Version conflict: the fragment has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the fragment with get_fragment and retry with the latest sys.version.`
6630
+ );
6631
+ }
6632
+ const fragment = await contentfulClient.fragment.unpublish({
6633
+ ...params,
6634
+ version: args.version
6635
+ });
6636
+ return createSuccessResponse("Fragment unpublished successfully", {
6637
+ fragment
6638
+ });
6639
+ }
6640
+ return withErrorHandling(tool2, "Error unpublishing fragment");
6641
+ }
6642
+
6643
+ // src/tools/exo/fragments/register.ts
6644
+ function createFragmentTools(config) {
6645
+ const getFragment = getFragmentTool(config);
6646
+ const listFragments = listFragmentsTool(config);
6647
+ const createFragment = createFragmentTool(config);
6648
+ const updateFragment = updateFragmentTool(config);
6649
+ const deleteFragment = deleteFragmentTool(config);
6650
+ const publishFragment = publishFragmentTool(config);
6651
+ const unpublishFragment = unpublishFragmentTool(config);
6652
+ return {
6653
+ getFragment: {
6654
+ title: "get_fragment",
6655
+ description: "Get details about a specific ExO fragment (a reusable content unit that can be referenced across multiple Experiences and ComponentTypes).",
6656
+ inputParams: GetFragmentToolParams.shape,
6657
+ annotations: {
6658
+ readOnlyHint: true,
6659
+ destructiveHint: false,
6660
+ openWorldHint: false
6661
+ },
6662
+ tool: getFragment
6663
+ },
6664
+ listFragments: {
6665
+ title: "list_fragments",
6666
+ description: "List ExO fragments in a space and environment. Returns a maximum of 10 items per request; use the pageNext cursor (returned in pages.next) to paginate.",
6667
+ inputParams: ListFragmentsToolParams.shape,
6668
+ annotations: {
6669
+ readOnlyHint: true,
6670
+ destructiveHint: false,
6671
+ openWorldHint: false
6672
+ },
6673
+ tool: listFragments
6674
+ },
6675
+ createFragment: {
6676
+ title: "create_fragment",
6677
+ description: "Create a new ExO fragment.",
6678
+ inputParams: CreateFragmentToolParams.shape,
6679
+ annotations: {
6680
+ readOnlyHint: false,
6681
+ destructiveHint: false,
6682
+ idempotentHint: false,
6683
+ openWorldHint: false
6684
+ },
6685
+ tool: createFragment
6686
+ },
6687
+ updateFragment: {
6688
+ title: "update_fragment",
6689
+ description: "Update an existing ExO fragment. You MUST call get_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 fragment fields, so you only need to provide the fields you want to change. If the version is stale (the fragment changed since you read it), the update is rejected and you must re-fetch with get_fragment.",
6690
+ inputParams: UpdateFragmentToolParams.shape,
6691
+ annotations: {
6692
+ readOnlyHint: false,
6693
+ destructiveHint: false,
6694
+ idempotentHint: false,
6695
+ openWorldHint: false
6696
+ },
6697
+ tool: updateFragment
6698
+ },
6699
+ deleteFragment: {
6700
+ title: "delete_fragment",
6701
+ description: "Delete an ExO fragment. Two-phase: the first call (without confirm/confirmToken) returns a preview and a confirmToken. To complete the deletion, call again with the same fragmentId, confirm: true, and the confirmToken from the preview.",
6702
+ inputParams: DeleteFragmentToolParams.shape,
6703
+ annotations: {
6704
+ readOnlyHint: false,
6705
+ destructiveHint: true,
6706
+ idempotentHint: false,
6707
+ openWorldHint: false
6708
+ },
6709
+ tool: deleteFragment
6710
+ },
6711
+ publishFragment: {
6712
+ title: "publish_fragment",
6713
+ description: "Publish an ExO fragment. You MUST call get_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_fragment.",
6714
+ inputParams: PublishFragmentToolParams.shape,
6715
+ annotations: {
6716
+ readOnlyHint: false,
6717
+ destructiveHint: true,
6718
+ idempotentHint: true,
6719
+ openWorldHint: false
6720
+ },
6721
+ tool: publishFragment
6722
+ },
6723
+ unpublishFragment: {
6724
+ title: "unpublish_fragment",
6725
+ description: "Unpublish an ExO fragment. You MUST call get_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_fragment.",
6726
+ inputParams: UnpublishFragmentToolParams.shape,
6727
+ annotations: {
6728
+ readOnlyHint: false,
6729
+ destructiveHint: true,
6730
+ idempotentHint: true,
6731
+ openWorldHint: false
6732
+ },
6733
+ tool: unpublishFragment
6734
+ }
6735
+ };
6736
+ }
6737
+
6738
+ // src/tools/exo/templates/getTemplate.ts
6739
+ import { z as z98 } from "zod";
6740
+ var GetTemplateToolParams = BaseToolSchema.extend({
6741
+ templateId: z98.string().describe("The ID of the template to retrieve details for")
6742
+ });
6743
+ function getTemplateTool(config) {
6744
+ async function tool2(args) {
6745
+ const contentfulClient = createToolClient(config, args);
6746
+ const template = await contentfulClient.template.get({
6747
+ spaceId: args.spaceId,
6748
+ environmentId: args.environmentId,
6749
+ templateId: args.templateId
6750
+ });
6751
+ return createSuccessResponse("Template retrieved successfully", {
6752
+ template
6753
+ });
6754
+ }
6755
+ return withErrorHandling(tool2, "Error retrieving template");
6756
+ }
6757
+
6758
+ // src/tools/exo/templates/listTemplates.ts
6759
+ import { z as z99 } from "zod";
6760
+ var ListTemplatesToolParams = BaseToolSchema.extend({
6761
+ limit: z99.number().optional().describe("Maximum number of templates to return (max 10)"),
6762
+ pageNext: z99.string().optional().describe("Cursor token to fetch the next page of results"),
6763
+ pagePrev: z99.string().optional().describe("Cursor token to fetch the previous page of results"),
6764
+ order: z99.string().optional().describe("Order templates by this field (e.g. sys.createdAt)")
6765
+ });
6766
+ function listTemplatesTool(config) {
6767
+ async function tool2(args) {
6768
+ const contentfulClient = createToolClient(config, args);
6769
+ const templates = await contentfulClient.template.getMany({
6770
+ spaceId: args.spaceId,
6771
+ environmentId: args.environmentId,
6772
+ query: {
6773
+ limit: Math.min(args.limit || 10, 10),
6774
+ ...args.pageNext && { pageNext: args.pageNext },
6775
+ ...args.pagePrev && { pagePrev: args.pagePrev },
6776
+ ...args.order && { order: args.order }
6777
+ }
6778
+ });
6779
+ const summarized = summarizeData(templates, {
6780
+ maxItems: 10,
6781
+ remainingMessage: "To see more templates, ask me to retrieve the next page using the pageNext cursor."
6782
+ });
6783
+ return createSuccessResponse("Templates retrieved successfully", {
6784
+ templates: summarized,
6785
+ total: templates.total,
6786
+ limit: templates.limit,
6787
+ pages: templates.pages
6788
+ });
6789
+ }
6790
+ return withErrorHandling(tool2, "Error listing templates");
6791
+ }
6792
+
6793
+ // src/tools/exo/templates/createTemplate.ts
6794
+ import { z as z100 } from "zod";
6795
+ var CreateTemplateToolParams = BaseToolSchema.extend({
6796
+ name: z100.string().describe("The name of the template"),
6797
+ description: z100.string().describe("Description of the template"),
6798
+ viewports: z100.array(ViewportSchema).describe("Viewport definitions for the template (may be empty)"),
6799
+ contentProperties: z100.array(ContentPropertySchema).describe("Content property definitions (may be empty)"),
6800
+ designProperties: z100.array(DesignPropertySchema).describe("Design property definitions (may be empty)"),
6801
+ componentTree: z100.array(TreeNodeSchema).optional().describe("Optional component tree node definitions"),
6802
+ slots: z100.array(SlotDefinitionSchema).optional().describe("Optional slot definitions"),
6803
+ metadata: ExoMetadataSchema.optional().describe(
6804
+ "Optional ExO metadata (tags, concepts)"
6805
+ )
6806
+ });
6807
+ function createTemplateTool(config) {
6808
+ async function tool2(args) {
6809
+ assertEnvironmentNotProtected(
6810
+ args.environmentId,
6811
+ config.protectedEnvironments
6812
+ );
6813
+ const contentfulClient = createToolClient(config, args);
6814
+ const template = await contentfulClient.template.create(
6815
+ { spaceId: args.spaceId, environmentId: args.environmentId },
6816
+ {
6817
+ name: args.name,
6818
+ description: args.description,
6819
+ viewports: args.viewports,
6820
+ contentProperties: args.contentProperties,
6821
+ designProperties: args.designProperties,
6822
+ ...args.componentTree && { componentTree: args.componentTree },
6823
+ ...args.slots && { slots: args.slots },
6824
+ ...args.metadata && { metadata: args.metadata }
6825
+ }
6826
+ );
6827
+ return createSuccessResponse("Template created successfully", {
6828
+ template
6829
+ });
6830
+ }
6831
+ return withErrorHandling(tool2, "Error creating template");
6832
+ }
6833
+
6834
+ // src/tools/exo/templates/upsertTemplate.ts
6835
+ import { z as z101 } from "zod";
6836
+ var UpsertTemplateToolParams = BaseToolSchema.extend({
6837
+ templateId: z101.string().describe("The ID of the template to update"),
6838
+ version: z101.number().describe(
6839
+ "REQUIRED. The template's sys.version as returned by get_template. You must call get_template first to read the current state and version. The update is rejected if this does not match the current version, which means the template changed since you read it."
6840
+ ),
6841
+ name: z101.string().optional().describe("The name of the template"),
6842
+ description: z101.string().optional().describe("Description of the template"),
6843
+ viewports: z101.array(ViewportSchema).optional().describe("Viewport definitions; replaces existing viewports if provided"),
6844
+ contentProperties: z101.array(ContentPropertySchema).optional().describe("Content property definitions; replaces existing if provided"),
6845
+ designProperties: z101.array(DesignPropertySchema).optional().describe("Design property definitions; replaces existing if provided"),
6846
+ componentTree: z101.array(TreeNodeSchema).optional().describe("Component tree node definitions; replaces existing if provided"),
6847
+ slots: z101.array(SlotDefinitionSchema).optional().describe("Slot definitions; replaces existing if provided"),
6848
+ metadata: ExoMetadataSchema.optional().describe(
6849
+ "ExO metadata (tags, concepts); replaces existing if provided"
6850
+ )
6851
+ });
6852
+ function upsertTemplateTool(config) {
6853
+ async function tool2(args) {
6854
+ assertEnvironmentNotProtected(
6855
+ args.environmentId,
6856
+ config.protectedEnvironments
6857
+ );
6858
+ const params = {
6859
+ spaceId: args.spaceId,
6860
+ environmentId: args.environmentId,
6861
+ templateId: args.templateId
6862
+ };
6863
+ const contentfulClient = createToolClient(config, args);
6864
+ const current = await contentfulClient.template.get(params);
6865
+ if (args.version !== current.sys.version) {
6866
+ throw new Error(
6867
+ `Version conflict: the template has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the template with get_template and retry the update with the latest sys.version.`
6868
+ );
6869
+ }
6870
+ const template = await contentfulClient.template.upsert(params, {
6871
+ sys: {
6872
+ id: current.sys.id,
6873
+ type: "Template",
6874
+ version: current.sys.version
6875
+ },
6876
+ name: args.name ?? current.name,
6877
+ description: args.description ?? current.description,
6878
+ viewports: args.viewports ?? current.viewports,
6879
+ contentProperties: args.contentProperties ?? current.contentProperties,
6880
+ designProperties: args.designProperties ?? current.designProperties,
6881
+ ...args.componentTree ?? current.componentTree ? { componentTree: args.componentTree ?? current.componentTree } : {},
6882
+ ...args.slots ?? current.slots ? { slots: args.slots ?? current.slots } : {},
6883
+ ...args.metadata ?? current.metadata ? { metadata: args.metadata ?? current.metadata } : {},
6884
+ ...current.dataAssemblies ? { dataAssemblies: current.dataAssemblies } : {}
6885
+ });
6886
+ return createSuccessResponse("Template updated successfully", {
6887
+ template
6888
+ });
6889
+ }
6890
+ return withErrorHandling(tool2, "Error updating template");
6891
+ }
6892
+
6893
+ // src/tools/exo/templates/deleteTemplate.ts
6894
+ import { z as z102 } from "zod";
6895
+ var DeleteTemplateToolParams = BaseToolSchema.extend({
6896
+ templateId: z102.string().describe("The ID of the template to delete"),
6897
+ confirm: z102.boolean().optional().describe(
6898
+ "Set to true on the second call to actually perform the deletion. Required together with confirmToken."
6899
+ ),
6900
+ confirmToken: z102.string().optional().describe(
6901
+ "Token returned by the preview call; must be supplied with confirm: true."
6902
+ )
6903
+ });
6904
+ function deleteTemplateTool(config) {
6905
+ async function tool2(args) {
6906
+ assertEnvironmentNotProtected(
6907
+ args.environmentId,
6908
+ config.protectedEnvironments
6909
+ );
6910
+ const params = {
6911
+ spaceId: args.spaceId,
6912
+ environmentId: args.environmentId,
6913
+ templateId: args.templateId
6914
+ };
6915
+ const contentfulClient = createToolClient(config, args);
6916
+ const template = await contentfulClient.template.get(params);
6917
+ const expectedToken = buildConfirmToken(
6918
+ "template",
6919
+ args.templateId,
6920
+ template.sys.version
6921
+ );
6922
+ if (args.confirm !== true || args.confirmToken !== expectedToken) {
6923
+ return createSuccessResponse(
6924
+ `${CONFIRMATION_MESSAGE_PREFIX} template`,
6925
+ buildConfirmationPreview(
6926
+ "template",
6927
+ args.templateId,
6928
+ { template },
6929
+ expectedToken
6930
+ )
6931
+ );
6932
+ }
6933
+ await contentfulClient.template.delete(params);
6934
+ return createSuccessResponse("Template deleted successfully", {
6935
+ templateId: args.templateId
6936
+ });
6937
+ }
6938
+ return withErrorHandling(tool2, "Error deleting template");
6939
+ }
6940
+
6941
+ // src/tools/exo/templates/publishTemplate.ts
6942
+ import { z as z103 } from "zod";
6943
+ var PublishTemplateToolParams = BaseToolSchema.extend({
6944
+ templateId: z103.string().describe("The ID of the template to publish"),
6945
+ version: z103.number().describe(
6946
+ "REQUIRED. The template's sys.version as returned by get_template. You must call get_template first to read the current state and version. The publish is rejected if this does not match the current version, which means the template changed since you read it."
6947
+ )
6948
+ });
6949
+ function publishTemplateTool(config) {
6950
+ async function tool2(args) {
6951
+ assertEnvironmentNotProtected(
6952
+ args.environmentId,
6953
+ config.protectedEnvironments
6954
+ );
6955
+ const params = {
6956
+ spaceId: args.spaceId,
6957
+ environmentId: args.environmentId,
6958
+ templateId: args.templateId
6959
+ };
6960
+ const contentfulClient = createToolClient(config, args);
6961
+ const current = await contentfulClient.template.get(params);
6962
+ if (args.version !== current.sys.version) {
6963
+ throw new Error(
6964
+ `Version conflict: the template has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the template with get_template and retry with the latest sys.version.`
6965
+ );
6966
+ }
6967
+ const template = await contentfulClient.template.publish({
6968
+ ...params,
6969
+ version: args.version
6970
+ });
6971
+ return createSuccessResponse("Template published successfully", {
6972
+ template
6973
+ });
6974
+ }
6975
+ return withErrorHandling(tool2, "Error publishing template");
6976
+ }
6977
+
6978
+ // src/tools/exo/templates/unpublishTemplate.ts
6979
+ import { z as z104 } from "zod";
6980
+ var UnpublishTemplateToolParams = BaseToolSchema.extend({
6981
+ templateId: z104.string().describe("The ID of the template to unpublish"),
6982
+ version: z104.number().describe(
6983
+ "REQUIRED. The template's sys.version as returned by get_template. You must call get_template first to read the current state and version. The unpublish is rejected if this does not match the current version, which means the template changed since you read it."
6984
+ )
6985
+ });
6986
+ function unpublishTemplateTool(config) {
6987
+ async function tool2(args) {
6988
+ assertEnvironmentNotProtected(
6989
+ args.environmentId,
6990
+ config.protectedEnvironments
6991
+ );
6992
+ const params = {
6993
+ spaceId: args.spaceId,
6994
+ environmentId: args.environmentId,
6995
+ templateId: args.templateId
6996
+ };
6997
+ const contentfulClient = createToolClient(config, args);
6998
+ const current = await contentfulClient.template.get(params);
6999
+ if (args.version !== current.sys.version) {
7000
+ throw new Error(
7001
+ `Version conflict: the template has changed since you read it (your version: ${args.version}, current version: ${current.sys.version}). Re-fetch the template with get_template and retry with the latest sys.version.`
7002
+ );
7003
+ }
7004
+ const template = await contentfulClient.template.unpublish({
7005
+ ...params,
7006
+ version: args.version
7007
+ });
7008
+ return createSuccessResponse("Template unpublished successfully", {
7009
+ template
7010
+ });
7011
+ }
7012
+ return withErrorHandling(tool2, "Error unpublishing template");
7013
+ }
7014
+
7015
+ // src/tools/exo/templates/register.ts
7016
+ function createTemplateTools(config) {
7017
+ const getTemplate = getTemplateTool(config);
7018
+ const listTemplates = listTemplatesTool(config);
7019
+ const createTemplate = createTemplateTool(config);
7020
+ const upsertTemplate = upsertTemplateTool(config);
7021
+ const deleteTemplate = deleteTemplateTool(config);
7022
+ const publishTemplate = publishTemplateTool(config);
7023
+ const unpublishTemplate = unpublishTemplateTool(config);
7024
+ return {
7025
+ getTemplate: {
7026
+ title: "get_template",
7027
+ description: "Get details about a specific ExO template (a layout definition that backs template-based Experiences).",
7028
+ inputParams: GetTemplateToolParams.shape,
7029
+ annotations: {
7030
+ readOnlyHint: true,
7031
+ destructiveHint: false,
7032
+ openWorldHint: false
7033
+ },
7034
+ tool: getTemplate
7035
+ },
7036
+ listTemplates: {
7037
+ title: "list_templates",
7038
+ description: "List ExO templates in a space and environment. Returns a maximum of 10 items per request; use the pageNext cursor (returned in pages.next) to paginate.",
7039
+ inputParams: ListTemplatesToolParams.shape,
7040
+ annotations: {
7041
+ readOnlyHint: true,
7042
+ destructiveHint: false,
7043
+ openWorldHint: false
7044
+ },
7045
+ tool: listTemplates
7046
+ },
7047
+ createTemplate: {
7048
+ title: "create_template",
7049
+ description: "Create a new ExO template.",
7050
+ inputParams: CreateTemplateToolParams.shape,
7051
+ annotations: {
7052
+ readOnlyHint: false,
7053
+ destructiveHint: false,
7054
+ idempotentHint: false,
7055
+ openWorldHint: false
7056
+ },
7057
+ tool: createTemplate
7058
+ },
7059
+ upsertTemplate: {
7060
+ title: "upsert_template",
7061
+ description: "Update an existing ExO template. You MUST call get_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 template fields, so you only need to provide the fields you want to change. If the version is stale (the template changed since you read it), the update is rejected and you must re-fetch with get_template.",
7062
+ inputParams: UpsertTemplateToolParams.shape,
7063
+ annotations: {
7064
+ readOnlyHint: false,
7065
+ destructiveHint: false,
7066
+ idempotentHint: false,
7067
+ openWorldHint: false
7068
+ },
7069
+ tool: upsertTemplate
7070
+ },
7071
+ deleteTemplate: {
7072
+ title: "delete_template",
7073
+ description: "Delete an ExO template. Two-phase: the first call (without confirm/confirmToken) returns a preview and a confirmToken. To complete the deletion, call again with the same templateId, confirm: true, and the confirmToken from the preview.",
7074
+ inputParams: DeleteTemplateToolParams.shape,
7075
+ annotations: {
7076
+ readOnlyHint: false,
7077
+ destructiveHint: true,
7078
+ idempotentHint: false,
7079
+ openWorldHint: false
7080
+ },
7081
+ tool: deleteTemplate
7082
+ },
7083
+ publishTemplate: {
7084
+ title: "publish_template",
7085
+ description: "Publish an ExO template. You MUST call get_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_template.",
7086
+ inputParams: PublishTemplateToolParams.shape,
7087
+ annotations: {
7088
+ readOnlyHint: false,
7089
+ destructiveHint: true,
7090
+ idempotentHint: true,
7091
+ openWorldHint: false
7092
+ },
7093
+ tool: publishTemplate
7094
+ },
7095
+ unpublishTemplate: {
7096
+ title: "unpublish_template",
7097
+ description: "Unpublish an ExO template. You MUST call get_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_template.",
7098
+ inputParams: UnpublishTemplateToolParams.shape,
7099
+ annotations: {
7100
+ readOnlyHint: false,
7101
+ destructiveHint: true,
7102
+ idempotentHint: true,
7103
+ openWorldHint: false
7104
+ },
7105
+ tool: unpublishTemplate
7106
+ }
7107
+ };
7108
+ }
7109
+
7110
+ // src/tools/exo/experiences/getExperience.ts
7111
+ import { z as z105 } from "zod";
7112
+ var GetExperienceToolParams = BaseToolSchema.extend({
7113
+ experienceId: z105.string().describe("The ID of the experience to retrieve")
7114
+ });
7115
+ function getExperienceTool(config) {
7116
+ async function tool2(args) {
7117
+ const contentfulClient = createToolClient(config, args);
7118
+ const experience = await contentfulClient.experience.get({
7119
+ spaceId: args.spaceId,
7120
+ environmentId: args.environmentId,
7121
+ experienceId: args.experienceId
7122
+ });
7123
+ return createSuccessResponse("Experience retrieved successfully", {
7124
+ experience
7125
+ });
7126
+ }
7127
+ return withErrorHandling(tool2, "Error retrieving experience");
7128
+ }
7129
+
7130
+ // src/tools/exo/experiences/listExperiences.ts
7131
+ import { z as z106 } from "zod";
7132
+ var ListExperiencesToolParams = BaseToolSchema.extend({
7133
+ limit: z106.number().optional().describe("Maximum number of experiences to return (max 10)"),
7134
+ pageNext: z106.string().optional().describe("Cursor token to fetch the next page of results"),
7135
+ pagePrev: z106.string().optional().describe("Cursor token to fetch the previous page of results"),
7136
+ order: z106.string().optional().describe("Order experiences by this field (e.g. sys.createdAt)")
7137
+ });
7138
+ function listExperiencesTool(config) {
7139
+ async function tool2(args) {
7140
+ const contentfulClient = createToolClient(config, args);
7141
+ const experiences = await contentfulClient.experience.getMany({
7142
+ spaceId: args.spaceId,
7143
+ environmentId: args.environmentId,
7144
+ query: {
7145
+ limit: Math.min(args.limit || 10, 10),
7146
+ ...args.pageNext && { pageNext: args.pageNext },
7147
+ ...args.pagePrev && { pagePrev: args.pagePrev },
7148
+ ...args.order && { order: args.order }
7149
+ }
7150
+ });
7151
+ const summarized = summarizeData(experiences, {
7152
+ maxItems: 10,
7153
+ remainingMessage: "To see more experiences, ask me to retrieve the next page using the pageNext cursor."
7154
+ });
7155
+ return createSuccessResponse("Experiences retrieved successfully", {
7156
+ experiences: summarized,
7157
+ total: experiences.total,
7158
+ limit: experiences.limit,
7159
+ pages: experiences.pages
7160
+ });
7161
+ }
7162
+ return withErrorHandling(tool2, "Error listing experiences");
7163
+ }
7164
+
7165
+ // src/tools/exo/experiences/createExperience.ts
7166
+ import { z as z107 } from "zod";
7167
+ var TemplateResourceLinkSchema = z107.object({
7168
+ sys: z107.object({
7169
+ type: z107.literal("ResourceLink"),
7170
+ linkType: z107.literal("Contentful:Template"),
7171
+ urn: z107.string().describe("URN of the linked resource")
7172
+ })
7173
+ });
7174
+ var CreateExperienceToolParams = BaseToolSchema.extend({
7175
+ name: z107.string().describe("The name of the experience"),
7176
+ description: z107.string().describe("Description of the experience"),
7177
+ template: TemplateResourceLinkSchema.describe(
7178
+ "Resource link to the Template this experience is backed by"
7179
+ ),
7180
+ viewports: z107.array(ViewportSchema).describe("Viewport definitions for the experience (may be empty)"),
7181
+ designProperties: z107.record(z107.string(), DimensionedDesignPropertyValueSchema).describe(
7182
+ "Design property values keyed by property ID. Each value is a dimensioned map (viewport ID \u2192 design value). May be an empty object."
7183
+ ),
7184
+ contentBindings: ExperienceContentBindingsSchema.optional().describe(
7185
+ "Optional content bindings linking this experience to a data assembly"
7186
+ ),
7187
+ slots: z107.record(z107.string(), z107.array(ExperienceSlotNodeSchema)).optional().describe(
7188
+ "Optional slot contents keyed by slot ID. Each value is an array of FragmentNode or InlineFragmentNode."
7189
+ ),
7190
+ metadata: ExperienceMetadataSchema.optional().describe(
7191
+ "Optional ExO metadata (tags, concepts)"
7192
+ )
7193
+ });
7194
+ function createExperienceTool(config) {
7195
+ async function tool2(args) {
7196
+ assertEnvironmentNotProtected(
7197
+ args.environmentId,
7198
+ config.protectedEnvironments
7199
+ );
7200
+ const contentfulClient = createToolClient(config, args);
7201
+ const experience = await contentfulClient.experience.create(
7202
+ { spaceId: args.spaceId, environmentId: args.environmentId },
7203
+ {
7204
+ name: args.name,
7205
+ description: args.description,
7206
+ template: args.template,
7207
+ viewports: args.viewports,
7208
+ designProperties: args.designProperties,
7209
+ ...args.contentBindings && { contentBindings: args.contentBindings },
7210
+ ...args.slots && { slots: args.slots },
7211
+ ...args.metadata && { metadata: args.metadata }
7212
+ }
7213
+ );
7214
+ return createSuccessResponse("Experience created successfully", {
7215
+ experience
7216
+ });
7217
+ }
7218
+ return withErrorHandling(tool2, "Error creating experience");
7219
+ }
7220
+
7221
+ // src/tools/exo/experiences/upsertExperience.ts
7222
+ import { z as z108 } from "zod";
7223
+ var UpsertExperienceToolParams = BaseToolSchema.extend({
7224
+ experienceId: z108.string().describe("The ID of the experience to update"),
7225
+ version: z108.number().describe(
7226
+ "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."
7227
+ ),
7228
+ name: z108.string().optional().describe("The name of the experience"),
7229
+ description: z108.string().optional().describe("Description of the experience"),
7230
+ viewports: z108.array(ViewportSchema).optional().describe("Viewport definitions; replaces existing viewports if provided"),
7231
+ designProperties: z108.record(z108.string(), DimensionedDesignPropertyValueSchema).optional().describe(
7232
+ "Design property values keyed by property ID; replaces existing if provided"
7233
+ ),
7234
+ contentBindings: ExperienceContentBindingsSchema.optional().describe(
7235
+ "Content bindings linking this experience to a data assembly; replaces existing if provided"
7236
+ ),
7237
+ slots: z108.record(z108.string(), z108.array(ExperienceSlotNodeSchema)).optional().describe(
7238
+ "Slot contents keyed by slot ID; replaces existing if provided"
7239
+ ),
7240
+ metadata: ExperienceMetadataSchema.optional().describe(
7241
+ "ExO metadata (tags, concepts); replaces existing if provided"
7242
+ )
7243
+ });
7244
+ function upsertExperienceTool(config) {
7245
+ async function tool2(args) {
7246
+ assertEnvironmentNotProtected(
7247
+ args.environmentId,
7248
+ config.protectedEnvironments
7249
+ );
7250
+ const params = {
7251
+ spaceId: args.spaceId,
7252
+ environmentId: args.environmentId,
7253
+ experienceId: args.experienceId
7254
+ };
7255
+ const contentfulClient = createToolClient(config, args);
7256
+ const current = await contentfulClient.experience.get(params);
7257
+ if (args.version !== current.sys.version) {
7258
+ throw new Error(
7259
+ `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.`
7260
+ );
7261
+ }
7262
+ const experience = await contentfulClient.experience.upsert(params, {
7263
+ sys: {
7264
+ id: current.sys.id,
7265
+ type: "Experience",
7266
+ version: current.sys.version
7267
+ },
7268
+ name: args.name ?? current.name,
7269
+ description: args.description ?? current.description,
7270
+ viewports: args.viewports ?? current.viewports,
7271
+ designProperties: args.designProperties ?? current.designProperties,
7272
+ ...args.contentBindings ?? current.contentBindings ? { contentBindings: args.contentBindings ?? current.contentBindings } : {},
7273
+ ...args.slots ?? current.slots ? { slots: args.slots ?? current.slots } : {},
7274
+ ...args.metadata ?? current.metadata ? { metadata: args.metadata ?? current.metadata } : {}
7275
+ });
7276
+ return createSuccessResponse("Experience updated successfully", {
7277
+ experience
7278
+ });
7279
+ }
7280
+ return withErrorHandling(tool2, "Error updating experience");
7281
+ }
7282
+
7283
+ // src/tools/exo/experiences/deleteExperience.ts
7284
+ import { z as z109 } from "zod";
7285
+ var DeleteExperienceToolParams = BaseToolSchema.extend({
7286
+ experienceId: z109.string().describe("The ID of the experience to delete"),
7287
+ confirm: z109.boolean().optional().describe(
7288
+ "Set to true on the second call to actually perform the deletion. Required together with confirmToken."
7289
+ ),
7290
+ confirmToken: z109.string().optional().describe(
7291
+ "Token returned by the preview call; must be supplied with confirm: true."
7292
+ )
7293
+ });
7294
+ function deleteExperienceTool(config) {
7295
+ async function tool2(args) {
7296
+ assertEnvironmentNotProtected(
7297
+ args.environmentId,
7298
+ config.protectedEnvironments
7299
+ );
7300
+ const params = {
7301
+ spaceId: args.spaceId,
7302
+ environmentId: args.environmentId,
7303
+ experienceId: args.experienceId
7304
+ };
7305
+ const contentfulClient = createToolClient(config, args);
7306
+ const experience = await contentfulClient.experience.get(params);
7307
+ const expectedToken = buildConfirmToken(
7308
+ "experience",
7309
+ args.experienceId,
7310
+ experience.sys.version
7311
+ );
7312
+ if (args.confirm !== true || args.confirmToken !== expectedToken) {
7313
+ return createSuccessResponse(
7314
+ `${CONFIRMATION_MESSAGE_PREFIX} experience`,
7315
+ buildConfirmationPreview(
7316
+ "experience",
7317
+ args.experienceId,
7318
+ { experience },
7319
+ expectedToken
7320
+ )
7321
+ );
7322
+ }
7323
+ await contentfulClient.experience.delete(params);
7324
+ return createSuccessResponse("Experience deleted successfully", {
7325
+ experienceId: args.experienceId
7326
+ });
7327
+ }
7328
+ return withErrorHandling(tool2, "Error deleting experience");
7329
+ }
7330
+
7331
+ // src/tools/exo/experiences/publishExperience.ts
7332
+ import { z as z110 } from "zod";
7333
+ var PublishExperienceToolParams = BaseToolSchema.extend({
7334
+ experienceId: z110.string().describe("The ID of the experience to publish"),
7335
+ version: z110.number().describe(
7336
+ "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."
7337
+ )
7338
+ });
7339
+ function publishExperienceTool(config) {
7340
+ async function tool2(args) {
7341
+ assertEnvironmentNotProtected(
7342
+ args.environmentId,
7343
+ config.protectedEnvironments
7344
+ );
7345
+ const params = {
7346
+ spaceId: args.spaceId,
7347
+ environmentId: args.environmentId,
7348
+ experienceId: args.experienceId
7349
+ };
7350
+ const contentfulClient = createToolClient(config, args);
7351
+ const current = await contentfulClient.experience.get(params);
7352
+ if (args.version !== current.sys.version) {
7353
+ throw new Error(
7354
+ `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.`
7355
+ );
7356
+ }
7357
+ const experience = await contentfulClient.experience.publish({
7358
+ ...params,
7359
+ version: args.version
7360
+ });
7361
+ return createSuccessResponse("Experience published successfully", {
7362
+ experience
7363
+ });
7364
+ }
7365
+ return withErrorHandling(tool2, "Error publishing experience");
7366
+ }
7367
+
7368
+ // src/tools/exo/experiences/unpublishExperience.ts
7369
+ import { z as z111 } from "zod";
7370
+ var UnpublishExperienceToolParams = BaseToolSchema.extend({
7371
+ experienceId: z111.string().describe("The ID of the experience to unpublish"),
7372
+ version: z111.number().describe(
7373
+ "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."
7374
+ )
7375
+ });
7376
+ function unpublishExperienceTool(config) {
7377
+ async function tool2(args) {
7378
+ assertEnvironmentNotProtected(
7379
+ args.environmentId,
7380
+ config.protectedEnvironments
7381
+ );
7382
+ const params = {
7383
+ spaceId: args.spaceId,
7384
+ environmentId: args.environmentId,
7385
+ experienceId: args.experienceId
7386
+ };
7387
+ const contentfulClient = createToolClient(config, args);
7388
+ const current = await contentfulClient.experience.get(params);
7389
+ if (args.version !== current.sys.version) {
7390
+ throw new Error(
7391
+ `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.`
7392
+ );
7393
+ }
7394
+ const experience = await contentfulClient.experience.unpublish({
7395
+ ...params,
7396
+ version: args.version
7397
+ });
7398
+ return createSuccessResponse("Experience unpublished successfully", {
7399
+ experience
7400
+ });
7401
+ }
7402
+ return withErrorHandling(tool2, "Error unpublishing experience");
7403
+ }
7404
+
7405
+ // src/tools/exo/experiences/register.ts
7406
+ function createExperienceTools(config) {
7407
+ const getExperience = getExperienceTool(config);
7408
+ const listExperiences = listExperiencesTool(config);
7409
+ const createExperience = createExperienceTool(config);
7410
+ const upsertExperience = upsertExperienceTool(config);
7411
+ const deleteExperience = deleteExperienceTool(config);
7412
+ const publishExperience = publishExperienceTool(config);
7413
+ const unpublishExperience = unpublishExperienceTool(config);
7414
+ return {
7415
+ getExperience: {
7416
+ title: "get_experience",
7417
+ description: "Get details about a specific ExO experience (a concrete page or screen that composes a root ComponentType with content and design settings, backed by a Template).",
7418
+ inputParams: GetExperienceToolParams.shape,
7419
+ annotations: {
7420
+ readOnlyHint: true,
7421
+ destructiveHint: false,
7422
+ openWorldHint: false
7423
+ },
7424
+ tool: getExperience
7425
+ },
7426
+ listExperiences: {
7427
+ title: "list_experiences",
7428
+ 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.",
7429
+ inputParams: ListExperiencesToolParams.shape,
7430
+ annotations: {
7431
+ readOnlyHint: true,
7432
+ destructiveHint: false,
7433
+ openWorldHint: false
7434
+ },
7435
+ tool: listExperiences
7436
+ },
7437
+ createExperience: {
7438
+ title: "create_experience",
7439
+ description: "Create a new ExO experience backed by a Template.",
7440
+ inputParams: CreateExperienceToolParams.shape,
7441
+ annotations: {
7442
+ readOnlyHint: false,
7443
+ destructiveHint: false,
7444
+ idempotentHint: false,
7445
+ openWorldHint: false
7446
+ },
7447
+ tool: createExperience
7448
+ },
7449
+ upsertExperience: {
7450
+ title: "upsert_experience",
7451
+ 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.",
7452
+ inputParams: UpsertExperienceToolParams.shape,
7453
+ annotations: {
7454
+ readOnlyHint: false,
7455
+ destructiveHint: false,
7456
+ idempotentHint: false,
7457
+ openWorldHint: false
7458
+ },
7459
+ tool: upsertExperience
7460
+ },
7461
+ deleteExperience: {
7462
+ title: "delete_experience",
7463
+ 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.",
7464
+ inputParams: DeleteExperienceToolParams.shape,
7465
+ annotations: {
7466
+ readOnlyHint: false,
7467
+ destructiveHint: true,
7468
+ idempotentHint: false,
7469
+ openWorldHint: false
7470
+ },
7471
+ tool: deleteExperience
7472
+ },
7473
+ publishExperience: {
7474
+ title: "publish_experience",
7475
+ 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.",
7476
+ inputParams: PublishExperienceToolParams.shape,
7477
+ annotations: {
7478
+ readOnlyHint: false,
7479
+ destructiveHint: true,
7480
+ idempotentHint: true,
7481
+ openWorldHint: false
7482
+ },
7483
+ tool: publishExperience
7484
+ },
7485
+ unpublishExperience: {
7486
+ title: "unpublish_experience",
7487
+ 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.",
7488
+ inputParams: UnpublishExperienceToolParams.shape,
7489
+ annotations: {
7490
+ readOnlyHint: false,
7491
+ destructiveHint: true,
7492
+ idempotentHint: true,
7493
+ openWorldHint: false
7494
+ },
7495
+ tool: unpublishExperience
7496
+ }
7497
+ };
7498
+ }
7499
+
7500
+ // src/tools/exo/data-assemblies/getDataAssembly.ts
7501
+ import { z as z112 } from "zod";
7502
+ var GetDataAssemblyToolParams = BaseToolSchema.extend({
7503
+ dataAssemblyId: z112.string().describe("The ID of the data assembly to retrieve")
7504
+ });
7505
+ function getDataAssemblyTool(config) {
7506
+ async function tool2(args) {
7507
+ const contentfulClient = createToolClient(config, args);
7508
+ const dataAssembly = await contentfulClient.dataAssembly.get({
7509
+ spaceId: args.spaceId,
7510
+ environmentId: args.environmentId,
7511
+ dataAssemblyId: args.dataAssemblyId
7512
+ });
7513
+ return createSuccessResponse("Data assembly retrieved successfully", {
7514
+ dataAssembly
7515
+ });
7516
+ }
7517
+ return withErrorHandling(tool2, "Error retrieving data assembly");
7518
+ }
7519
+
7520
+ // src/tools/exo/data-assemblies/getPublishedDataAssembly.ts
7521
+ import { z as z113 } from "zod";
7522
+ var GetPublishedDataAssemblyToolParams = BaseToolSchema.extend({
7523
+ dataAssemblyId: z113.string().describe("The ID of the published data assembly to retrieve")
7524
+ });
7525
+ function getPublishedDataAssemblyTool(config) {
7526
+ async function tool2(args) {
7527
+ const contentfulClient = createToolClient(config, args);
7528
+ const dataAssembly = await contentfulClient.dataAssembly.getPublished({
7529
+ spaceId: args.spaceId,
7530
+ environmentId: args.environmentId,
7531
+ dataAssemblyId: args.dataAssemblyId
7532
+ });
7533
+ return createSuccessResponse("Published data assembly retrieved successfully", {
7534
+ dataAssembly
7535
+ });
7536
+ }
7537
+ return withErrorHandling(tool2, "Error retrieving published data assembly");
7538
+ }
7539
+
7540
+ // src/tools/exo/data-assemblies/listDataAssemblies.ts
7541
+ import { z as z114 } from "zod";
7542
+ var ListDataAssembliesToolParams = BaseToolSchema.extend({
7543
+ limit: z114.number().optional().describe("Maximum number of data assemblies to return (max 10)"),
7544
+ pageNext: z114.string().optional().describe("Cursor token to fetch the next page of results"),
7545
+ pagePrev: z114.string().optional().describe("Cursor token to fetch the previous page of results"),
7546
+ sysIdIn: z114.string().optional().describe("Comma-separated list of data assembly IDs to filter by")
7547
+ });
7548
+ function listDataAssembliesTool(config) {
7549
+ async function tool2(args) {
7550
+ const contentfulClient = createToolClient(config, args);
7551
+ const dataAssemblies = await contentfulClient.dataAssembly.getMany({
7552
+ spaceId: args.spaceId,
7553
+ environmentId: args.environmentId,
7554
+ query: {
7555
+ limit: Math.min(args.limit || 10, 10),
7556
+ ...args.pageNext && { pageNext: args.pageNext },
7557
+ ...args.pagePrev && { pagePrev: args.pagePrev },
7558
+ ...args.sysIdIn && { "sys.id[in]": args.sysIdIn }
7559
+ }
7560
+ });
7561
+ const summarized = summarizeData(dataAssemblies, {
7562
+ maxItems: 10,
7563
+ remainingMessage: "To see more data assemblies, ask me to retrieve the next page using the pageNext cursor."
7564
+ });
7565
+ return createSuccessResponse("Data assemblies retrieved successfully", {
7566
+ dataAssemblies: summarized,
7567
+ total: dataAssemblies.total,
7568
+ pages: dataAssemblies.pages
7569
+ });
7570
+ }
7571
+ return withErrorHandling(tool2, "Error listing data assemblies");
7572
+ }
7573
+
7574
+ // src/tools/exo/data-assemblies/listPublishedDataAssemblies.ts
7575
+ import { z as z115 } from "zod";
7576
+ var ListPublishedDataAssembliesToolParams = BaseToolSchema.extend({
7577
+ limit: z115.number().optional().describe("Maximum number of published data assemblies to return (max 10)"),
7578
+ pageNext: z115.string().optional().describe("Cursor token to fetch the next page of results"),
7579
+ pagePrev: z115.string().optional().describe("Cursor token to fetch the previous page of results"),
7580
+ sysIdIn: z115.string().optional().describe("Comma-separated list of data assembly IDs to filter by")
7581
+ });
7582
+ function listPublishedDataAssembliesTool(config) {
7583
+ async function tool2(args) {
7584
+ const contentfulClient = createToolClient(config, args);
7585
+ const dataAssemblies = await contentfulClient.dataAssembly.getManyPublished({
7586
+ spaceId: args.spaceId,
7587
+ environmentId: args.environmentId,
7588
+ query: {
7589
+ limit: Math.min(args.limit || 10, 10),
7590
+ ...args.pageNext && { pageNext: args.pageNext },
7591
+ ...args.pagePrev && { pagePrev: args.pagePrev },
7592
+ ...args.sysIdIn && { "sys.id[in]": args.sysIdIn }
7593
+ }
7594
+ });
7595
+ const summarized = summarizeData(dataAssemblies, {
7596
+ maxItems: 10,
7597
+ remainingMessage: "To see more published data assemblies, ask me to retrieve the next page using the pageNext cursor."
7598
+ });
7599
+ return createSuccessResponse("Published data assemblies retrieved successfully", {
7600
+ dataAssemblies: summarized,
7601
+ total: dataAssemblies.total,
7602
+ pages: dataAssemblies.pages
7603
+ });
7604
+ }
7605
+ return withErrorHandling(tool2, "Error listing published data assemblies");
7606
+ }
7607
+
7608
+ // src/tools/exo/data-assemblies/createDataAssembly.ts
7609
+ import { z as z117 } from "zod";
7610
+
7611
+ // src/types/dataAssemblySchemas.ts
7612
+ import { z as z116 } from "zod";
7613
+ var PointerExpressionValueSchema = z116.lazy(
7614
+ () => z116.union([
7615
+ z116.string(),
7616
+ z116.object({
7617
+ $from: z116.union([
7618
+ z116.string(),
7619
+ z116.object({
7620
+ source: z116.string(),
7621
+ select: PointerExpressionValueSchema.optional()
7622
+ })
7623
+ ])
7624
+ }),
7625
+ z116.object({ $literal: z116.custom() }),
7626
+ z116.object({ $object: z116.record(z116.string(), PointerExpressionValueSchema) }),
7627
+ z116.object({
7628
+ $on: z116.object({
7629
+ type: z116.record(z116.string(), PointerExpressionValueSchema),
7630
+ default: PointerExpressionValueSchema.optional()
7631
+ })
7632
+ }),
7633
+ z116.record(z116.string(), PointerExpressionValueSchema)
7634
+ ])
7635
+ );
7636
+ var CanonicalDataTypeArmSchema = z116.object({
7637
+ type: z116.enum([
7638
+ "String",
7639
+ "Number",
7640
+ "Integer",
7641
+ "Boolean",
7642
+ "RichText",
7643
+ "Array",
7644
+ "Record",
7645
+ "TypeRef",
7646
+ "Literal",
7647
+ "DiscriminatedUnion"
7648
+ ]),
7649
+ id: z116.string().describe("Data type field identifier"),
7650
+ name: z116.string().describe("Human-readable name"),
7651
+ required: z116.boolean().optional()
7652
+ }).catchall(z116.unknown());
7653
+ var LegacyDataTypeArmSchema = z116.object({
7654
+ id: z116.string().describe("Data type field identifier"),
7655
+ name: z116.string().describe("Human-readable name"),
7656
+ type: z116.string(),
7657
+ required: z116.boolean().optional(),
7658
+ source: z116.string().optional(),
7659
+ ref: z116.unknown().optional()
7660
+ });
7661
+ var DataAssemblyDataTypeFieldSchema = z116.union([
7662
+ CanonicalDataTypeArmSchema,
7663
+ LegacyDataTypeArmSchema
7664
+ ]);
7665
+ var SAME_SPACE_CONTENT_SOURCE = "crn:contentful:::content:spaces/$self/environments/$self";
7666
+ var DataAssemblyResourceLinkParameterSchema = z116.object({
7667
+ name: z116.string().optional(),
7668
+ description: z116.string().optional(),
7669
+ type: z116.literal("ResourceLink"),
7670
+ linkType: z116.literal("Contentful:Entry"),
7671
+ allowedResources: z116.array(
7672
+ z116.object({
7673
+ type: z116.literal("Contentful:Entry"),
7674
+ source: z116.literal(SAME_SPACE_CONTENT_SOURCE),
7675
+ allowedTypes: z116.array(z116.string())
7676
+ })
7677
+ )
7678
+ });
7679
+ var DataAssemblyParameterConfigSchema = z116.record(
7680
+ z116.string(),
7681
+ DataAssemblyResourceLinkParameterSchema
7682
+ );
7683
+ var DataAssemblyGraphQLResolverSchema = z116.object({
7684
+ source: z116.literal("Contentful:GraphQL"),
7685
+ query: z116.string().describe("GraphQL query string"),
7686
+ parameters: PointerExpressionValueSchema.optional()
7687
+ });
7688
+ var DataAssemblyNestedResolverSchema = z116.object({
7689
+ source: z116.literal("Contentful:DataAssembly"),
7690
+ dataAssembly: z116.object({
7691
+ sys: z116.object({
7692
+ type: z116.literal("ResourceLink"),
7693
+ linkType: z116.literal("Contentful:DataAssembly"),
7694
+ urn: z116.string()
7695
+ })
7696
+ }),
7697
+ parameters: PointerExpressionValueSchema.optional()
7698
+ });
7699
+ var DataAssemblyResolverDefinitionSchema = z116.union([
7700
+ DataAssemblyGraphQLResolverSchema,
7701
+ DataAssemblyNestedResolverSchema
7702
+ ]);
7703
+ var DataAssemblyResolverConfigSchema = z116.record(
7704
+ z116.string(),
7705
+ DataAssemblyResolverDefinitionSchema
7706
+ );
7707
+ var DataAssemblyReturnMappingConfigSchema = PointerExpressionValueSchema;
7708
+ var DataAssemblyMetadataSchema = z116.object({
7709
+ tags: z116.array(
7710
+ z116.object({
7711
+ sys: z116.object({
7712
+ type: z116.literal("Link"),
7713
+ linkType: z116.literal("Tag"),
7714
+ id: z116.string()
7715
+ })
7716
+ })
7717
+ )
7718
+ });
7719
+
7720
+ // src/tools/exo/data-assemblies/createDataAssembly.ts
7721
+ var CreateDataAssemblyToolParams = BaseToolSchema.extend({
7722
+ name: z117.string().describe("The name of the data assembly"),
7723
+ description: z117.string().describe("Description of the data assembly"),
7724
+ parameters: DataAssemblyParameterConfigSchema.describe(
7725
+ "Parameter definitions keyed by parameter name (may be empty object)"
7726
+ ),
7727
+ resolvers: DataAssemblyResolverConfigSchema.describe(
7728
+ "Resolver definitions keyed by resolver name (may be empty object)"
7729
+ ),
7730
+ return: DataAssemblyReturnMappingConfigSchema.describe(
7731
+ "Return mapping configuration specifying how to map resolved data"
7732
+ ),
7733
+ dataType: z117.array(DataAssemblyDataTypeFieldSchema).describe("Data type field definitions for this data assembly (may be empty array)"),
7734
+ variant: z117.string().optional().describe("Optional variant identifier for this data assembly"),
7735
+ metadata: DataAssemblyMetadataSchema.optional().describe("Optional metadata (tags)")
7736
+ });
7737
+ function createDataAssemblyTool(config) {
7738
+ async function tool2(args) {
7739
+ assertEnvironmentNotProtected(
7740
+ args.environmentId,
7741
+ config.protectedEnvironments
7742
+ );
7743
+ const contentfulClient = createToolClient(config, args);
7744
+ const dataAssembly = await contentfulClient.dataAssembly.create(
7745
+ { spaceId: args.spaceId, environmentId: args.environmentId },
7746
+ {
7747
+ sys: {
7748
+ type: "DataAssembly",
7749
+ dataType: args.dataType,
7750
+ ...args.variant && { variant: args.variant }
7751
+ },
7752
+ name: args.name,
7753
+ description: args.description,
7754
+ parameters: args.parameters,
7755
+ resolvers: args.resolvers,
7756
+ return: args.return,
7757
+ metadata: args.metadata ?? { tags: [] }
7758
+ }
7759
+ );
7760
+ return createSuccessResponse("Data assembly created successfully", {
7761
+ dataAssembly
7762
+ });
7763
+ }
7764
+ return withErrorHandling(tool2, "Error creating data assembly");
7765
+ }
7766
+
7767
+ // src/tools/exo/data-assemblies/updateDataAssembly.ts
7768
+ import { z as z118 } from "zod";
7769
+ var UpdateDataAssemblyToolParams = BaseToolSchema.extend({
7770
+ dataAssemblyId: z118.string().describe("The ID of the data assembly to update"),
7771
+ version: z118.number().describe(
7772
+ "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."
7773
+ ),
7774
+ name: z118.string().optional().describe("The name of the data assembly"),
7775
+ description: z118.string().optional().describe("Description of the data assembly"),
7776
+ parameters: DataAssemblyParameterConfigSchema.optional().describe(
7777
+ "Parameter definitions; replaces existing if provided"
7778
+ ),
7779
+ resolvers: DataAssemblyResolverConfigSchema.optional().describe(
7780
+ "Resolver definitions; replaces existing if provided"
7781
+ ),
7782
+ return: DataAssemblyReturnMappingConfigSchema.optional().describe(
7783
+ "Return mapping configuration; replaces existing if provided"
7784
+ ),
7785
+ dataType: z118.array(DataAssemblyDataTypeFieldSchema).optional().describe("Data type field definitions; replaces existing if provided"),
7786
+ variant: z118.string().optional().describe("Optional variant identifier; replaces existing if provided"),
7787
+ metadata: DataAssemblyMetadataSchema.optional().describe(
7788
+ "Metadata (tags); replaces existing if provided"
7789
+ )
7790
+ });
7791
+ function updateDataAssemblyTool(config) {
7792
+ async function tool2(args) {
7793
+ assertEnvironmentNotProtected(
7794
+ args.environmentId,
7795
+ config.protectedEnvironments
7796
+ );
7797
+ const params = {
7798
+ spaceId: args.spaceId,
7799
+ environmentId: args.environmentId,
7800
+ dataAssemblyId: args.dataAssemblyId
7801
+ };
7802
+ const contentfulClient = createToolClient(config, args);
7803
+ const current = await contentfulClient.dataAssembly.get(params);
7804
+ if (args.version !== current.sys.version) {
7805
+ throw new Error(
7806
+ `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.`
7807
+ );
7808
+ }
7809
+ const dataAssembly = await contentfulClient.dataAssembly.update(params, {
7810
+ sys: {
7811
+ id: current.sys.id,
7812
+ type: "DataAssembly",
7813
+ version: current.sys.version,
7814
+ dataType: args.dataType ?? current.sys.dataType,
7815
+ ...args.variant !== void 0 ? { variant: args.variant } : current.sys.variant !== void 0 ? { variant: current.sys.variant } : {}
7816
+ },
7817
+ name: args.name ?? current.name,
7818
+ description: args.description ?? current.description,
7819
+ parameters: args.parameters ?? current.parameters,
7820
+ resolvers: args.resolvers ?? current.resolvers,
7821
+ return: args.return ?? current.return,
7822
+ metadata: args.metadata ?? current.metadata
7823
+ });
7824
+ return createSuccessResponse("Data assembly updated successfully", {
7825
+ dataAssembly
7826
+ });
7827
+ }
7828
+ return withErrorHandling(tool2, "Error updating data assembly");
7829
+ }
7830
+
7831
+ // src/tools/exo/data-assemblies/deleteDataAssembly.ts
7832
+ import { z as z119 } from "zod";
7833
+ var DeleteDataAssemblyToolParams = BaseToolSchema.extend({
7834
+ dataAssemblyId: z119.string().describe("The ID of the data assembly to delete"),
7835
+ confirm: z119.boolean().optional().describe(
7836
+ "Set to true on the second call to actually perform the deletion. Required together with confirmToken."
7837
+ ),
7838
+ confirmToken: z119.string().optional().describe(
7839
+ "Token returned by the preview call; must be supplied with confirm: true."
7840
+ )
7841
+ });
7842
+ function deleteDataAssemblyTool(config) {
7843
+ async function tool2(args) {
7844
+ assertEnvironmentNotProtected(
7845
+ args.environmentId,
7846
+ config.protectedEnvironments
7847
+ );
7848
+ const params = {
7849
+ spaceId: args.spaceId,
7850
+ environmentId: args.environmentId,
7851
+ dataAssemblyId: args.dataAssemblyId
7852
+ };
7853
+ const contentfulClient = createToolClient(config, args);
7854
+ const dataAssembly = await contentfulClient.dataAssembly.get(params);
7855
+ const expectedToken = buildConfirmToken(
7856
+ "dataAssembly",
7857
+ args.dataAssemblyId,
7858
+ dataAssembly.sys.version
7859
+ );
7860
+ if (args.confirm !== true || args.confirmToken !== expectedToken) {
7861
+ return createSuccessResponse(
7862
+ `${CONFIRMATION_MESSAGE_PREFIX} data assembly`,
7863
+ buildConfirmationPreview(
7864
+ "dataAssembly",
7865
+ args.dataAssemblyId,
7866
+ { dataAssembly },
7867
+ expectedToken
7868
+ )
7869
+ );
7870
+ }
7871
+ await contentfulClient.dataAssembly.delete(params);
7872
+ return createSuccessResponse("Data assembly deleted successfully", {
7873
+ dataAssemblyId: args.dataAssemblyId
7874
+ });
7875
+ }
7876
+ return withErrorHandling(tool2, "Error deleting data assembly");
7877
+ }
7878
+
7879
+ // src/tools/exo/data-assemblies/publishDataAssembly.ts
7880
+ import { z as z120 } from "zod";
7881
+ var PublishDataAssemblyToolParams = BaseToolSchema.extend({
7882
+ dataAssemblyId: z120.string().describe("The ID of the data assembly to publish"),
7883
+ version: z120.number().describe(
7884
+ "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."
7885
+ )
7886
+ });
7887
+ function publishDataAssemblyTool(config) {
7888
+ async function tool2(args) {
7889
+ assertEnvironmentNotProtected(
7890
+ args.environmentId,
7891
+ config.protectedEnvironments
7892
+ );
7893
+ const params = {
7894
+ spaceId: args.spaceId,
7895
+ environmentId: args.environmentId,
7896
+ dataAssemblyId: args.dataAssemblyId
7897
+ };
7898
+ const contentfulClient = createToolClient(config, args);
7899
+ const current = await contentfulClient.dataAssembly.get(params);
7900
+ if (args.version !== current.sys.version) {
7901
+ throw new Error(
7902
+ `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.`
7903
+ );
7904
+ }
7905
+ const dataAssembly = await contentfulClient.dataAssembly.publish({
7906
+ ...params,
7907
+ version: args.version
7908
+ });
7909
+ return createSuccessResponse("Data assembly published successfully", {
7910
+ dataAssembly
7911
+ });
7912
+ }
7913
+ return withErrorHandling(tool2, "Error publishing data assembly");
7914
+ }
7915
+
7916
+ // src/tools/exo/data-assemblies/unpublishDataAssembly.ts
7917
+ import { z as z121 } from "zod";
7918
+ var UnpublishDataAssemblyToolParams = BaseToolSchema.extend({
7919
+ dataAssemblyId: z121.string().describe("The ID of the data assembly to unpublish"),
7920
+ version: z121.number().describe(
7921
+ "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."
7922
+ )
7923
+ });
7924
+ function unpublishDataAssemblyTool(config) {
7925
+ async function tool2(args) {
7926
+ assertEnvironmentNotProtected(
7927
+ args.environmentId,
7928
+ config.protectedEnvironments
7929
+ );
7930
+ const params = {
7931
+ spaceId: args.spaceId,
7932
+ environmentId: args.environmentId,
7933
+ dataAssemblyId: args.dataAssemblyId
7934
+ };
7935
+ const contentfulClient = createToolClient(config, args);
7936
+ const current = await contentfulClient.dataAssembly.get(params);
7937
+ if (args.version !== current.sys.version) {
7938
+ throw new Error(
7939
+ `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.`
7940
+ );
7941
+ }
7942
+ const dataAssembly = await contentfulClient.dataAssembly.unpublish({
7943
+ ...params,
7944
+ version: args.version
7945
+ });
7946
+ return createSuccessResponse("Data assembly unpublished successfully", {
7947
+ dataAssembly
7948
+ });
7949
+ }
7950
+ return withErrorHandling(tool2, "Error unpublishing data assembly");
7951
+ }
7952
+
7953
+ // src/tools/exo/data-assemblies/register.ts
7954
+ function createDataAssemblyTools(config) {
7955
+ const getDataAssembly = getDataAssemblyTool(config);
7956
+ const getPublishedDataAssembly = getPublishedDataAssemblyTool(config);
7957
+ const listDataAssemblies = listDataAssembliesTool(config);
7958
+ const listPublishedDataAssemblies = listPublishedDataAssembliesTool(config);
7959
+ const createDataAssembly = createDataAssemblyTool(config);
7960
+ const updateDataAssembly = updateDataAssemblyTool(config);
7961
+ const deleteDataAssembly = deleteDataAssemblyTool(config);
7962
+ const publishDataAssembly = publishDataAssemblyTool(config);
7963
+ const unpublishDataAssembly = unpublishDataAssemblyTool(config);
7964
+ return {
7965
+ getDataAssembly: {
7966
+ title: "get_data_assembly",
7967
+ 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).",
7968
+ inputParams: GetDataAssemblyToolParams.shape,
7969
+ annotations: {
7970
+ readOnlyHint: true,
7971
+ destructiveHint: false,
7972
+ openWorldHint: false
7973
+ },
7974
+ tool: getDataAssembly
7975
+ },
7976
+ getPublishedDataAssembly: {
7977
+ title: "get_published_data_assembly",
7978
+ description: "Get details about a specific published ExO DataAssembly by ID.",
7979
+ inputParams: GetPublishedDataAssemblyToolParams.shape,
7980
+ annotations: {
7981
+ readOnlyHint: true,
7982
+ destructiveHint: false,
7983
+ openWorldHint: false
7984
+ },
7985
+ tool: getPublishedDataAssembly
7986
+ },
7987
+ listDataAssemblies: {
7988
+ title: "list_data_assemblies",
7989
+ 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.",
7990
+ inputParams: ListDataAssembliesToolParams.shape,
7991
+ annotations: {
7992
+ readOnlyHint: true,
7993
+ destructiveHint: false,
7994
+ openWorldHint: false
7995
+ },
7996
+ tool: listDataAssemblies
7997
+ },
7998
+ listPublishedDataAssemblies: {
7999
+ title: "list_published_data_assemblies",
8000
+ 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.",
8001
+ inputParams: ListPublishedDataAssembliesToolParams.shape,
8002
+ annotations: {
8003
+ readOnlyHint: true,
8004
+ destructiveHint: false,
8005
+ openWorldHint: false
8006
+ },
8007
+ tool: listPublishedDataAssemblies
8008
+ },
8009
+ createDataAssembly: {
8010
+ title: "create_data_assembly",
8011
+ description: "Create a new ExO DataAssembly.",
8012
+ inputParams: CreateDataAssemblyToolParams.shape,
8013
+ annotations: {
8014
+ readOnlyHint: false,
8015
+ destructiveHint: false,
8016
+ idempotentHint: false,
8017
+ openWorldHint: false
8018
+ },
8019
+ tool: createDataAssembly
8020
+ },
8021
+ updateDataAssembly: {
8022
+ title: "update_data_assembly",
8023
+ 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.",
8024
+ inputParams: UpdateDataAssemblyToolParams.shape,
8025
+ annotations: {
8026
+ readOnlyHint: false,
8027
+ destructiveHint: false,
8028
+ idempotentHint: false,
8029
+ openWorldHint: false
8030
+ },
8031
+ tool: updateDataAssembly
8032
+ },
8033
+ deleteDataAssembly: {
8034
+ title: "delete_data_assembly",
8035
+ 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.",
8036
+ inputParams: DeleteDataAssemblyToolParams.shape,
8037
+ annotations: {
8038
+ readOnlyHint: false,
8039
+ destructiveHint: true,
8040
+ idempotentHint: false,
8041
+ openWorldHint: false
8042
+ },
8043
+ tool: deleteDataAssembly
8044
+ },
8045
+ publishDataAssembly: {
8046
+ title: "publish_data_assembly",
8047
+ 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.",
8048
+ inputParams: PublishDataAssemblyToolParams.shape,
8049
+ annotations: {
8050
+ readOnlyHint: false,
8051
+ destructiveHint: true,
8052
+ idempotentHint: true,
8053
+ openWorldHint: false
8054
+ },
8055
+ tool: publishDataAssembly
8056
+ },
8057
+ unpublishDataAssembly: {
8058
+ title: "unpublish_data_assembly",
8059
+ 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.",
8060
+ inputParams: UnpublishDataAssemblyToolParams.shape,
8061
+ annotations: {
8062
+ readOnlyHint: false,
8063
+ destructiveHint: true,
8064
+ idempotentHint: true,
8065
+ openWorldHint: false
8066
+ },
8067
+ tool: unpublishDataAssembly
8068
+ }
8069
+ };
8070
+ }
8071
+
8072
+ // src/ContentfulMcpTools.ts
8073
+ var ContentfulMcpTools = class {
8074
+ config;
8075
+ constructor(config) {
8076
+ this.config = {
8077
+ ...config,
8078
+ host: config.host ?? "api.contentful.com",
8079
+ environmentId: config.environmentId ?? "master"
8080
+ };
8081
+ }
8082
+ /**
8083
+ * Update the configuration after initialization
8084
+ *
8085
+ * @param updates - Partial configuration to merge with existing config
8086
+ */
8087
+ updateConfig(updates) {
8088
+ this.config = { ...this.config, ...updates };
8089
+ }
8090
+ /**
8091
+ * Get AI action tools
8092
+ */
8093
+ getAiActionTools() {
8094
+ return createAiActionTools(this.config);
8095
+ }
8096
+ /**
8097
+ * Get asset tools
8098
+ */
8099
+ getAssetTools() {
8100
+ return createAssetTools(this.config);
8101
+ }
8102
+ /**
8103
+ * Get content type tools
8104
+ */
8105
+ getContentTypeTools() {
8106
+ return createContentTypeTools(this.config);
8107
+ }
8108
+ /**
8109
+ * Get ExO component type tools
8110
+ */
8111
+ getComponentTypeTools() {
8112
+ return createComponentTypeTools(this.config);
8113
+ }
8114
+ /**
8115
+ * Get ExO template tools
8116
+ */
8117
+ getTemplateTools() {
8118
+ return createTemplateTools(this.config);
8119
+ }
8120
+ /**
8121
+ * Get ExO experience tools
8122
+ */
8123
+ getExperienceTools() {
8124
+ return createExperienceTools(this.config);
8125
+ }
8126
+ /**
8127
+ * Get context tools
8128
+ */
8129
+ getContextTools() {
8130
+ return createContextTools(this.config);
8131
+ }
8132
+ /**
8133
+ * Get editor interface tools
8134
+ */
8135
+ getEditorInterfaceTools() {
8136
+ return createEditorInterfaceTools(this.config);
8137
+ }
8138
+ /**
8139
+ * Get entry tools
8140
+ */
8141
+ getEntryTools() {
8142
+ return createEntryTools(this.config);
8143
+ }
8144
+ /**
8145
+ * Get environment tools
8146
+ */
8147
+ getEnvironmentTools() {
8148
+ return createEnvironmentTools(this.config);
8149
+ }
8150
+ /**
8151
+ * Get locale tools
8152
+ */
8153
+ getLocaleTools() {
8154
+ return createLocaleTools(this.config);
8155
+ }
8156
+ /**
8157
+ * Get organization tools
8158
+ */
8159
+ getOrgTools() {
8160
+ return createOrgTools(this.config);
8161
+ }
8162
+ /**
8163
+ * Get space tools
8164
+ */
8165
+ getSpaceTools() {
8166
+ return createSpaceTools(this.config);
8167
+ }
8168
+ /**
8169
+ * Get tag tools
8170
+ */
8171
+ getTagTools() {
8172
+ return createTagTools(this.config);
5872
8173
  }
5873
8174
  /**
5874
8175
  * Get taxonomy tools
@@ -5876,6 +8177,18 @@ var ContentfulMcpTools = class {
5876
8177
  getTaxonomyTools() {
5877
8178
  return createTaxonomyTools(this.config);
5878
8179
  }
8180
+ /**
8181
+ * Get ExO fragment tools
8182
+ */
8183
+ getFragmentTools() {
8184
+ return createFragmentTools(this.config);
8185
+ }
8186
+ /**
8187
+ * Get ExO data assembly tools
8188
+ */
8189
+ getDataAssemblyTools() {
8190
+ return createDataAssemblyTools(this.config);
8191
+ }
5879
8192
  /**
5880
8193
  * Get job tools (space-to-space migration)
5881
8194
  */
@@ -5883,6 +8196,44 @@ var ContentfulMcpTools = class {
5883
8196
  return createJobTools(this.config);
5884
8197
  }
5885
8198
  };
8199
+
8200
+ // src/utils/entitlements.ts
8201
+ import { createClient as createClient16 } from "contentful-management";
8202
+ var EXO_M1_FEATURE = "exoM1";
8203
+ function createPlainClient(config) {
8204
+ return createClient16(createClientConfig(config), { type: "plain" });
8205
+ }
8206
+ async function orgHasExoM1(client, organizationId) {
8207
+ try {
8208
+ const entitlements = await client.raw.get(
8209
+ `/organizations/${organizationId}/organization_entitlement_set`
8210
+ );
8211
+ return entitlements.features?.[EXO_M1_FEATURE]?.value === true;
8212
+ } catch {
8213
+ return false;
8214
+ }
8215
+ }
8216
+ async function hasExoM1Entitlement(config) {
8217
+ try {
8218
+ const client = createPlainClient(config);
8219
+ const orgs = await client.organization.getAll();
8220
+ if (!orgs.items.length) {
8221
+ return false;
8222
+ }
8223
+ const results = await Promise.all(
8224
+ orgs.items.map((org) => orgHasExoM1(client, org.sys.id))
8225
+ );
8226
+ return results.some(Boolean);
8227
+ } catch {
8228
+ return false;
8229
+ }
8230
+ }
5886
8231
  export {
5887
- ContentfulMcpTools
8232
+ CONVENTIONS_GUIDANCE,
8233
+ CORE_INVARIANTS,
8234
+ ContentfulMcpTools,
8235
+ EXO_DISPOSITION,
8236
+ EXO_M1_FEATURE,
8237
+ SEARCHING_GUIDANCE,
8238
+ hasExoM1Entitlement
5888
8239
  };