@contentful/mcp-server 1.0.5 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/config/env.js +2 -2
- package/build/tools/ai-actions/mockClient.js +228 -0
- package/build/tools/assets/mockClient.js +159 -0
- package/build/tools/{types → content-types}/createContentType.js +10 -3
- package/build/tools/content-types/mockClient.js +138 -0
- package/build/tools/locales/mockClient.js +54 -0
- package/build/tools/register.js +1 -1
- package/build/types/fieldSchema.js +1 -0
- package/package.json +4 -2
- /package/build/tools/{types → content-types}/deleteContentType.js +0 -0
- /package/build/tools/{types → content-types}/getContentType.js +0 -0
- /package/build/tools/{types → content-types}/listContentTypes.js +0 -0
- /package/build/tools/{types → content-types}/publishContentType.js +0 -0
- /package/build/tools/{types → content-types}/register.js +0 -0
- /package/build/tools/{types → content-types}/unpublishContentType.js +0 -0
- /package/build/tools/{types → content-types}/updateContentType.js +0 -0
package/build/config/env.js
CHANGED
|
@@ -4,7 +4,7 @@ dotenv.config();
|
|
|
4
4
|
const EnvSchema = z.object({
|
|
5
5
|
CONTENTFUL_MANAGEMENT_ACCESS_TOKEN: z
|
|
6
6
|
.string()
|
|
7
|
-
.describe('
|
|
7
|
+
.describe('Contentful CMA token'),
|
|
8
8
|
CONTENTFUL_HOST: z
|
|
9
9
|
.string()
|
|
10
10
|
.optional()
|
|
@@ -19,7 +19,7 @@ const EnvSchema = z.object({
|
|
|
19
19
|
.describe('Contentful environment ID'),
|
|
20
20
|
});
|
|
21
21
|
export const env = EnvSchema.safeParse(process.env);
|
|
22
|
-
if (!env.success) {
|
|
22
|
+
if (!env.success && process.env.TEST_TYPE !== 'unit') {
|
|
23
23
|
console.error('Invalid environment variables', env.error.format());
|
|
24
24
|
process.exit(1);
|
|
25
25
|
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
import { createToolClient } from '../../utils/tools.js';
|
|
3
|
+
import { VariableType, OutputFormat } from '../../utils/ai-actions.js';
|
|
4
|
+
/**
|
|
5
|
+
* Shared mock objects for AI action tests
|
|
6
|
+
* Provides standardized mock client and AI action objects used across all AI action tests
|
|
7
|
+
*/
|
|
8
|
+
// Create mock functions for the client
|
|
9
|
+
export const mockAiActionGet = vi.fn();
|
|
10
|
+
export const mockAiActionCreate = vi.fn();
|
|
11
|
+
export const mockAiActionUpdate = vi.fn();
|
|
12
|
+
export const mockAiActionDelete = vi.fn();
|
|
13
|
+
export const mockAiActionPublish = vi.fn();
|
|
14
|
+
export const mockAiActionUnpublish = vi.fn();
|
|
15
|
+
export const mockAiActionGetMany = vi.fn();
|
|
16
|
+
export const mockAiActionInvoke = vi.fn();
|
|
17
|
+
export const mockAiActionInvocationGet = vi.fn();
|
|
18
|
+
/**
|
|
19
|
+
* Standard mock Contentful client with all AI action operations
|
|
20
|
+
*/
|
|
21
|
+
export const mockClient = {
|
|
22
|
+
aiAction: {
|
|
23
|
+
get: mockAiActionGet,
|
|
24
|
+
create: mockAiActionCreate,
|
|
25
|
+
update: mockAiActionUpdate,
|
|
26
|
+
delete: mockAiActionDelete,
|
|
27
|
+
publish: mockAiActionPublish,
|
|
28
|
+
unpublish: mockAiActionUnpublish,
|
|
29
|
+
getMany: mockAiActionGetMany,
|
|
30
|
+
invoke: mockAiActionInvoke,
|
|
31
|
+
},
|
|
32
|
+
aiActionInvocation: {
|
|
33
|
+
get: mockAiActionInvocationGet,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Sets up the mock client for tests
|
|
38
|
+
* Call this in beforeEach to ensure the mock is properly configured
|
|
39
|
+
*/
|
|
40
|
+
export function setupMockClient() {
|
|
41
|
+
vi.mocked(createToolClient).mockReturnValue(mockClient);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Standard mock AI action object used across tests
|
|
45
|
+
*/
|
|
46
|
+
export const mockAiAction = {
|
|
47
|
+
sys: {
|
|
48
|
+
id: 'test-ai-action-id',
|
|
49
|
+
type: 'AiAction',
|
|
50
|
+
version: 1,
|
|
51
|
+
space: {
|
|
52
|
+
sys: {
|
|
53
|
+
type: 'Link',
|
|
54
|
+
linkType: 'Space',
|
|
55
|
+
id: 'test-space-id',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
environment: {
|
|
59
|
+
sys: {
|
|
60
|
+
type: 'Link',
|
|
61
|
+
linkType: 'Environment',
|
|
62
|
+
id: 'test-environment',
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
createdAt: '2023-01-01T00:00:00Z',
|
|
66
|
+
updatedAt: '2023-01-01T00:00:00Z',
|
|
67
|
+
publishedVersion: undefined,
|
|
68
|
+
},
|
|
69
|
+
name: 'Test AI Action',
|
|
70
|
+
description: 'A test AI action for unit tests',
|
|
71
|
+
instruction: {
|
|
72
|
+
template: 'Translate the following text from {{var.sourceLocale}} to {{var.targetLocale}}: {{var.sourceContent}}',
|
|
73
|
+
variables: [
|
|
74
|
+
{
|
|
75
|
+
id: 'sourceContent',
|
|
76
|
+
name: 'Source Content',
|
|
77
|
+
type: VariableType.TEXT,
|
|
78
|
+
description: 'The content to be translated',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: 'sourceLocale',
|
|
82
|
+
name: 'Source Locale',
|
|
83
|
+
type: VariableType.LOCALE,
|
|
84
|
+
description: 'The source language locale',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: 'targetLocale',
|
|
88
|
+
name: 'Target Locale',
|
|
89
|
+
type: VariableType.LOCALE,
|
|
90
|
+
description: 'The target language locale',
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
configuration: {
|
|
95
|
+
modelType: 'gpt-4',
|
|
96
|
+
modelTemperature: 0.3,
|
|
97
|
+
},
|
|
98
|
+
testCases: [],
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Mock AI action with published version
|
|
102
|
+
*/
|
|
103
|
+
export const mockPublishedAiAction = {
|
|
104
|
+
...mockAiAction,
|
|
105
|
+
sys: {
|
|
106
|
+
...mockAiAction.sys,
|
|
107
|
+
publishedVersion: 1,
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Standard test arguments for AI action operations
|
|
112
|
+
*/
|
|
113
|
+
export const mockArgs = {
|
|
114
|
+
spaceId: 'test-space-id',
|
|
115
|
+
environmentId: 'test-environment',
|
|
116
|
+
aiActionId: 'test-ai-action-id',
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* Mock AI action invocation result
|
|
120
|
+
*/
|
|
121
|
+
export const mockAiActionInvocation = {
|
|
122
|
+
sys: {
|
|
123
|
+
id: 'test-invocation-id',
|
|
124
|
+
type: 'AiActionInvocation',
|
|
125
|
+
status: 'COMPLETED',
|
|
126
|
+
createdAt: '2023-01-01T00:00:00Z',
|
|
127
|
+
updatedAt: '2023-01-01T00:00:00Z',
|
|
128
|
+
},
|
|
129
|
+
result: {
|
|
130
|
+
content: 'Translated content result',
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Mock AI action invocation status response
|
|
135
|
+
*/
|
|
136
|
+
export const mockInvocationStatusResponse = {
|
|
137
|
+
sys: {
|
|
138
|
+
id: 'test-invocation-id',
|
|
139
|
+
status: 'COMPLETED',
|
|
140
|
+
},
|
|
141
|
+
result: {
|
|
142
|
+
content: 'AI action completed successfully',
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Mock AI actions list response
|
|
147
|
+
*/
|
|
148
|
+
export const mockAiActionsResponse = {
|
|
149
|
+
total: 2,
|
|
150
|
+
skip: 0,
|
|
151
|
+
limit: 3,
|
|
152
|
+
items: [
|
|
153
|
+
mockAiAction,
|
|
154
|
+
{
|
|
155
|
+
...mockAiAction,
|
|
156
|
+
sys: { ...mockAiAction.sys, id: 'another-ai-action' },
|
|
157
|
+
name: 'Another AI Action',
|
|
158
|
+
description: 'Another test AI action',
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Mock variable values for AI action invocation
|
|
164
|
+
*/
|
|
165
|
+
export const mockVariables = [
|
|
166
|
+
{
|
|
167
|
+
id: 'sourceContent',
|
|
168
|
+
value: 'Hello, world!',
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
id: 'sourceLocale',
|
|
172
|
+
value: 'en-US',
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
id: 'targetLocale',
|
|
176
|
+
value: 'es-ES',
|
|
177
|
+
},
|
|
178
|
+
];
|
|
179
|
+
/**
|
|
180
|
+
* Mock fields for AI action invocation
|
|
181
|
+
*/
|
|
182
|
+
export const mockInvocationFields = [
|
|
183
|
+
{
|
|
184
|
+
outputFormat: OutputFormat.PLAIN_TEXT,
|
|
185
|
+
variables: mockVariables,
|
|
186
|
+
},
|
|
187
|
+
];
|
|
188
|
+
/**
|
|
189
|
+
* Mock complex AI action with all field types
|
|
190
|
+
*/
|
|
191
|
+
export const mockComplexAiAction = {
|
|
192
|
+
...mockAiAction,
|
|
193
|
+
name: 'Complex AI Action',
|
|
194
|
+
description: 'An AI action with complex variable types',
|
|
195
|
+
instruction: {
|
|
196
|
+
template: 'Process content from {{var.entryRef}} with context {{var.smartContext}} for {{var.mediaRef}}',
|
|
197
|
+
variables: [
|
|
198
|
+
{
|
|
199
|
+
id: 'entryRef',
|
|
200
|
+
name: 'Entry Reference',
|
|
201
|
+
type: VariableType.REFERENCE,
|
|
202
|
+
description: 'Reference to a content entry',
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
id: 'smartContext',
|
|
206
|
+
name: 'Smart Context',
|
|
207
|
+
type: VariableType.SMART_CONTEXT,
|
|
208
|
+
description: 'AI-powered context understanding',
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
id: 'mediaRef',
|
|
212
|
+
name: 'Media Reference',
|
|
213
|
+
type: VariableType.MEDIA_REFERENCE,
|
|
214
|
+
description: 'Reference to media assets',
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
},
|
|
218
|
+
configuration: {
|
|
219
|
+
modelType: 'gpt-3.5-turbo',
|
|
220
|
+
modelTemperature: 0.7,
|
|
221
|
+
},
|
|
222
|
+
testCases: [
|
|
223
|
+
{
|
|
224
|
+
name: 'Test case 1',
|
|
225
|
+
variables: {},
|
|
226
|
+
},
|
|
227
|
+
],
|
|
228
|
+
};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
import { createToolClient } from '../../utils/tools.js';
|
|
3
|
+
/**
|
|
4
|
+
* Shared mock objects for asset tests
|
|
5
|
+
* Provides standardized mock client and asset objects used across all asset tests
|
|
6
|
+
*/
|
|
7
|
+
// Create mock functions for the client
|
|
8
|
+
export const mockAssetGet = vi.fn();
|
|
9
|
+
export const mockAssetCreate = vi.fn();
|
|
10
|
+
export const mockAssetUpdate = vi.fn();
|
|
11
|
+
export const mockAssetDelete = vi.fn();
|
|
12
|
+
export const mockAssetPublish = vi.fn();
|
|
13
|
+
export const mockAssetUnpublish = vi.fn();
|
|
14
|
+
export const mockAssetGetMany = vi.fn();
|
|
15
|
+
export const mockAssetProcessForAllLocales = vi.fn();
|
|
16
|
+
// Mock bulk operations
|
|
17
|
+
export const mockBulkActionPublish = vi.fn();
|
|
18
|
+
export const mockBulkActionUnpublish = vi.fn();
|
|
19
|
+
export const mockBulkActionGet = vi.fn();
|
|
20
|
+
/**
|
|
21
|
+
* Standard mock Contentful client with all asset operations
|
|
22
|
+
*/
|
|
23
|
+
export const mockClient = {
|
|
24
|
+
asset: {
|
|
25
|
+
get: mockAssetGet,
|
|
26
|
+
create: mockAssetCreate,
|
|
27
|
+
update: mockAssetUpdate,
|
|
28
|
+
delete: mockAssetDelete,
|
|
29
|
+
publish: mockAssetPublish,
|
|
30
|
+
unpublish: mockAssetUnpublish,
|
|
31
|
+
getMany: mockAssetGetMany,
|
|
32
|
+
processForAllLocales: mockAssetProcessForAllLocales,
|
|
33
|
+
},
|
|
34
|
+
bulkAction: {
|
|
35
|
+
publish: mockBulkActionPublish,
|
|
36
|
+
unpublish: mockBulkActionUnpublish,
|
|
37
|
+
get: mockBulkActionGet,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Sets up the mock client for tests
|
|
42
|
+
* Call this in beforeEach to ensure the mock is properly configured
|
|
43
|
+
*/
|
|
44
|
+
export function setupMockClient() {
|
|
45
|
+
vi.mocked(createToolClient).mockReturnValue(mockClient);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Standard mock asset object used across tests
|
|
49
|
+
*/
|
|
50
|
+
export const mockAsset = {
|
|
51
|
+
sys: {
|
|
52
|
+
id: 'test-asset-id',
|
|
53
|
+
type: 'Asset',
|
|
54
|
+
version: 1,
|
|
55
|
+
space: {
|
|
56
|
+
sys: {
|
|
57
|
+
type: 'Link',
|
|
58
|
+
linkType: 'Space',
|
|
59
|
+
id: 'test-space-id',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
environment: {
|
|
63
|
+
sys: {
|
|
64
|
+
type: 'Link',
|
|
65
|
+
linkType: 'Environment',
|
|
66
|
+
id: 'test-environment',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
createdAt: '2023-01-01T00:00:00Z',
|
|
70
|
+
updatedAt: '2023-01-01T00:00:00Z',
|
|
71
|
+
publishedVersion: 1,
|
|
72
|
+
},
|
|
73
|
+
fields: {
|
|
74
|
+
title: {
|
|
75
|
+
'en-US': 'Test Asset',
|
|
76
|
+
},
|
|
77
|
+
description: {
|
|
78
|
+
'en-US': 'A test asset for unit tests',
|
|
79
|
+
},
|
|
80
|
+
file: {
|
|
81
|
+
'en-US': {
|
|
82
|
+
fileName: 'test-image.jpg',
|
|
83
|
+
contentType: 'image/jpeg',
|
|
84
|
+
url: 'https://images.ctfassets.net/test/test-image.jpg',
|
|
85
|
+
details: {
|
|
86
|
+
size: 12345,
|
|
87
|
+
image: {
|
|
88
|
+
width: 800,
|
|
89
|
+
height: 600,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Standard test arguments for asset operations
|
|
98
|
+
*/
|
|
99
|
+
export const mockArgs = {
|
|
100
|
+
spaceId: 'test-space-id',
|
|
101
|
+
environmentId: 'test-environment',
|
|
102
|
+
assetId: 'test-asset-id',
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Mock file object for upload tests
|
|
106
|
+
*/
|
|
107
|
+
export const mockFile = {
|
|
108
|
+
fileName: 'test-image.jpg',
|
|
109
|
+
contentType: 'image/jpeg',
|
|
110
|
+
upload: 'https://upload.example.com/test-upload-url',
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Mock assets list response
|
|
114
|
+
*/
|
|
115
|
+
export const mockAssetsResponse = {
|
|
116
|
+
total: 2,
|
|
117
|
+
skip: 0,
|
|
118
|
+
limit: 3,
|
|
119
|
+
items: [
|
|
120
|
+
mockAsset,
|
|
121
|
+
{
|
|
122
|
+
...mockAsset,
|
|
123
|
+
sys: { ...mockAsset.sys, id: 'another-asset-id' },
|
|
124
|
+
fields: {
|
|
125
|
+
...mockAsset.fields,
|
|
126
|
+
title: { 'en-US': 'Another Test Asset' },
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Mock bulk action response
|
|
133
|
+
*/
|
|
134
|
+
export const mockBulkAction = {
|
|
135
|
+
sys: {
|
|
136
|
+
id: 'bulk-action-id',
|
|
137
|
+
type: 'BulkAction',
|
|
138
|
+
status: 'succeeded',
|
|
139
|
+
createdAt: '2023-01-01T00:00:00Z',
|
|
140
|
+
updatedAt: '2023-01-01T00:00:00Z',
|
|
141
|
+
},
|
|
142
|
+
action: 'publish',
|
|
143
|
+
payload: {},
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Mock processed asset for upload
|
|
147
|
+
*/
|
|
148
|
+
export const mockProcessedAsset = {
|
|
149
|
+
...mockAsset,
|
|
150
|
+
fields: {
|
|
151
|
+
...mockAsset.fields,
|
|
152
|
+
file: {
|
|
153
|
+
'en-US': {
|
|
154
|
+
...mockAsset.fields.file['en-US'],
|
|
155
|
+
url: 'https://images.ctfassets.net/processed/test-image.jpg',
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
};
|
|
@@ -9,6 +9,10 @@ export const CreateContentTypeToolParams = BaseToolSchema.extend({
|
|
|
9
9
|
.string()
|
|
10
10
|
.optional()
|
|
11
11
|
.describe('Description of the content type'),
|
|
12
|
+
contentTypeId: z
|
|
13
|
+
.string()
|
|
14
|
+
.optional()
|
|
15
|
+
.describe('Optional ID for the content type. If provided, will use createWithId method'),
|
|
12
16
|
fields: z
|
|
13
17
|
.array(FieldSchema)
|
|
14
18
|
.describe('Array of field definitions for the content type'),
|
|
@@ -19,13 +23,16 @@ async function tool(args) {
|
|
|
19
23
|
environmentId: args.environmentId,
|
|
20
24
|
};
|
|
21
25
|
const contentfulClient = createToolClient(args);
|
|
22
|
-
|
|
23
|
-
const contentType = await contentfulClient.contentType.create(params, {
|
|
26
|
+
const contentTypeData = {
|
|
24
27
|
name: args.name,
|
|
25
28
|
displayField: args.displayField,
|
|
26
29
|
description: args.description,
|
|
27
30
|
fields: args.fields,
|
|
28
|
-
}
|
|
31
|
+
};
|
|
32
|
+
// Create the content type with or without ID
|
|
33
|
+
const contentType = args.contentTypeId
|
|
34
|
+
? await contentfulClient.contentType.createWithId({ ...params, contentTypeId: args.contentTypeId }, contentTypeData)
|
|
35
|
+
: await contentfulClient.contentType.create(params, contentTypeData);
|
|
29
36
|
return createSuccessResponse('Content type created successfully', {
|
|
30
37
|
contentType,
|
|
31
38
|
});
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
/**
|
|
3
|
+
* Shared mock objects for content type tests
|
|
4
|
+
* Provides standardized mock client and content type objects used across all content type tests
|
|
5
|
+
*/
|
|
6
|
+
const { mockContentTypeGet, mockContentTypeCreate, mockContentTypeCreateWithId, mockContentTypeUpdate, mockContentTypeDelete, mockContentTypePublish, mockContentTypeUnpublish, mockContentTypeGetMany, mockCreateToolClient, } = vi.hoisted(() => {
|
|
7
|
+
return {
|
|
8
|
+
mockContentTypeGet: vi.fn(),
|
|
9
|
+
mockContentTypeCreate: vi.fn(),
|
|
10
|
+
mockContentTypeCreateWithId: vi.fn(),
|
|
11
|
+
mockContentTypeUpdate: vi.fn(),
|
|
12
|
+
mockContentTypeDelete: vi.fn(),
|
|
13
|
+
mockContentTypePublish: vi.fn(),
|
|
14
|
+
mockContentTypeUnpublish: vi.fn(),
|
|
15
|
+
mockContentTypeGetMany: vi.fn(),
|
|
16
|
+
mockCreateToolClient: vi.fn(() => {
|
|
17
|
+
return {
|
|
18
|
+
contentType: {
|
|
19
|
+
get: mockContentTypeGet,
|
|
20
|
+
create: mockContentTypeCreate,
|
|
21
|
+
createWithId: mockContentTypeCreateWithId,
|
|
22
|
+
update: mockContentTypeUpdate,
|
|
23
|
+
delete: mockContentTypeDelete,
|
|
24
|
+
publish: mockContentTypePublish,
|
|
25
|
+
unpublish: mockContentTypeUnpublish,
|
|
26
|
+
getMany: mockContentTypeGetMany,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
vi.mock('../../utils/tools.js', async (importOriginal) => {
|
|
33
|
+
const org = await importOriginal();
|
|
34
|
+
return {
|
|
35
|
+
...org,
|
|
36
|
+
createToolClient: mockCreateToolClient,
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
export { mockContentTypeGet, mockContentTypeCreate, mockContentTypeCreateWithId, mockContentTypeUpdate, mockContentTypeDelete, mockContentTypePublish, mockContentTypeUnpublish, mockContentTypeGetMany, mockCreateToolClient, };
|
|
40
|
+
/**
|
|
41
|
+
* Standard mock content type object used across tests
|
|
42
|
+
*/
|
|
43
|
+
export const mockContentType = {
|
|
44
|
+
sys: {
|
|
45
|
+
id: 'test-content-type-id',
|
|
46
|
+
type: 'ContentType',
|
|
47
|
+
version: 1,
|
|
48
|
+
space: {
|
|
49
|
+
sys: {
|
|
50
|
+
type: 'Link',
|
|
51
|
+
linkType: 'Space',
|
|
52
|
+
id: 'test-space-id',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
environment: {
|
|
56
|
+
sys: {
|
|
57
|
+
type: 'Link',
|
|
58
|
+
linkType: 'Environment',
|
|
59
|
+
id: 'test-environment',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
createdAt: '2023-01-01T00:00:00Z',
|
|
63
|
+
updatedAt: '2023-01-01T00:00:00Z',
|
|
64
|
+
},
|
|
65
|
+
name: 'Test Content Type',
|
|
66
|
+
description: 'A test content type for unit tests',
|
|
67
|
+
displayField: 'title',
|
|
68
|
+
fields: [
|
|
69
|
+
{
|
|
70
|
+
id: 'title',
|
|
71
|
+
name: 'Title',
|
|
72
|
+
type: 'Symbol',
|
|
73
|
+
required: true,
|
|
74
|
+
localized: false,
|
|
75
|
+
validations: [],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: 'description',
|
|
79
|
+
name: 'Description',
|
|
80
|
+
type: 'Text',
|
|
81
|
+
required: false,
|
|
82
|
+
localized: false,
|
|
83
|
+
validations: [],
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Standard test arguments for content type operations
|
|
89
|
+
*/
|
|
90
|
+
export const mockArgs = {
|
|
91
|
+
spaceId: 'test-space-id',
|
|
92
|
+
environmentId: 'test-environment',
|
|
93
|
+
contentTypeId: 'test-content-type-id',
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Mock field definitions for testing
|
|
97
|
+
*/
|
|
98
|
+
export const mockField = {
|
|
99
|
+
id: 'title',
|
|
100
|
+
name: 'Title',
|
|
101
|
+
type: 'Symbol',
|
|
102
|
+
required: true,
|
|
103
|
+
localized: false,
|
|
104
|
+
validations: [],
|
|
105
|
+
};
|
|
106
|
+
export const mockTextField = {
|
|
107
|
+
id: 'description',
|
|
108
|
+
name: 'Description',
|
|
109
|
+
type: 'Text',
|
|
110
|
+
required: false,
|
|
111
|
+
localized: false,
|
|
112
|
+
validations: [],
|
|
113
|
+
};
|
|
114
|
+
export const mockLinkField = {
|
|
115
|
+
id: 'relatedEntry',
|
|
116
|
+
name: 'Related Entry',
|
|
117
|
+
type: 'Link',
|
|
118
|
+
linkType: 'Entry',
|
|
119
|
+
required: false,
|
|
120
|
+
localized: false,
|
|
121
|
+
validations: [],
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Mock content types list response
|
|
125
|
+
*/
|
|
126
|
+
export const mockContentTypesResponse = {
|
|
127
|
+
total: 2,
|
|
128
|
+
skip: 0,
|
|
129
|
+
limit: 10,
|
|
130
|
+
items: [
|
|
131
|
+
mockContentType,
|
|
132
|
+
{
|
|
133
|
+
...mockContentType,
|
|
134
|
+
sys: { ...mockContentType.sys, id: 'another-content-type' },
|
|
135
|
+
name: 'Another Content Type',
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
const { mockLocaleCreate, mockLocaleGet, mockLocaleDelete, mockLocaleGetMany, mockLocaleUpdate, mockCreateToolClient, } = vi.hoisted(() => {
|
|
3
|
+
return {
|
|
4
|
+
mockLocaleCreate: vi.fn(),
|
|
5
|
+
mockLocaleGet: vi.fn(),
|
|
6
|
+
mockLocaleDelete: vi.fn(),
|
|
7
|
+
mockLocaleGetMany: vi.fn(),
|
|
8
|
+
mockLocaleUpdate: vi.fn(),
|
|
9
|
+
mockCreateToolClient: vi.fn(() => {
|
|
10
|
+
return {
|
|
11
|
+
locale: {
|
|
12
|
+
create: mockLocaleCreate,
|
|
13
|
+
get: mockLocaleGet,
|
|
14
|
+
delete: mockLocaleDelete,
|
|
15
|
+
getMany: mockLocaleGetMany,
|
|
16
|
+
update: mockLocaleUpdate,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}),
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
vi.mock('../../utils/tools.js', async (importOriginal) => {
|
|
23
|
+
const org = await importOriginal();
|
|
24
|
+
return {
|
|
25
|
+
...org,
|
|
26
|
+
createToolClient: mockCreateToolClient,
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
export { mockLocaleCreate, mockLocaleGet, mockLocaleDelete, mockLocaleGetMany, mockLocaleUpdate, mockCreateToolClient, };
|
|
30
|
+
export const testLocale = {
|
|
31
|
+
name: 'Test Locale',
|
|
32
|
+
code: 'en-US',
|
|
33
|
+
fallbackCode: null,
|
|
34
|
+
contentDeliveryApi: true,
|
|
35
|
+
contentManagementApi: true,
|
|
36
|
+
default: true,
|
|
37
|
+
optional: false,
|
|
38
|
+
sys: {
|
|
39
|
+
id: 'test-locale-id',
|
|
40
|
+
type: 'Locale',
|
|
41
|
+
space: { sys: { type: 'Link', linkType: 'Space', id: 'test-space-id' } },
|
|
42
|
+
environment: {
|
|
43
|
+
sys: { type: 'Link', linkType: 'Environment', id: 'test-environment-id' },
|
|
44
|
+
},
|
|
45
|
+
createdAt: '2025-08-25T10:00:00Z',
|
|
46
|
+
updatedAt: '2025-08-25T10:00:00Z',
|
|
47
|
+
version: 1,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
export const mockArgs = {
|
|
51
|
+
spaceId: 'test-space-id',
|
|
52
|
+
environmentId: 'test-environment-id',
|
|
53
|
+
cmaToken: 'test-cma-token',
|
|
54
|
+
};
|
package/build/tools/register.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { registerContextTools } from './context/register.js';
|
|
2
2
|
import { registerEntriesTools } from './entries/register.js';
|
|
3
|
-
import { registerContentTypesTools } from './types/register.js';
|
|
3
|
+
import { registerContentTypesTools } from './content-types/register.js';
|
|
4
4
|
import { registerEnvironmentTools } from './environments/register.js';
|
|
5
5
|
import { registerAssetTools } from './assets/register.js';
|
|
6
6
|
import { registerSpaceTools } from './spaces/register.js';
|
|
@@ -14,6 +14,7 @@ export const FieldSchema = z.object({
|
|
|
14
14
|
.describe('Whether the field is omitted from the API response'),
|
|
15
15
|
validations: z.array(z.any()).optional().describe('Field validations'),
|
|
16
16
|
settings: z.record(z.any()).optional().describe('Field-specific settings'),
|
|
17
|
+
defaultValue: z.any().optional().describe('Default value for the field'),
|
|
17
18
|
linkType: z
|
|
18
19
|
.string()
|
|
19
20
|
.optional()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/mcp-server",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/contentful/contentful-mcp-server"
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"npm": ">=10.0.0"
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
|
-
"
|
|
21
|
+
"clean": "rimraf build",
|
|
22
|
+
"build": "npm run clean && tsc",
|
|
22
23
|
"dev": "nodemon --ext ts --ignore build/ --watch src/ --exec 'npm run build && npm start'",
|
|
23
24
|
"format": "prettier --write .",
|
|
24
25
|
"lint": "eslint .",
|
|
@@ -58,6 +59,7 @@
|
|
|
58
59
|
"nx": "^21.3.5",
|
|
59
60
|
"prettier": "^3.6.2",
|
|
60
61
|
"pretty-quick": "^4.2.2",
|
|
62
|
+
"rimraf": "^6.0.1",
|
|
61
63
|
"ts-node": "^10.9.2",
|
|
62
64
|
"typescript": "^5.8.2",
|
|
63
65
|
"vitest": "^3.2.4"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|