@type-crafter/mcp 0.1.0 → 0.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/dist/index.js +162 -74
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -7,6 +7,27 @@ import { parse as parseYaml } from 'yaml';
|
|
|
7
7
|
import { exec } from 'child_process';
|
|
8
8
|
import { promisify } from 'util';
|
|
9
9
|
const execAsync = promisify(exec);
|
|
10
|
+
// Type guards
|
|
11
|
+
function isRecord(value) {
|
|
12
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
13
|
+
}
|
|
14
|
+
function isSpecInfo(value) {
|
|
15
|
+
return (isRecord(value) &&
|
|
16
|
+
typeof value.version === 'string' &&
|
|
17
|
+
typeof value.title === 'string');
|
|
18
|
+
}
|
|
19
|
+
function isExecError(error) {
|
|
20
|
+
return error instanceof Error;
|
|
21
|
+
}
|
|
22
|
+
function isGenerateTypesArgs(value) {
|
|
23
|
+
return (isRecord(value) &&
|
|
24
|
+
typeof value.language === 'string' &&
|
|
25
|
+
typeof value.specFilePath === 'string' &&
|
|
26
|
+
typeof value.outputDirectory === 'string');
|
|
27
|
+
}
|
|
28
|
+
function isSpecFilePathArgs(value) {
|
|
29
|
+
return isRecord(value) && typeof value.specFilePath === 'string';
|
|
30
|
+
}
|
|
10
31
|
// Helper function to read YAML files
|
|
11
32
|
async function readYaml(filePath) {
|
|
12
33
|
const fileContent = await fs.readFile(filePath, 'utf-8');
|
|
@@ -14,29 +35,27 @@ async function readYaml(filePath) {
|
|
|
14
35
|
}
|
|
15
36
|
// Helper function to validate spec structure
|
|
16
37
|
function validateSpecData(data) {
|
|
17
|
-
if (
|
|
38
|
+
if (!isRecord(data)) {
|
|
18
39
|
return { valid: false };
|
|
19
40
|
}
|
|
20
|
-
const spec = data;
|
|
21
41
|
// Check for required info
|
|
22
|
-
if (
|
|
42
|
+
if (!isRecord(data.info)) {
|
|
23
43
|
return { valid: false };
|
|
24
44
|
}
|
|
25
|
-
|
|
26
|
-
if (typeof info.version !== 'string' || typeof info.title !== 'string') {
|
|
45
|
+
if (!isSpecInfo(data.info)) {
|
|
27
46
|
return { valid: false };
|
|
28
47
|
}
|
|
29
48
|
// At least one of types or groupedTypes must exist
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
if (
|
|
49
|
+
const types = isRecord(data.types) ? data.types : undefined;
|
|
50
|
+
const groupedTypes = isRecord(data.groupedTypes) ? data.groupedTypes : undefined;
|
|
51
|
+
if (typeof types === 'undefined' && typeof groupedTypes === 'undefined') {
|
|
33
52
|
return { valid: false };
|
|
34
53
|
}
|
|
35
54
|
return {
|
|
36
55
|
valid: true,
|
|
37
|
-
info:
|
|
38
|
-
types
|
|
39
|
-
groupedTypes
|
|
56
|
+
info: data.info,
|
|
57
|
+
types,
|
|
58
|
+
groupedTypes,
|
|
40
59
|
};
|
|
41
60
|
}
|
|
42
61
|
// Create server instance
|
|
@@ -48,40 +67,87 @@ const server = new McpServer({
|
|
|
48
67
|
tools: {},
|
|
49
68
|
},
|
|
50
69
|
});
|
|
70
|
+
// Schema definitions for all tools
|
|
71
|
+
const generateTypesSchema = {
|
|
72
|
+
type: 'object',
|
|
73
|
+
properties: {
|
|
74
|
+
language: {
|
|
75
|
+
type: 'string',
|
|
76
|
+
description: 'Target language for type generation',
|
|
77
|
+
enum: ['typescript', 'typescript-with-decoders'],
|
|
78
|
+
},
|
|
79
|
+
specFilePath: {
|
|
80
|
+
type: 'string',
|
|
81
|
+
description: 'Path to the YAML specification file',
|
|
82
|
+
},
|
|
83
|
+
outputDirectory: {
|
|
84
|
+
type: 'string',
|
|
85
|
+
description: 'Directory where generated types will be written',
|
|
86
|
+
},
|
|
87
|
+
typesWriterMode: {
|
|
88
|
+
type: 'string',
|
|
89
|
+
description: 'Writer mode for types: SingleFile or Files',
|
|
90
|
+
enum: ['SingleFile', 'Files'],
|
|
91
|
+
},
|
|
92
|
+
groupedTypesWriterMode: {
|
|
93
|
+
type: 'string',
|
|
94
|
+
description: 'Writer mode for grouped types: FolderWithFiles or SingleFile',
|
|
95
|
+
enum: ['FolderWithFiles', 'SingleFile'],
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
required: ['language', 'specFilePath', 'outputDirectory'],
|
|
99
|
+
additionalProperties: false,
|
|
100
|
+
};
|
|
101
|
+
const validateSpecSchema = {
|
|
102
|
+
type: 'object',
|
|
103
|
+
properties: {
|
|
104
|
+
specFilePath: {
|
|
105
|
+
type: 'string',
|
|
106
|
+
description: 'Path to the YAML specification file to validate',
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
required: ['specFilePath'],
|
|
110
|
+
additionalProperties: false,
|
|
111
|
+
};
|
|
112
|
+
const listLanguagesSchema = {
|
|
113
|
+
type: 'object',
|
|
114
|
+
properties: {},
|
|
115
|
+
additionalProperties: false,
|
|
116
|
+
};
|
|
117
|
+
const getSpecInfoSchema = {
|
|
118
|
+
type: 'object',
|
|
119
|
+
properties: {
|
|
120
|
+
specFilePath: {
|
|
121
|
+
type: 'string',
|
|
122
|
+
description: 'Path to the YAML specification file',
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
required: ['specFilePath'],
|
|
126
|
+
additionalProperties: false,
|
|
127
|
+
};
|
|
128
|
+
const getSpecRulesSchema = {
|
|
129
|
+
type: 'object',
|
|
130
|
+
properties: {},
|
|
131
|
+
additionalProperties: false,
|
|
132
|
+
};
|
|
51
133
|
// Register generate-types tool
|
|
52
134
|
server.registerTool('generate-types', {
|
|
53
135
|
description: 'Generate type definitions from a YAML specification file. Supports TypeScript and TypeScript with decoders. ' +
|
|
54
136
|
'The YAML spec should follow the Type Crafter format with info, types, and/or groupedTypes sections.',
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
properties: {
|
|
58
|
-
language: {
|
|
59
|
-
type: 'string',
|
|
60
|
-
description: 'Target language for type generation',
|
|
61
|
-
enum: ['typescript', 'typescript-with-decoders'],
|
|
62
|
-
},
|
|
63
|
-
specFilePath: {
|
|
64
|
-
type: 'string',
|
|
65
|
-
description: 'Path to the YAML specification file',
|
|
66
|
-
},
|
|
67
|
-
outputDirectory: {
|
|
68
|
-
type: 'string',
|
|
69
|
-
description: 'Directory where generated types will be written',
|
|
70
|
-
},
|
|
71
|
-
typesWriterMode: {
|
|
72
|
-
type: 'string',
|
|
73
|
-
description: 'Writer mode for types: SingleFile or Files',
|
|
74
|
-
enum: ['SingleFile', 'Files'],
|
|
75
|
-
},
|
|
76
|
-
groupedTypesWriterMode: {
|
|
77
|
-
type: 'string',
|
|
78
|
-
description: 'Writer mode for grouped types: FolderWithFiles or SingleFile',
|
|
79
|
-
enum: ['FolderWithFiles', 'SingleFile'],
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
required: ['language', 'specFilePath', 'outputDirectory'],
|
|
83
|
-
},
|
|
137
|
+
// @ts-expect-error - MCP SDK schema type mismatch
|
|
138
|
+
inputSchema: generateTypesSchema,
|
|
84
139
|
}, async (args) => {
|
|
140
|
+
if (!isGenerateTypesArgs(args)) {
|
|
141
|
+
return {
|
|
142
|
+
content: [
|
|
143
|
+
{
|
|
144
|
+
type: 'text',
|
|
145
|
+
text: 'Error: Invalid arguments provided',
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
isError: true,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
85
151
|
const { language, specFilePath, outputDirectory, typesWriterMode = 'SingleFile', groupedTypesWriterMode = 'SingleFile', } = args;
|
|
86
152
|
// Validate language
|
|
87
153
|
if (!['typescript', 'typescript-with-decoders'].includes(language.toLowerCase())) {
|
|
@@ -128,13 +194,23 @@ server.registerTool('generate-types', {
|
|
|
128
194
|
};
|
|
129
195
|
}
|
|
130
196
|
catch (error) {
|
|
131
|
-
|
|
132
|
-
|
|
197
|
+
if (!isExecError(error)) {
|
|
198
|
+
return {
|
|
199
|
+
content: [
|
|
200
|
+
{
|
|
201
|
+
type: 'text',
|
|
202
|
+
text: 'Error: Unknown error occurred during type generation',
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
isError: true,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const errorDetails = error.stderr ?? error.stdout ?? '';
|
|
133
209
|
return {
|
|
134
210
|
content: [
|
|
135
211
|
{
|
|
136
212
|
type: 'text',
|
|
137
|
-
text: `Error generating types: ${
|
|
213
|
+
text: `Error generating types: ${error.message}\n${errorDetails}`,
|
|
138
214
|
},
|
|
139
215
|
],
|
|
140
216
|
isError: true,
|
|
@@ -145,17 +221,20 @@ server.registerTool('generate-types', {
|
|
|
145
221
|
server.registerTool('validate-spec', {
|
|
146
222
|
description: 'Validate a YAML specification file without generating types. ' +
|
|
147
223
|
'Checks if the spec file is valid and can be processed by Type Crafter.',
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
properties: {
|
|
151
|
-
specFilePath: {
|
|
152
|
-
type: 'string',
|
|
153
|
-
description: 'Path to the YAML specification file to validate',
|
|
154
|
-
},
|
|
155
|
-
},
|
|
156
|
-
required: ['specFilePath'],
|
|
157
|
-
},
|
|
224
|
+
// @ts-expect-error - MCP SDK schema type mismatch
|
|
225
|
+
inputSchema: validateSpecSchema,
|
|
158
226
|
}, async (args) => {
|
|
227
|
+
if (!isSpecFilePathArgs(args)) {
|
|
228
|
+
return {
|
|
229
|
+
content: [
|
|
230
|
+
{
|
|
231
|
+
type: 'text',
|
|
232
|
+
text: 'Error: Invalid arguments provided',
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
isError: true,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
159
238
|
const { specFilePath } = args;
|
|
160
239
|
// Resolve path
|
|
161
240
|
const resolvedSpecPath = path.resolve(specFilePath);
|
|
@@ -204,10 +283,8 @@ server.registerTool('validate-spec', {
|
|
|
204
283
|
// Register list-languages tool
|
|
205
284
|
server.registerTool('list-languages', {
|
|
206
285
|
description: 'List all supported target languages for type generation',
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
properties: {},
|
|
210
|
-
},
|
|
286
|
+
// @ts-expect-error - MCP SDK schema type mismatch
|
|
287
|
+
inputSchema: listLanguagesSchema,
|
|
211
288
|
}, async () => {
|
|
212
289
|
return {
|
|
213
290
|
content: [
|
|
@@ -222,17 +299,20 @@ server.registerTool('list-languages', {
|
|
|
222
299
|
server.registerTool('get-spec-info', {
|
|
223
300
|
description: 'Get information about a YAML specification file including version, title, ' +
|
|
224
301
|
'and counts of types and grouped types defined in the spec.',
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
properties: {
|
|
228
|
-
specFilePath: {
|
|
229
|
-
type: 'string',
|
|
230
|
-
description: 'Path to the YAML specification file',
|
|
231
|
-
},
|
|
232
|
-
},
|
|
233
|
-
required: ['specFilePath'],
|
|
234
|
-
},
|
|
302
|
+
// @ts-expect-error - MCP SDK schema type mismatch
|
|
303
|
+
inputSchema: getSpecInfoSchema,
|
|
235
304
|
}, async (args) => {
|
|
305
|
+
if (!isSpecFilePathArgs(args)) {
|
|
306
|
+
return {
|
|
307
|
+
content: [
|
|
308
|
+
{
|
|
309
|
+
type: 'text',
|
|
310
|
+
text: 'Error: Invalid arguments provided',
|
|
311
|
+
},
|
|
312
|
+
],
|
|
313
|
+
isError: true,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
236
316
|
const { specFilePath } = args;
|
|
237
317
|
// Resolve path
|
|
238
318
|
const resolvedSpecPath = path.resolve(specFilePath);
|
|
@@ -285,7 +365,7 @@ server.registerTool('get-spec-info', {
|
|
|
285
365
|
infoText += 'Grouped Types:\n';
|
|
286
366
|
Object.keys(validation.groupedTypes).forEach((groupName) => {
|
|
287
367
|
const group = validation.groupedTypes?.[groupName];
|
|
288
|
-
if (
|
|
368
|
+
if (isRecord(group) && !('$ref' in group)) {
|
|
289
369
|
const typeNames = Object.keys(group);
|
|
290
370
|
infoText += ` ${groupName} (${typeNames.length} types):\n`;
|
|
291
371
|
typeNames.forEach((typeName) => {
|
|
@@ -311,10 +391,8 @@ server.registerTool('get-spec-rules', {
|
|
|
311
391
|
description: 'Get comprehensive rules and guidelines for writing Type Crafter YAML specification files. ' +
|
|
312
392
|
'This provides LLMs with detailed information about the YAML spec format, type mappings, nullable types, ' +
|
|
313
393
|
'references, composition, best practices, and common patterns. Use this before creating or modifying spec files.',
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
properties: {},
|
|
317
|
-
},
|
|
394
|
+
// @ts-expect-error - MCP SDK schema type mismatch
|
|
395
|
+
inputSchema: getSpecRulesSchema,
|
|
318
396
|
}, async () => {
|
|
319
397
|
try {
|
|
320
398
|
// Read the SPEC_RULES.md file from src directory
|
|
@@ -330,12 +408,22 @@ server.registerTool('get-spec-rules', {
|
|
|
330
408
|
};
|
|
331
409
|
}
|
|
332
410
|
catch (error) {
|
|
333
|
-
|
|
411
|
+
if (!isExecError(error)) {
|
|
412
|
+
return {
|
|
413
|
+
content: [
|
|
414
|
+
{
|
|
415
|
+
type: 'text',
|
|
416
|
+
text: 'Error: Unknown error occurred while reading spec rules',
|
|
417
|
+
},
|
|
418
|
+
],
|
|
419
|
+
isError: true,
|
|
420
|
+
};
|
|
421
|
+
}
|
|
334
422
|
return {
|
|
335
423
|
content: [
|
|
336
424
|
{
|
|
337
425
|
type: 'text',
|
|
338
|
-
text: `Error reading spec rules: ${
|
|
426
|
+
text: `Error reading spec rules: ${error.message}`,
|
|
339
427
|
},
|
|
340
428
|
],
|
|
341
429
|
isError: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@type-crafter/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "MCP server for Type Crafter - generate types from YAML specifications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
}
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
63
|
+
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
64
64
|
"yaml": "^2.3.2"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|