@contentful/mcp-server 1.0.3 → 1.0.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.
- package/README.md +2 -1
- package/build/config/contentful.js +19 -0
- package/build/config/env.js +25 -0
- package/build/config/version.js +2 -0
- package/build/index.js +38 -0
- package/build/prompts/register.js +1 -0
- package/build/resources/register.js +1 -0
- package/build/tools/ai-actions/createAiAction.js +55 -0
- package/build/tools/ai-actions/deleteAiAction.js +20 -0
- package/build/tools/ai-actions/getAiAction.js +20 -0
- package/build/tools/ai-actions/getAiActionInvocation.js +21 -0
- package/build/tools/ai-actions/invokeAiAction.js +74 -0
- package/build/tools/ai-actions/listAiActions.js +65 -0
- package/build/tools/ai-actions/publishAiAction.js +34 -0
- package/build/tools/ai-actions/register.js +20 -0
- package/build/tools/ai-actions/unpublishAiAction.js +28 -0
- package/build/tools/ai-actions/updateAiAction.js +64 -0
- package/build/tools/assets/deleteAsset.js +20 -0
- package/build/tools/assets/getAsset.js +18 -0
- package/build/tools/assets/listAssets.js +68 -0
- package/build/tools/assets/publishAsset.js +58 -0
- package/build/tools/assets/register.js +16 -0
- package/build/tools/assets/unpublishAsset.js +58 -0
- package/build/tools/assets/updateAsset.js +42 -0
- package/build/tools/assets/uploadAsset.js +51 -0
- package/build/tools/context/getInitialContextTool.js +41 -0
- package/build/tools/context/instructions.js +111 -0
- package/build/tools/context/middleware.js +8 -0
- package/build/tools/context/register.js +4 -0
- package/build/tools/context/store.js +15 -0
- package/build/tools/entries/createEntry.js +39 -0
- package/build/tools/entries/deleteEntry.js +21 -0
- package/build/tools/entries/getEntry.js +18 -0
- package/build/tools/entries/publishEntry.js +58 -0
- package/build/tools/entries/register.js +16 -0
- package/build/tools/entries/searchEntries.js +50 -0
- package/build/tools/entries/unpublishEntry.js +58 -0
- package/build/tools/entries/updateEntry.js +50 -0
- package/build/tools/environments/createEnvironment.js +21 -0
- package/build/tools/environments/deleteEnvironment.js +19 -0
- package/build/tools/environments/listEnvironments.js +62 -0
- package/build/tools/environments/register.js +8 -0
- package/build/tools/locales/createLocale.js +49 -0
- package/build/tools/locales/deleteLocale.js +21 -0
- package/build/tools/locales/getLocale.js +18 -0
- package/build/tools/locales/listLocales.js +61 -0
- package/build/tools/locales/register.js +12 -0
- package/build/tools/locales/updateLocale.js +47 -0
- package/build/tools/register.js +20 -0
- package/build/tools/spaces/getSpace.js +20 -0
- package/build/tools/spaces/listSpaces.js +53 -0
- package/build/tools/spaces/register.js +6 -0
- package/build/tools/tags/createTag.js +24 -0
- package/build/tools/tags/listTags.js +50 -0
- package/build/tools/tags/register.js +6 -0
- package/build/tools/types/createContentType.js +33 -0
- package/build/tools/types/deleteContentType.js +20 -0
- package/build/tools/types/getContentType.js +24 -0
- package/build/tools/types/listContentTypes.js +59 -0
- package/build/tools/types/publishContentType.js +22 -0
- package/build/tools/types/register.js +16 -0
- package/build/tools/types/unpublishContentType.js +20 -0
- package/build/tools/types/updateContentType.js +78 -0
- package/build/types/fieldSchema.js +29 -0
- package/build/utils/ai-actions.js +46 -0
- package/build/utils/bulkOperations.js +94 -0
- package/build/utils/formatters.js +39 -0
- package/build/utils/getVersion.js +11 -0
- package/build/utils/response.js +37 -0
- package/build/utils/summarizer.js +39 -0
- package/build/utils/tools.js +20 -0
- package/package.json +1 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createSuccessResponse, withErrorHandling, } from '../../utils/response.js';
|
|
3
|
+
import { BaseToolSchema, createToolClient } from '../../utils/tools.js';
|
|
4
|
+
import { createEntryUnversionedLinks, createEntitiesCollection, waitForBulkActionCompletion, } from '../../utils/bulkOperations.js';
|
|
5
|
+
export const UnpublishEntryToolParams = BaseToolSchema.extend({
|
|
6
|
+
entryId: z
|
|
7
|
+
.union([z.string(), z.array(z.string()).max(100)])
|
|
8
|
+
.describe('The ID of the entry to unpublish (string) or an array of entry IDs (up to 100 entries)'),
|
|
9
|
+
});
|
|
10
|
+
async function tool(args) {
|
|
11
|
+
const baseParams = {
|
|
12
|
+
spaceId: args.spaceId,
|
|
13
|
+
environmentId: args.environmentId,
|
|
14
|
+
};
|
|
15
|
+
const contentfulClient = createToolClient(args);
|
|
16
|
+
// Normalize input to always be an array
|
|
17
|
+
const entryIds = Array.isArray(args.entryId) ? args.entryId : [args.entryId];
|
|
18
|
+
// For single entry, use individual publish for simplicity
|
|
19
|
+
if (entryIds.length === 1) {
|
|
20
|
+
try {
|
|
21
|
+
const entryId = entryIds[0];
|
|
22
|
+
const params = {
|
|
23
|
+
...baseParams,
|
|
24
|
+
entryId,
|
|
25
|
+
};
|
|
26
|
+
// Get the entry first
|
|
27
|
+
const entry = await contentfulClient.entry.get(params);
|
|
28
|
+
// Unpublish the entry
|
|
29
|
+
const unpublishedEntry = await contentfulClient.entry.unpublish(params, entry);
|
|
30
|
+
return createSuccessResponse('Entry unpublished successfully', {
|
|
31
|
+
status: unpublishedEntry.sys.status,
|
|
32
|
+
entryId,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
return createSuccessResponse('Entry unpublish failed', {
|
|
37
|
+
status: error,
|
|
38
|
+
entryId: entryIds[0],
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// For multiple entries, use bulk action API
|
|
43
|
+
// Get the unversioned links for each entry (unpublish doesn't need version info)
|
|
44
|
+
const entityLinks = await createEntryUnversionedLinks(contentfulClient, baseParams, entryIds);
|
|
45
|
+
// Create the collection object
|
|
46
|
+
const entitiesCollection = createEntitiesCollection(entityLinks);
|
|
47
|
+
// Create the bulk action
|
|
48
|
+
const bulkAction = await contentfulClient.bulkAction.unpublish(baseParams, {
|
|
49
|
+
entities: entitiesCollection,
|
|
50
|
+
});
|
|
51
|
+
// Wait for the bulk action to complete
|
|
52
|
+
const action = await waitForBulkActionCompletion(contentfulClient, baseParams, bulkAction.sys.id);
|
|
53
|
+
return createSuccessResponse('Entry(s) unpublished successfully', {
|
|
54
|
+
status: action.sys.status,
|
|
55
|
+
entryIds,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
export const unpublishEntryTool = withErrorHandling(tool, 'Error unpublishing entry');
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createSuccessResponse, withErrorHandling, } from '../../utils/response.js';
|
|
3
|
+
import { BaseToolSchema, createToolClient } from '../../utils/tools.js';
|
|
4
|
+
export const UpdateEntryToolParams = BaseToolSchema.extend({
|
|
5
|
+
entryId: z.string().describe('The ID of the entry to update'),
|
|
6
|
+
fields: z
|
|
7
|
+
.record(z.any())
|
|
8
|
+
.describe('The field values to update. Keys should be field IDs and values should be the field content. Will be merged with existing fields.'),
|
|
9
|
+
metadata: z
|
|
10
|
+
.object({
|
|
11
|
+
tags: z.array(z.object({
|
|
12
|
+
sys: z.object({
|
|
13
|
+
type: z.literal('Link'),
|
|
14
|
+
linkType: z.literal('Tag'),
|
|
15
|
+
id: z.string(),
|
|
16
|
+
}),
|
|
17
|
+
})),
|
|
18
|
+
})
|
|
19
|
+
.optional(),
|
|
20
|
+
});
|
|
21
|
+
async function tool(args) {
|
|
22
|
+
const params = {
|
|
23
|
+
spaceId: args.spaceId,
|
|
24
|
+
environmentId: args.environmentId,
|
|
25
|
+
entryId: args.entryId,
|
|
26
|
+
};
|
|
27
|
+
const contentfulClient = createToolClient(args);
|
|
28
|
+
// First, get the existing entry
|
|
29
|
+
const existingEntry = await contentfulClient.entry.get(params);
|
|
30
|
+
// Merge the provided fields with existing fields
|
|
31
|
+
const mergedFields = {
|
|
32
|
+
...existingEntry.fields,
|
|
33
|
+
...args.fields,
|
|
34
|
+
};
|
|
35
|
+
const allTags = [
|
|
36
|
+
...(existingEntry.metadata?.tags || []),
|
|
37
|
+
...(args.metadata?.tags || []),
|
|
38
|
+
];
|
|
39
|
+
// Update the entry with merged fields
|
|
40
|
+
const updatedEntry = await contentfulClient.entry.update(params, {
|
|
41
|
+
...existingEntry,
|
|
42
|
+
fields: mergedFields,
|
|
43
|
+
metadata: {
|
|
44
|
+
tags: allTags,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
//return info about the entry that was updated
|
|
48
|
+
return createSuccessResponse('Entry updated successfully', { updatedEntry });
|
|
49
|
+
}
|
|
50
|
+
export const updateEntryTool = withErrorHandling(tool, 'Error updating entry');
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createSuccessResponse, withErrorHandling, } from '../../utils/response.js';
|
|
3
|
+
import { BaseToolSchema, createToolClient } from '../../utils/tools.js';
|
|
4
|
+
export const CreateEnvironmentToolParams = BaseToolSchema.extend({
|
|
5
|
+
environmentId: z.string().describe('The ID of the environment to create'),
|
|
6
|
+
name: z.string().describe('The name of the environment to create'),
|
|
7
|
+
});
|
|
8
|
+
async function tool(args) {
|
|
9
|
+
const contentfulClient = createToolClient(args);
|
|
10
|
+
// Create the environment
|
|
11
|
+
const environment = await contentfulClient.environment.createWithId({
|
|
12
|
+
spaceId: args.spaceId,
|
|
13
|
+
environmentId: args.environmentId,
|
|
14
|
+
}, {
|
|
15
|
+
name: args.name,
|
|
16
|
+
});
|
|
17
|
+
return createSuccessResponse('Environment created successfully', {
|
|
18
|
+
environment,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export const createEnvironmentTool = withErrorHandling(tool, 'Error creating environment');
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createSuccessResponse, withErrorHandling, } from '../../utils/response.js';
|
|
3
|
+
import { BaseToolSchema, createToolClient } from '../../utils/tools.js';
|
|
4
|
+
export const DeleteEnvironmentToolParams = BaseToolSchema.extend({
|
|
5
|
+
environmentId: z.string().describe('The ID of the environment to delete'),
|
|
6
|
+
});
|
|
7
|
+
async function tool(args) {
|
|
8
|
+
const params = {
|
|
9
|
+
spaceId: args.spaceId,
|
|
10
|
+
environmentId: args.environmentId,
|
|
11
|
+
};
|
|
12
|
+
const contentfulClient = createToolClient(args);
|
|
13
|
+
// Delete the environment
|
|
14
|
+
await contentfulClient.environment.delete(params);
|
|
15
|
+
return createSuccessResponse('Environment deleted successfully', {
|
|
16
|
+
environmentId: args.environmentId,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
export const deleteEnvironmentTool = withErrorHandling(tool, 'Error deleting environment');
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createSuccessResponse, withErrorHandling, } from '../../utils/response.js';
|
|
3
|
+
import { BaseToolSchema, createToolClient } from '../../utils/tools.js';
|
|
4
|
+
import { summarizeData } from '../../utils/summarizer.js';
|
|
5
|
+
// Extend BaseToolSchema but make environmentId optional since it's not needed for listing
|
|
6
|
+
export const ListEnvironmentsToolParams = BaseToolSchema.extend({
|
|
7
|
+
environmentId: z
|
|
8
|
+
.string()
|
|
9
|
+
.optional()
|
|
10
|
+
.describe('The ID of the Contentful environment (not required for listing)'),
|
|
11
|
+
limit: z
|
|
12
|
+
.number()
|
|
13
|
+
.optional()
|
|
14
|
+
.describe('Maximum number of environments to return (max 10)'),
|
|
15
|
+
skip: z
|
|
16
|
+
.number()
|
|
17
|
+
.optional()
|
|
18
|
+
.describe('Skip this many environments for pagination'),
|
|
19
|
+
select: z
|
|
20
|
+
.string()
|
|
21
|
+
.optional()
|
|
22
|
+
.describe('Comma-separated list of fields to return'),
|
|
23
|
+
order: z.string().optional().describe('Order environments by this field'),
|
|
24
|
+
});
|
|
25
|
+
async function tool(args) {
|
|
26
|
+
// Provide a default environmentId if not specified
|
|
27
|
+
const clientArgs = {
|
|
28
|
+
spaceId: args.spaceId,
|
|
29
|
+
environmentId: args.environmentId || 'master',
|
|
30
|
+
};
|
|
31
|
+
const contentfulClient = createToolClient(clientArgs);
|
|
32
|
+
const environments = await contentfulClient.environment.getMany({
|
|
33
|
+
spaceId: args.spaceId,
|
|
34
|
+
query: {
|
|
35
|
+
limit: Math.min(args.limit || 10, 10),
|
|
36
|
+
skip: args.skip || 0,
|
|
37
|
+
...(args.select && { select: args.select }),
|
|
38
|
+
...(args.order && { order: args.order }),
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
const summarizedEnvironments = environments.items.map((environment) => ({
|
|
42
|
+
id: environment.sys.id,
|
|
43
|
+
name: environment.name,
|
|
44
|
+
status: environment.sys.status?.sys?.id || 'unknown',
|
|
45
|
+
createdAt: environment.sys.createdAt,
|
|
46
|
+
updatedAt: environment.sys.updatedAt,
|
|
47
|
+
}));
|
|
48
|
+
const summarized = summarizeData({
|
|
49
|
+
...environments,
|
|
50
|
+
items: summarizedEnvironments,
|
|
51
|
+
}, {
|
|
52
|
+
maxItems: 10,
|
|
53
|
+
remainingMessage: 'To see more environments, please ask me to retrieve the next page using the skip parameter.',
|
|
54
|
+
});
|
|
55
|
+
return createSuccessResponse('Environments retrieved successfully', {
|
|
56
|
+
environments: summarized,
|
|
57
|
+
total: environments.total,
|
|
58
|
+
limit: environments.limit,
|
|
59
|
+
skip: environments.skip,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
export const listEnvironmentsTool = withErrorHandling(tool, 'Error listing environments');
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createEnvironmentTool, CreateEnvironmentToolParams, } from './createEnvironment.js';
|
|
2
|
+
import { listEnvironmentsTool, ListEnvironmentsToolParams, } from './listEnvironments.js';
|
|
3
|
+
import { deleteEnvironmentTool, DeleteEnvironmentToolParams, } from './deleteEnvironment.js';
|
|
4
|
+
export function registerEnvironmentTools(server) {
|
|
5
|
+
server.tool('create_environment', 'Create a new environment', CreateEnvironmentToolParams.shape, createEnvironmentTool);
|
|
6
|
+
server.tool('list_environments', 'List all environments in a space', ListEnvironmentsToolParams.shape, listEnvironmentsTool);
|
|
7
|
+
server.tool('delete_environment', 'Delete an environment', DeleteEnvironmentToolParams.shape, deleteEnvironmentTool);
|
|
8
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createSuccessResponse, withErrorHandling, } from '../../utils/response.js';
|
|
3
|
+
import { BaseToolSchema, createToolClient } from '../../utils/tools.js';
|
|
4
|
+
export const CreateLocaleToolParams = BaseToolSchema.extend({
|
|
5
|
+
name: z.string().describe('The name of the locale'),
|
|
6
|
+
code: z.string().describe('The locale code (e.g., "en-US")'),
|
|
7
|
+
fallbackCode: z
|
|
8
|
+
.string()
|
|
9
|
+
.optional()
|
|
10
|
+
.describe('The locale code to fallback to when there is no content for the current locale'),
|
|
11
|
+
contentDeliveryApi: z
|
|
12
|
+
.boolean()
|
|
13
|
+
.optional()
|
|
14
|
+
.default(true)
|
|
15
|
+
.describe('If the content under this locale should be available on the CDA (for public reading)'),
|
|
16
|
+
contentManagementApi: z
|
|
17
|
+
.boolean()
|
|
18
|
+
.optional()
|
|
19
|
+
.default(true)
|
|
20
|
+
.describe('If the content under this locale should be available on the CMA (for editing)'),
|
|
21
|
+
default: z
|
|
22
|
+
.boolean()
|
|
23
|
+
.optional()
|
|
24
|
+
.default(false)
|
|
25
|
+
.describe('If this is the default locale'),
|
|
26
|
+
optional: z
|
|
27
|
+
.boolean()
|
|
28
|
+
.optional()
|
|
29
|
+
.default(false)
|
|
30
|
+
.describe('If the locale needs to be filled in on entries or not'),
|
|
31
|
+
});
|
|
32
|
+
async function tool(args) {
|
|
33
|
+
const params = {
|
|
34
|
+
spaceId: args.spaceId,
|
|
35
|
+
environmentId: args.environmentId,
|
|
36
|
+
};
|
|
37
|
+
const contentfulClient = createToolClient(args);
|
|
38
|
+
// Create the locale
|
|
39
|
+
const newLocale = await contentfulClient.locale.create(params, {
|
|
40
|
+
name: args.name,
|
|
41
|
+
code: args.code,
|
|
42
|
+
fallbackCode: args.fallbackCode,
|
|
43
|
+
contentDeliveryApi: args.contentDeliveryApi,
|
|
44
|
+
contentManagementApi: args.contentManagementApi,
|
|
45
|
+
optional: args.optional,
|
|
46
|
+
});
|
|
47
|
+
return createSuccessResponse('Locale created successfully', { newLocale });
|
|
48
|
+
}
|
|
49
|
+
export const createLocaleTool = withErrorHandling(tool, 'Error creating locale');
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createSuccessResponse, withErrorHandling, } from '../../utils/response.js';
|
|
3
|
+
import { BaseToolSchema, createToolClient } from '../../utils/tools.js';
|
|
4
|
+
export const DeleteLocaleToolParams = BaseToolSchema.extend({
|
|
5
|
+
localeId: z.string().describe('The ID of the locale to delete'),
|
|
6
|
+
});
|
|
7
|
+
async function tool(args) {
|
|
8
|
+
const params = {
|
|
9
|
+
spaceId: args.spaceId,
|
|
10
|
+
environmentId: args.environmentId,
|
|
11
|
+
localeId: args.localeId,
|
|
12
|
+
};
|
|
13
|
+
const contentfulClient = createToolClient(args);
|
|
14
|
+
// First, get the locale to check its current state
|
|
15
|
+
const locale = await contentfulClient.locale.get(params);
|
|
16
|
+
// Delete the locale
|
|
17
|
+
await contentfulClient.locale.delete(params);
|
|
18
|
+
// Return info about the locale that was deleted
|
|
19
|
+
return createSuccessResponse('Locale deleted successfully', { locale });
|
|
20
|
+
}
|
|
21
|
+
export const deleteLocaleTool = withErrorHandling(tool, 'Error deleting locale');
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createSuccessResponse, withErrorHandling, } from '../../utils/response.js';
|
|
3
|
+
import { BaseToolSchema, createToolClient } from '../../utils/tools.js';
|
|
4
|
+
export const GetLocaleToolParams = BaseToolSchema.extend({
|
|
5
|
+
localeId: z.string().describe('The ID of the locale to retrieve'),
|
|
6
|
+
});
|
|
7
|
+
async function tool(args) {
|
|
8
|
+
const params = {
|
|
9
|
+
spaceId: args.spaceId,
|
|
10
|
+
environmentId: args.environmentId,
|
|
11
|
+
localeId: args.localeId,
|
|
12
|
+
};
|
|
13
|
+
const contentfulClient = createToolClient(args);
|
|
14
|
+
// Get the locale
|
|
15
|
+
const locale = await contentfulClient.locale.get(params);
|
|
16
|
+
return createSuccessResponse('Locale retrieved successfully', { locale });
|
|
17
|
+
}
|
|
18
|
+
export const getLocaleTool = withErrorHandling(tool, 'Error retrieving locale');
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createSuccessResponse, withErrorHandling, } from '../../utils/response.js';
|
|
3
|
+
import { BaseToolSchema, createToolClient } from '../../utils/tools.js';
|
|
4
|
+
import { summarizeData } from '../../utils/summarizer.js';
|
|
5
|
+
export const ListLocaleToolParams = BaseToolSchema.extend({
|
|
6
|
+
limit: z.number().optional().describe('Maximum number of locales to return'),
|
|
7
|
+
skip: z.number().optional().describe('Skip this many locales for pagination'),
|
|
8
|
+
select: z
|
|
9
|
+
.string()
|
|
10
|
+
.optional()
|
|
11
|
+
.describe('Comma-separated list of fields to return'),
|
|
12
|
+
include: z
|
|
13
|
+
.number()
|
|
14
|
+
.optional()
|
|
15
|
+
.describe('Include this many levels of linked entries'),
|
|
16
|
+
order: z.string().optional().describe('Order locales by this field'),
|
|
17
|
+
});
|
|
18
|
+
async function tool(args) {
|
|
19
|
+
const params = {
|
|
20
|
+
spaceId: args.spaceId,
|
|
21
|
+
environmentId: args.environmentId,
|
|
22
|
+
};
|
|
23
|
+
const contentfulClient = createToolClient(args);
|
|
24
|
+
const locales = await contentfulClient.locale.getMany({
|
|
25
|
+
...params,
|
|
26
|
+
query: {
|
|
27
|
+
limit: args.limit || 100,
|
|
28
|
+
skip: args.skip || 0,
|
|
29
|
+
...(args.select && { select: args.select }),
|
|
30
|
+
...(args.include && { include: args.include }),
|
|
31
|
+
...(args.order && { order: args.order }),
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
const summarizedLocales = locales.items.map((locale) => ({
|
|
35
|
+
id: locale.sys.id,
|
|
36
|
+
name: locale.name,
|
|
37
|
+
code: locale.code,
|
|
38
|
+
fallbackCode: locale.fallbackCode || null,
|
|
39
|
+
contentDeliveryApi: locale.contentDeliveryApi,
|
|
40
|
+
contentManagementApi: locale.contentManagementApi,
|
|
41
|
+
default: locale.default,
|
|
42
|
+
optional: locale.optional,
|
|
43
|
+
createdAt: locale.sys.createdAt,
|
|
44
|
+
updatedAt: locale.sys.updatedAt,
|
|
45
|
+
version: locale.sys.version,
|
|
46
|
+
}));
|
|
47
|
+
const summarized = summarizeData({
|
|
48
|
+
...locales,
|
|
49
|
+
items: summarizedLocales,
|
|
50
|
+
}, {
|
|
51
|
+
maxItems: 10,
|
|
52
|
+
remainingMessage: 'To see more locales, please ask me to retrieve the next page using the skip parameter.',
|
|
53
|
+
});
|
|
54
|
+
return createSuccessResponse('Locales retrieved successfully', {
|
|
55
|
+
locales: summarized,
|
|
56
|
+
total: locales.total,
|
|
57
|
+
limit: locales.limit,
|
|
58
|
+
skip: locales.skip,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
export const listLocaleTool = withErrorHandling(tool, 'Error listing locales');
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { getLocaleTool, GetLocaleToolParams } from './getLocale.js';
|
|
2
|
+
import { createLocaleTool, CreateLocaleToolParams } from './createLocale.js';
|
|
3
|
+
import { listLocaleTool, ListLocaleToolParams } from './listLocales.js';
|
|
4
|
+
import { updateLocaleTool, UpdateLocaleToolParams } from './updateLocale.js';
|
|
5
|
+
import { deleteLocaleTool, DeleteLocaleToolParams } from './deleteLocale.js';
|
|
6
|
+
export function registerLocaleTools(server) {
|
|
7
|
+
server.tool('get_locale', 'Retrieve a specific locale from your Contentful environment', GetLocaleToolParams.shape, getLocaleTool);
|
|
8
|
+
server.tool('create_locale', 'Create a new locale in your Contentful environment. A locale defines a language-region pair (e.g., "en-US" for English United States). You can specify fallback behavior, API availability settings, and whether the locale is optional for content editors. Note: setting \'default\' is currently not supported.', CreateLocaleToolParams.shape, createLocaleTool);
|
|
9
|
+
server.tool('list_locales', 'List all locales in your Contentful environment. Returns locale information including language codes, fallback settings, and API availability.', ListLocaleToolParams.shape, listLocaleTool);
|
|
10
|
+
server.tool('update_locale', 'Update an existing locale in your Contentful environment. You can modify the locale name, code, fallback behavior, API availability settings, and whether the locale is optional for content editors. Only provide the fields you want to change. IMPORTANT: internal_code cannot be updated.', UpdateLocaleToolParams.shape, updateLocaleTool);
|
|
11
|
+
server.tool('delete_locale', 'Delete a specific locale from your Contentful environment. This operation permanently removes the locale and cannot be undone.', DeleteLocaleToolParams.shape, deleteLocaleTool);
|
|
12
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createSuccessResponse, withErrorHandling, } from '../../utils/response.js';
|
|
3
|
+
import { BaseToolSchema, createToolClient } from '../../utils/tools.js';
|
|
4
|
+
export const UpdateLocaleToolParams = BaseToolSchema.extend({
|
|
5
|
+
localeId: z.string().describe('The ID of the locale to update'),
|
|
6
|
+
fields: z.object({
|
|
7
|
+
name: z.string().optional().describe('The name of the locale'),
|
|
8
|
+
// NOTE: internal_code changes are not allowed
|
|
9
|
+
code: z.string().optional().describe('The code of the locale'),
|
|
10
|
+
fallbackCode: z
|
|
11
|
+
.string()
|
|
12
|
+
.optional()
|
|
13
|
+
.describe('The locale code to fallback to when there is no content for the current locale'),
|
|
14
|
+
contentDeliveryApi: z
|
|
15
|
+
.boolean()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe('If the content under this locale should be available on the CDA (for public reading)'),
|
|
18
|
+
contentManagementApi: z
|
|
19
|
+
.boolean()
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('If the content under this locale should be available on the CMA (for editing)'),
|
|
22
|
+
optional: z
|
|
23
|
+
.boolean()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe('If the locale needs to be filled in on entries or not'),
|
|
26
|
+
}),
|
|
27
|
+
});
|
|
28
|
+
async function tool(args) {
|
|
29
|
+
const params = {
|
|
30
|
+
spaceId: args.spaceId,
|
|
31
|
+
environmentId: args.environmentId,
|
|
32
|
+
localeId: args.localeId,
|
|
33
|
+
};
|
|
34
|
+
const contentfulClient = createToolClient(args);
|
|
35
|
+
// First, get the existing locale
|
|
36
|
+
const existingLocale = await contentfulClient.locale.get(params);
|
|
37
|
+
// Remove read-only fields (nternal_code cannot be updated)
|
|
38
|
+
delete existingLocale.internal_code;
|
|
39
|
+
// Build update data with only provided fields, merging with existing locale
|
|
40
|
+
const updateData = { ...existingLocale, ...args.fields };
|
|
41
|
+
// Update the locale with merged data
|
|
42
|
+
const updatedLocale = await contentfulClient.locale.update(params, updateData);
|
|
43
|
+
return createSuccessResponse('Locale updated successfully', {
|
|
44
|
+
updatedLocale,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
export const updateLocaleTool = withErrorHandling(tool, 'Error updating locale');
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { registerContextTools } from './context/register.js';
|
|
2
|
+
import { registerEntriesTools } from './entries/register.js';
|
|
3
|
+
import { registerContentTypesTools } from './types/register.js';
|
|
4
|
+
import { registerEnvironmentTools } from './environments/register.js';
|
|
5
|
+
import { registerAssetTools } from './assets/register.js';
|
|
6
|
+
import { registerSpaceTools } from './spaces/register.js';
|
|
7
|
+
import { registerTagsTools } from './tags/register.js';
|
|
8
|
+
import { registerAiActionsTools } from './ai-actions/register.js';
|
|
9
|
+
import { registerLocaleTools } from './locales/register.js';
|
|
10
|
+
export function registerAllTools(server) {
|
|
11
|
+
registerContextTools(server);
|
|
12
|
+
registerEntriesTools(server);
|
|
13
|
+
registerContentTypesTools(server);
|
|
14
|
+
registerEnvironmentTools(server);
|
|
15
|
+
registerAssetTools(server);
|
|
16
|
+
registerSpaceTools(server);
|
|
17
|
+
registerTagsTools(server);
|
|
18
|
+
registerAiActionsTools(server);
|
|
19
|
+
registerLocaleTools(server);
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createSuccessResponse, withErrorHandling, } from '../../utils/response.js';
|
|
3
|
+
import ctfl from 'contentful-management';
|
|
4
|
+
import { getDefaultClientConfig } from '../../config/contentful.js';
|
|
5
|
+
export const GetSpaceToolParams = z.object({
|
|
6
|
+
spaceId: z.string().describe('The ID of the space to retrieve'),
|
|
7
|
+
});
|
|
8
|
+
async function tool(args) {
|
|
9
|
+
// Create a client without space-specific configuration
|
|
10
|
+
const clientConfig = getDefaultClientConfig();
|
|
11
|
+
// Remove space from config since we'll specify it in the get call
|
|
12
|
+
delete clientConfig.space;
|
|
13
|
+
const contentfulClient = ctfl.createClient(clientConfig, { type: 'plain' });
|
|
14
|
+
// Get the space
|
|
15
|
+
const space = await contentfulClient.space.get({
|
|
16
|
+
spaceId: args.spaceId,
|
|
17
|
+
});
|
|
18
|
+
return createSuccessResponse('Space retrieved successfully', { space });
|
|
19
|
+
}
|
|
20
|
+
export const getSpaceTool = withErrorHandling(tool, 'Error retrieving space');
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createSuccessResponse, withErrorHandling, } from '../../utils/response.js';
|
|
3
|
+
import ctfl from 'contentful-management';
|
|
4
|
+
import { getDefaultClientConfig } from '../../config/contentful.js';
|
|
5
|
+
import { summarizeData } from '../../utils/summarizer.js';
|
|
6
|
+
// For listing spaces, we don't need spaceId or environmentId parameters
|
|
7
|
+
export const ListSpacesToolParams = z.object({
|
|
8
|
+
limit: z
|
|
9
|
+
.number()
|
|
10
|
+
.optional()
|
|
11
|
+
.describe('Maximum number of spaces to return (max 10)'),
|
|
12
|
+
skip: z.number().optional().describe('Skip this many spaces for pagination'),
|
|
13
|
+
select: z
|
|
14
|
+
.string()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe('Comma-separated list of fields to return'),
|
|
17
|
+
order: z.string().optional().describe('Order spaces by this field'),
|
|
18
|
+
});
|
|
19
|
+
async function tool(args) {
|
|
20
|
+
// Create a client without space-specific configuration for listing all spaces
|
|
21
|
+
const clientConfig = getDefaultClientConfig();
|
|
22
|
+
// Remove space from config since we're listing all spaces
|
|
23
|
+
delete clientConfig.space;
|
|
24
|
+
const contentfulClient = ctfl.createClient(clientConfig, { type: 'plain' });
|
|
25
|
+
const spaces = await contentfulClient.space.getMany({
|
|
26
|
+
query: {
|
|
27
|
+
limit: Math.min(args.limit || 10, 10),
|
|
28
|
+
skip: args.skip || 0,
|
|
29
|
+
...(args.select && { select: args.select }),
|
|
30
|
+
...(args.order && { order: args.order }),
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
const summarizedSpaces = spaces.items.map((space) => ({
|
|
34
|
+
id: space.sys.id,
|
|
35
|
+
name: space.name,
|
|
36
|
+
createdAt: space.sys.createdAt,
|
|
37
|
+
updatedAt: space.sys.updatedAt,
|
|
38
|
+
}));
|
|
39
|
+
const summarized = summarizeData({
|
|
40
|
+
...spaces,
|
|
41
|
+
items: summarizedSpaces,
|
|
42
|
+
}, {
|
|
43
|
+
maxItems: 10,
|
|
44
|
+
remainingMessage: 'To see more spaces, please ask me to retrieve the next page using the skip parameter.',
|
|
45
|
+
});
|
|
46
|
+
return createSuccessResponse('Spaces retrieved successfully', {
|
|
47
|
+
spaces: summarized,
|
|
48
|
+
total: spaces.total,
|
|
49
|
+
limit: spaces.limit,
|
|
50
|
+
skip: spaces.skip,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
export const listSpacesTool = withErrorHandling(tool, 'Error listing spaces');
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { listSpacesTool, ListSpacesToolParams } from './listSpaces.js';
|
|
2
|
+
import { getSpaceTool, GetSpaceToolParams } from './getSpace.js';
|
|
3
|
+
export function registerSpaceTools(server) {
|
|
4
|
+
server.tool('list_spaces', 'List all available spaces', ListSpacesToolParams.shape, listSpacesTool);
|
|
5
|
+
server.tool('get_space', 'Get details of a space', GetSpaceToolParams.shape, getSpaceTool);
|
|
6
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createSuccessResponse, withErrorHandling, } from '../../utils/response.js';
|
|
3
|
+
import { BaseToolSchema, createToolClient } from '../../utils/tools.js';
|
|
4
|
+
export const CreateTagToolParams = BaseToolSchema.extend({
|
|
5
|
+
name: z.string().describe('The name of the tag'),
|
|
6
|
+
id: z.string().describe('The ID of the tag'),
|
|
7
|
+
visibility: z
|
|
8
|
+
.enum(['public', 'private'])
|
|
9
|
+
.describe('The visibility of the tag. Default to private if not specified'),
|
|
10
|
+
});
|
|
11
|
+
async function tool(args) {
|
|
12
|
+
const params = {
|
|
13
|
+
spaceId: args.spaceId,
|
|
14
|
+
environmentId: args.environmentId,
|
|
15
|
+
tagId: args.id,
|
|
16
|
+
};
|
|
17
|
+
const contentfulClient = createToolClient(args);
|
|
18
|
+
let newTag = await contentfulClient.tag.createWithId(params, {
|
|
19
|
+
name: args.name,
|
|
20
|
+
sys: { visibility: args.visibility },
|
|
21
|
+
});
|
|
22
|
+
return createSuccessResponse('Tag created successfully', { newTag });
|
|
23
|
+
}
|
|
24
|
+
export const createTagTool = withErrorHandling(tool, 'Error creating tag');
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createSuccessResponse, withErrorHandling, } from '../../utils/response.js';
|
|
3
|
+
import { BaseToolSchema, createToolClient } from '../../utils/tools.js';
|
|
4
|
+
import { summarizeData } from '../../utils/summarizer.js';
|
|
5
|
+
export const ListTagsToolParams = BaseToolSchema.extend({
|
|
6
|
+
limit: z.number().optional().describe('Maximum number of tags to return'),
|
|
7
|
+
skip: z.number().optional().describe('Skip this many tags for pagination'),
|
|
8
|
+
select: z
|
|
9
|
+
.string()
|
|
10
|
+
.optional()
|
|
11
|
+
.describe('Comma-separated list of fields to return'),
|
|
12
|
+
order: z.string().optional().describe('Order tags by this field'),
|
|
13
|
+
});
|
|
14
|
+
async function tool(args) {
|
|
15
|
+
const params = {
|
|
16
|
+
spaceId: args.spaceId,
|
|
17
|
+
environmentId: args.environmentId,
|
|
18
|
+
};
|
|
19
|
+
const contentfulClient = createToolClient(args);
|
|
20
|
+
const tags = await contentfulClient.tag.getMany({
|
|
21
|
+
...params,
|
|
22
|
+
query: {
|
|
23
|
+
limit: args.limit || 100,
|
|
24
|
+
skip: args.skip || 0,
|
|
25
|
+
...(args.select && { select: args.select }),
|
|
26
|
+
...(args.order && { order: args.order }),
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
const summarizedTags = tags.items.map((tag) => ({
|
|
30
|
+
id: tag.sys.id,
|
|
31
|
+
name: tag.name,
|
|
32
|
+
visibility: tag.sys.visibility,
|
|
33
|
+
createdAt: tag.sys.createdAt,
|
|
34
|
+
updatedAt: tag.sys.updatedAt,
|
|
35
|
+
}));
|
|
36
|
+
const summarized = summarizeData({
|
|
37
|
+
...tags,
|
|
38
|
+
items: summarizedTags,
|
|
39
|
+
}, {
|
|
40
|
+
maxItems: 100,
|
|
41
|
+
remainingMessage: 'To see more tags, please ask me to retrieve the next page using the skip parameter.',
|
|
42
|
+
});
|
|
43
|
+
return createSuccessResponse('Tags retrieved successfully', {
|
|
44
|
+
tags: summarized,
|
|
45
|
+
total: tags.total,
|
|
46
|
+
limit: tags.limit,
|
|
47
|
+
skip: tags.skip,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export const listTagsTool = withErrorHandling(tool, 'Error listing tags');
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { listTagsTool, ListTagsToolParams } from './listTags.js';
|
|
2
|
+
import { createTagTool, CreateTagToolParams } from './createTag.js';
|
|
3
|
+
export function registerTagsTools(server) {
|
|
4
|
+
server.tool('list_tags', 'List all tags in a space. Returns all tags that exist in a given environment.', ListTagsToolParams.shape, listTagsTool);
|
|
5
|
+
server.tool('create_tag', 'Creates a new tag and returns it. Both name and ID must be unique to each environment. Tag names can be modified after creation, but the tag ID cannot. The tag visibility can be set to public or private, defaulting to private if not specified.', CreateTagToolParams.shape, createTagTool);
|
|
6
|
+
}
|