mcp-lint 0.1.0 → 0.3.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/README.md +222 -60
- package/dist/cli/commands/check.js +98 -52
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/compat.d.ts +2 -0
- package/dist/cli/commands/compat.js +138 -0
- package/dist/cli/commands/compat.js.map +1 -0
- package/dist/cli/commands/diff.d.ts +2 -0
- package/dist/cli/commands/diff.js +134 -0
- package/dist/cli/commands/diff.js.map +1 -0
- package/dist/cli/commands/explain.d.ts +2 -0
- package/dist/cli/commands/explain.js +50 -0
- package/dist/cli/commands/explain.js.map +1 -0
- package/dist/cli/commands/fix.js +3 -1
- package/dist/cli/commands/fix.js.map +1 -1
- package/dist/config/config.d.ts +1 -1
- package/dist/config/config.js +6 -3
- package/dist/config/config.js.map +1 -1
- package/dist/config/plugin-loader.d.ts +6 -0
- package/dist/config/plugin-loader.js +19 -0
- package/dist/config/plugin-loader.js.map +1 -0
- package/dist/config/presets.d.ts +2 -0
- package/dist/config/presets.js +58 -0
- package/dist/config/presets.js.map +1 -0
- package/dist/core/compat-matrix.d.ts +13 -0
- package/dist/core/compat-matrix.js +31 -0
- package/dist/core/compat-matrix.js.map +1 -0
- package/dist/core/quality-score.d.ts +15 -0
- package/dist/core/quality-score.js +30 -0
- package/dist/core/quality-score.js.map +1 -0
- package/dist/core/rule.d.ts +11 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/rules/client-specific/cline.d.ts +2 -0
- package/dist/rules/client-specific/cline.js +49 -0
- package/dist/rules/client-specific/cline.js.map +1 -0
- package/dist/rules/client-specific/continue.d.ts +2 -0
- package/dist/rules/client-specific/continue.js +30 -0
- package/dist/rules/client-specific/continue.js.map +1 -0
- package/dist/rules/client-specific/openai.d.ts +3 -0
- package/dist/rules/client-specific/openai.js +59 -0
- package/dist/rules/client-specific/openai.js.map +1 -0
- package/dist/rules/client-specific/windsurf.d.ts +2 -0
- package/dist/rules/client-specific/windsurf.js +39 -0
- package/dist/rules/client-specific/windsurf.js.map +1 -0
- package/dist/rules/index.js +9 -0
- package/dist/rules/index.js.map +1 -1
- package/package.json +44 -44
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
function gradeFromScore(score) {
|
|
2
|
+
if (score >= 90)
|
|
3
|
+
return 'A';
|
|
4
|
+
if (score >= 75)
|
|
5
|
+
return 'B';
|
|
6
|
+
if (score >= 60)
|
|
7
|
+
return 'C';
|
|
8
|
+
if (score >= 40)
|
|
9
|
+
return 'D';
|
|
10
|
+
return 'F';
|
|
11
|
+
}
|
|
12
|
+
export function computeQualityReport(tools, diagnostics) {
|
|
13
|
+
const byTool = new Map();
|
|
14
|
+
for (const tool of tools)
|
|
15
|
+
byTool.set(tool.name, []);
|
|
16
|
+
for (const d of diagnostics)
|
|
17
|
+
byTool.get(d.toolName)?.push(d);
|
|
18
|
+
const toolScores = tools.map((tool) => {
|
|
19
|
+
const diags = byTool.get(tool.name) ?? [];
|
|
20
|
+
const errors = diags.filter((d) => d.severity === 'error').length;
|
|
21
|
+
const warnings = diags.filter((d) => d.severity === 'warning').length;
|
|
22
|
+
const score = Math.max(0, 100 - errors * 15 - warnings * 5);
|
|
23
|
+
return { toolName: tool.name, score, grade: gradeFromScore(score), errors, warnings };
|
|
24
|
+
});
|
|
25
|
+
const overall = tools.length === 0
|
|
26
|
+
? 100
|
|
27
|
+
: Math.round(toolScores.reduce((sum, t) => sum + t.score, 0) / toolScores.length);
|
|
28
|
+
return { overall, grade: gradeFromScore(overall), tools: toolScores };
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=quality-score.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality-score.js","sourceRoot":"","sources":["../../src/core/quality-score.ts"],"names":[],"mappings":"AAiBA,SAAS,cAAc,CAAC,KAAa;IACnC,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAgB,EAAE,WAAyB;IAC9E,MAAM,MAAM,GAAG,IAAI,GAAG,EAAwB,CAAC;IAC/C,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACpD,KAAK,MAAM,CAAC,IAAI,WAAW;QAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAE7D,MAAM,UAAU,GAAgB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACjD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;QAClE,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;QACtE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,MAAM,GAAG,EAAE,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC;QAC5D,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IACxF,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,KAAK,CAAC;QAChC,CAAC,CAAC,GAAG;QACL,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAEpF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;AACxE,CAAC"}
|
package/dist/core/rule.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Severity } from './severity.js';
|
|
2
2
|
export type { Severity } from './severity.js';
|
|
3
3
|
import type { Diagnostic } from './diagnostic.js';
|
|
4
|
-
export type ClientId = 'claude' | 'cursor' | 'gemini' | 'vscode';
|
|
4
|
+
export type ClientId = 'claude' | 'cursor' | 'gemini' | 'vscode' | 'windsurf' | 'cline' | 'openai' | 'continue';
|
|
5
5
|
export interface JSONSchema {
|
|
6
6
|
type?: string | string[];
|
|
7
7
|
properties?: Record<string, JSONSchema>;
|
|
@@ -20,6 +20,7 @@ export interface JSONSchema {
|
|
|
20
20
|
not?: JSONSchema;
|
|
21
21
|
patternProperties?: Record<string, JSONSchema>;
|
|
22
22
|
additionalItems?: JSONSchema | boolean;
|
|
23
|
+
additionalProperties?: JSONSchema | boolean;
|
|
23
24
|
dependencies?: Record<string, JSONSchema | string[]>;
|
|
24
25
|
$dynamicRef?: string;
|
|
25
26
|
contentEncoding?: string;
|
|
@@ -34,6 +35,8 @@ export interface MCPTool {
|
|
|
34
35
|
inputSchema: JSONSchema;
|
|
35
36
|
}
|
|
36
37
|
export interface Config {
|
|
38
|
+
extends?: string;
|
|
39
|
+
plugins?: string[];
|
|
37
40
|
rules?: Record<string, Severity | 'off'>;
|
|
38
41
|
clients?: ClientId[];
|
|
39
42
|
ignore?: string[];
|
|
@@ -42,11 +45,18 @@ export interface Config {
|
|
|
42
45
|
export interface RuleContext {
|
|
43
46
|
config: Config;
|
|
44
47
|
}
|
|
48
|
+
export interface RuleDocs {
|
|
49
|
+
why: string;
|
|
50
|
+
badExample: object;
|
|
51
|
+
goodExample: object;
|
|
52
|
+
fixNote?: string;
|
|
53
|
+
}
|
|
45
54
|
export interface Rule {
|
|
46
55
|
id: string;
|
|
47
56
|
severity: Severity;
|
|
48
57
|
description: string;
|
|
49
58
|
url?: string;
|
|
50
59
|
clients: ClientId[];
|
|
60
|
+
docs?: RuleDocs;
|
|
51
61
|
check: (tool: MCPTool, context: RuleContext) => Diagnostic[];
|
|
52
62
|
}
|
package/dist/index.js
CHANGED
|
@@ -3,13 +3,19 @@ import { Command } from 'commander';
|
|
|
3
3
|
import { registerCheckCommand } from './cli/commands/check.js';
|
|
4
4
|
import { registerFixCommand } from './cli/commands/fix.js';
|
|
5
5
|
import { registerInitCommand } from './cli/commands/init.js';
|
|
6
|
+
import { registerCompatCommand } from './cli/commands/compat.js';
|
|
7
|
+
import { registerExplainCommand } from './cli/commands/explain.js';
|
|
8
|
+
import { registerDiffCommand } from './cli/commands/diff.js';
|
|
6
9
|
const program = new Command();
|
|
7
10
|
program
|
|
8
11
|
.name('mcp-lint')
|
|
9
12
|
.description('Lint MCP server tool schemas for cross-client compatibility')
|
|
10
|
-
.version('0.
|
|
13
|
+
.version('0.3.0');
|
|
11
14
|
registerCheckCommand(program);
|
|
12
15
|
registerFixCommand(program);
|
|
13
16
|
registerInitCommand(program);
|
|
17
|
+
registerCompatCommand(program);
|
|
18
|
+
registerExplainCommand(program);
|
|
19
|
+
registerDiffCommand(program);
|
|
14
20
|
program.parse();
|
|
15
21
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE7D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,6DAA6D,CAAC;KAC1E,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,kBAAkB,CAAC,OAAO,CAAC,CAAC;AAC5B,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAE7B,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE7D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,6DAA6D,CAAC;KAC1E,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,kBAAkB,CAAC,OAAO,CAAC,CAAC;AAC5B,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAE7B,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const MAX_LENGTH = 200;
|
|
2
|
+
export const clineDescriptionMaxLength = {
|
|
3
|
+
id: 'cline/description-max-length',
|
|
4
|
+
severity: 'warning',
|
|
5
|
+
description: `Cline truncates descriptions longer than ${MAX_LENGTH} characters.`,
|
|
6
|
+
clients: ['cline'],
|
|
7
|
+
docs: {
|
|
8
|
+
why: 'Cline\'s UI and prompt construction truncates tool and parameter descriptions at 200 characters. Longer descriptions are silently cut off, hiding important information.',
|
|
9
|
+
badExample: { description: 'A very long description that exceeds two hundred characters and will be truncated by Cline without any warning, potentially causing confusion for users who rely on the full text.' },
|
|
10
|
+
goodExample: { description: 'A concise description under 200 characters.' },
|
|
11
|
+
fixNote: 'Trim description to 200 characters.',
|
|
12
|
+
},
|
|
13
|
+
check(tool, _context) {
|
|
14
|
+
const diagnostics = [];
|
|
15
|
+
if (tool.description && tool.description.length > MAX_LENGTH) {
|
|
16
|
+
diagnostics.push({
|
|
17
|
+
ruleId: 'cline/description-max-length',
|
|
18
|
+
severity: 'warning',
|
|
19
|
+
message: `Tool "${tool.name}" description is ${tool.description.length} characters. Cline truncates at ${MAX_LENGTH}.`,
|
|
20
|
+
toolName: tool.name,
|
|
21
|
+
path: 'description',
|
|
22
|
+
clients: ['cline'],
|
|
23
|
+
fix: {
|
|
24
|
+
description: `Trim description to ${MAX_LENGTH} characters`,
|
|
25
|
+
apply: (s) => ({ ...s, description: s.description.slice(0, MAX_LENGTH) }),
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
const props = tool.inputSchema.properties ?? {};
|
|
30
|
+
for (const [propName, propSchema] of Object.entries(props)) {
|
|
31
|
+
if (typeof propSchema.description === 'string' && propSchema.description.length > MAX_LENGTH) {
|
|
32
|
+
diagnostics.push({
|
|
33
|
+
ruleId: 'cline/description-max-length',
|
|
34
|
+
severity: 'warning',
|
|
35
|
+
message: `Parameter "${propName}" description is ${propSchema.description.length} characters. Cline truncates at ${MAX_LENGTH}.`,
|
|
36
|
+
toolName: tool.name,
|
|
37
|
+
path: `inputSchema.properties.${propName}`,
|
|
38
|
+
clients: ['cline'],
|
|
39
|
+
fix: {
|
|
40
|
+
description: `Trim description to ${MAX_LENGTH} characters`,
|
|
41
|
+
apply: (s) => ({ ...s, description: s.description.slice(0, MAX_LENGTH) }),
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return diagnostics;
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=cline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cline.js","sourceRoot":"","sources":["../../../src/rules/client-specific/cline.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,GAAG,GAAG,CAAC;AAEvB,MAAM,CAAC,MAAM,yBAAyB,GAAS;IAC7C,EAAE,EAAE,8BAA8B;IAClC,QAAQ,EAAE,SAAS;IACnB,WAAW,EAAE,4CAA4C,UAAU,cAAc;IACjF,OAAO,EAAE,CAAC,OAAO,CAAC;IAClB,IAAI,EAAE;QACJ,GAAG,EAAE,0KAA0K;QAC/K,UAAU,EAAE,EAAE,WAAW,EAAE,oLAAoL,EAAE;QACjN,WAAW,EAAE,EAAE,WAAW,EAAE,6CAA6C,EAAE;QAC3E,OAAO,EAAE,qCAAqC;KAC/C;IAED,KAAK,CAAC,IAAa,EAAE,QAAqB;QACxC,MAAM,WAAW,GAAiB,EAAE,CAAC;QAErC,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;YAC7D,WAAW,CAAC,IAAI,CAAC;gBACf,MAAM,EAAE,8BAA8B;gBACtC,QAAQ,EAAE,SAAS;gBACnB,OAAO,EAAE,SAAS,IAAI,CAAC,IAAI,oBAAoB,IAAI,CAAC,WAAW,CAAC,MAAM,mCAAmC,UAAU,GAAG;gBACtH,QAAQ,EAAE,IAAI,CAAC,IAAI;gBACnB,IAAI,EAAE,aAAa;gBACnB,OAAO,EAAE,CAAC,OAAO,CAAC;gBAClB,GAAG,EAAE;oBACH,WAAW,EAAE,uBAAuB,UAAU,aAAa;oBAC3D,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,WAAW,EAAG,CAAC,CAAC,WAAsB,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,CAAC;iBACtF;aACF,CAAC,CAAC;QACL,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,IAAI,EAAE,CAAC;QAChD,KAAK,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,IAAI,OAAO,UAAU,CAAC,WAAW,KAAK,QAAQ,IAAI,UAAU,CAAC,WAAW,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;gBAC7F,WAAW,CAAC,IAAI,CAAC;oBACf,MAAM,EAAE,8BAA8B;oBACtC,QAAQ,EAAE,SAAS;oBACnB,OAAO,EAAE,cAAc,QAAQ,oBAAoB,UAAU,CAAC,WAAW,CAAC,MAAM,mCAAmC,UAAU,GAAG;oBAChI,QAAQ,EAAE,IAAI,CAAC,IAAI;oBACnB,IAAI,EAAE,0BAA0B,QAAQ,EAAE;oBAC1C,OAAO,EAAE,CAAC,OAAO,CAAC;oBAClB,GAAG,EAAE;wBACH,WAAW,EAAE,uBAAuB,UAAU,aAAa;wBAC3D,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,WAAW,EAAG,CAAC,CAAC,WAAsB,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,CAAC;qBACtF;iBACF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const continueNoDefaultValues = {
|
|
2
|
+
id: 'continue/no-default-values',
|
|
3
|
+
severity: 'warning',
|
|
4
|
+
description: 'Continue.dev ignores `default` fields — users may assume defaults are applied when they are not.',
|
|
5
|
+
clients: ['continue'],
|
|
6
|
+
docs: {
|
|
7
|
+
why: 'Continue.dev\'s MCP client does not apply `default` values from schemas. If a user omits an optional parameter, they won\'t get the default — they\'ll get an error or undefined behavior.',
|
|
8
|
+
badExample: { properties: { limit: { type: 'number', default: 10 } } },
|
|
9
|
+
goodExample: { properties: { limit: { type: 'number', description: 'Number of results (optional, defaults to 10 if omitted)' } } },
|
|
10
|
+
fixNote: 'Document the default value in the description instead of relying on the `default` field.',
|
|
11
|
+
},
|
|
12
|
+
check(tool, _context) {
|
|
13
|
+
const diagnostics = [];
|
|
14
|
+
const props = tool.inputSchema.properties ?? {};
|
|
15
|
+
for (const [propName, propSchema] of Object.entries(props)) {
|
|
16
|
+
if (propSchema.default !== undefined) {
|
|
17
|
+
diagnostics.push({
|
|
18
|
+
ruleId: 'continue/no-default-values',
|
|
19
|
+
severity: 'warning',
|
|
20
|
+
message: `Parameter "${propName}" in tool "${tool.name}" has a \`default\` value that Continue.dev will ignore. Document the default in the description instead.`,
|
|
21
|
+
toolName: tool.name,
|
|
22
|
+
path: `inputSchema.properties.${propName}`,
|
|
23
|
+
clients: ['continue'],
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return diagnostics;
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=continue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"continue.js","sourceRoot":"","sources":["../../../src/rules/client-specific/continue.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,MAAM,uBAAuB,GAAS;IAC3C,EAAE,EAAE,4BAA4B;IAChC,QAAQ,EAAE,SAAS;IACnB,WAAW,EAAE,kGAAkG;IAC/G,OAAO,EAAE,CAAC,UAAU,CAAC;IACrB,IAAI,EAAE;QACJ,GAAG,EAAE,4LAA4L;QACjM,UAAU,EAAE,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE;QACtE,WAAW,EAAE,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,yDAAyD,EAAE,EAAE,EAAE;QAClI,OAAO,EAAE,0FAA0F;KACpG;IAED,KAAK,CAAC,IAAa,EAAE,QAAqB;QACxC,MAAM,WAAW,GAAiB,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,IAAI,EAAE,CAAC;QAEhD,KAAK,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,IAAI,UAAU,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBACrC,WAAW,CAAC,IAAI,CAAC;oBACf,MAAM,EAAE,4BAA4B;oBACpC,QAAQ,EAAE,SAAS;oBACnB,OAAO,EAAE,cAAc,QAAQ,cAAc,IAAI,CAAC,IAAI,2GAA2G;oBACjK,QAAQ,EAAE,IAAI,CAAC,IAAI;oBACnB,IAAI,EAAE,0BAA0B,QAAQ,EAAE;oBAC1C,OAAO,EAAE,CAAC,UAAU,CAAC;iBACtB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { walkSchema } from '../../utils/schema-walker.js';
|
|
2
|
+
const ALLOWED_TYPES = new Set(['string', 'number', 'boolean', 'object', 'array', 'null']);
|
|
3
|
+
export const openaiNoAdditionalProperties = {
|
|
4
|
+
id: 'openai/no-additional-properties',
|
|
5
|
+
severity: 'error',
|
|
6
|
+
description: 'OpenAI Agents SDK strict mode requires `additionalProperties: false` on the root inputSchema.',
|
|
7
|
+
clients: ['openai'],
|
|
8
|
+
docs: {
|
|
9
|
+
why: 'OpenAI\'s strict function calling mode rejects schemas that don\'t explicitly set `additionalProperties: false` at the root level.',
|
|
10
|
+
badExample: { type: 'object', properties: { q: { type: 'string' } } },
|
|
11
|
+
goodExample: { type: 'object', properties: { q: { type: 'string' } }, additionalProperties: false },
|
|
12
|
+
fixNote: 'Add `"additionalProperties": false` to the root inputSchema.',
|
|
13
|
+
},
|
|
14
|
+
check(tool, _context) {
|
|
15
|
+
if (tool.inputSchema.additionalProperties === false)
|
|
16
|
+
return [];
|
|
17
|
+
return [{
|
|
18
|
+
ruleId: 'openai/no-additional-properties',
|
|
19
|
+
severity: 'error',
|
|
20
|
+
message: `Tool "${tool.name}" is missing \`additionalProperties: false\` on inputSchema. Required for OpenAI Agents SDK strict mode.`,
|
|
21
|
+
toolName: tool.name,
|
|
22
|
+
path: 'inputSchema',
|
|
23
|
+
clients: ['openai'],
|
|
24
|
+
fix: {
|
|
25
|
+
description: 'Add `additionalProperties: false` to inputSchema',
|
|
26
|
+
apply: (s) => ({ ...s, additionalProperties: false }),
|
|
27
|
+
},
|
|
28
|
+
}];
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
export const openaiStrictTypes = {
|
|
32
|
+
id: 'openai/strict-types',
|
|
33
|
+
severity: 'error',
|
|
34
|
+
description: 'OpenAI Agents SDK only allows string, number, boolean, object, array, null types.',
|
|
35
|
+
clients: ['openai'],
|
|
36
|
+
docs: {
|
|
37
|
+
why: 'OpenAI\'s function calling schema validation rejects non-standard types like `integer`. Use `number` instead.',
|
|
38
|
+
badExample: { properties: { count: { type: 'integer' } } },
|
|
39
|
+
goodExample: { properties: { count: { type: 'number' } } },
|
|
40
|
+
},
|
|
41
|
+
check(tool, _context) {
|
|
42
|
+
const diagnostics = [];
|
|
43
|
+
walkSchema(tool.inputSchema, (schema, path) => {
|
|
44
|
+
if (typeof schema.type === 'string' && !ALLOWED_TYPES.has(schema.type)) {
|
|
45
|
+
const diagnosticPath = path ? `inputSchema.${path}` : 'inputSchema';
|
|
46
|
+
diagnostics.push({
|
|
47
|
+
ruleId: 'openai/strict-types',
|
|
48
|
+
severity: 'error',
|
|
49
|
+
message: `Schema at "${diagnosticPath}" uses type "${schema.type}" which is not allowed by OpenAI Agents SDK. Use one of: ${[...ALLOWED_TYPES].join(', ')}.`,
|
|
50
|
+
toolName: tool.name,
|
|
51
|
+
path: diagnosticPath,
|
|
52
|
+
clients: ['openai'],
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
return diagnostics;
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=openai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/rules/client-specific/openai.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { walkSchema } from '../../utils/schema-walker.js';
|
|
2
|
+
export const windsurfNoUnionTypes = {
|
|
3
|
+
id: 'windsurf/no-union-types',
|
|
4
|
+
severity: 'warning',
|
|
5
|
+
description: 'Windsurf does not support `anyOf` with more than 2 variants.',
|
|
6
|
+
clients: ['windsurf'],
|
|
7
|
+
docs: {
|
|
8
|
+
why: 'Windsurf\'s MCP client has limited support for complex union types. `anyOf` with more than 2 variants may be silently ignored or cause unexpected behavior.',
|
|
9
|
+
badExample: {
|
|
10
|
+
properties: {
|
|
11
|
+
value: { anyOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }] },
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
goodExample: {
|
|
15
|
+
properties: {
|
|
16
|
+
value: { anyOf: [{ type: 'string' }, { type: 'null' }] },
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
fixNote: 'Reduce anyOf to at most 2 variants, or replace with a single type.',
|
|
20
|
+
},
|
|
21
|
+
check(tool, _context) {
|
|
22
|
+
const diagnostics = [];
|
|
23
|
+
walkSchema(tool.inputSchema, (schema, path) => {
|
|
24
|
+
if (Array.isArray(schema.anyOf) && schema.anyOf.length > 2) {
|
|
25
|
+
const diagnosticPath = path ? `inputSchema.${path}` : 'inputSchema';
|
|
26
|
+
diagnostics.push({
|
|
27
|
+
ruleId: 'windsurf/no-union-types',
|
|
28
|
+
severity: 'warning',
|
|
29
|
+
message: `Schema at "${diagnosticPath}" uses \`anyOf\` with ${schema.anyOf.length} variants. Windsurf supports at most 2.`,
|
|
30
|
+
toolName: tool.name,
|
|
31
|
+
path: diagnosticPath,
|
|
32
|
+
clients: ['windsurf'],
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
return diagnostics;
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=windsurf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windsurf.js","sourceRoot":"","sources":["../../../src/rules/client-specific/windsurf.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE1D,MAAM,CAAC,MAAM,oBAAoB,GAAS;IACxC,EAAE,EAAE,yBAAyB;IAC7B,QAAQ,EAAE,SAAS;IACnB,WAAW,EAAE,8DAA8D;IAC3E,OAAO,EAAE,CAAC,UAAU,CAAC;IACrB,IAAI,EAAE;QACJ,GAAG,EAAE,6JAA6J;QAClK,UAAU,EAAE;YACV,UAAU,EAAE;gBACV,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE;aAChF;SACF;QACD,WAAW,EAAE;YACX,UAAU,EAAE;gBACV,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE;aACzD;SACF;QACD,OAAO,EAAE,oEAAoE;KAC9E;IAED,KAAK,CAAC,IAAa,EAAE,QAAqB;QACxC,MAAM,WAAW,GAAiB,EAAE,CAAC;QAErC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;YAC5C,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC3D,MAAM,cAAc,GAAG,IAAI,CAAC,CAAC,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;gBACpE,WAAW,CAAC,IAAI,CAAC;oBACf,MAAM,EAAE,yBAAyB;oBACjC,QAAQ,EAAE,SAAS;oBACnB,OAAO,EAAE,cAAc,cAAc,yBAAyB,MAAM,CAAC,KAAK,CAAC,MAAM,yCAAyC;oBAC1H,QAAQ,EAAE,IAAI,CAAC,IAAI;oBACnB,IAAI,EAAE,cAAc;oBACpB,OAAO,EAAE,CAAC,UAAU,CAAC;iBACtB,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,WAAW,CAAC;IACrB,CAAC;CACF,CAAC"}
|
package/dist/rules/index.js
CHANGED
|
@@ -7,9 +7,13 @@ import { noRecursiveRefs } from './no-recursive-refs.js';
|
|
|
7
7
|
import { validJsonSchemaSubset } from './valid-json-schema-subset.js';
|
|
8
8
|
import { noUnsupportedFormats } from './no-unsupported-formats.js';
|
|
9
9
|
import { claudeNoTypeArray } from './client-specific/claude.js';
|
|
10
|
+
import { continueNoDefaultValues } from './client-specific/continue.js';
|
|
10
11
|
import { cursorNoDefaultWithoutType } from './client-specific/cursor.js';
|
|
11
12
|
import { geminiNoOptionalWithoutDefault, geminiNoNestedObjects } from './client-specific/gemini.js';
|
|
12
13
|
import { vscodeMaxParams } from './client-specific/vscode.js';
|
|
14
|
+
import { windsurfNoUnionTypes } from './client-specific/windsurf.js';
|
|
15
|
+
import { clineDescriptionMaxLength } from './client-specific/cline.js';
|
|
16
|
+
import { openaiNoAdditionalProperties, openaiStrictTypes } from './client-specific/openai.js';
|
|
13
17
|
export const allRules = [
|
|
14
18
|
noRequiredFalse,
|
|
15
19
|
noContentEncoding,
|
|
@@ -20,9 +24,14 @@ export const allRules = [
|
|
|
20
24
|
validJsonSchemaSubset,
|
|
21
25
|
noUnsupportedFormats,
|
|
22
26
|
claudeNoTypeArray,
|
|
27
|
+
continueNoDefaultValues,
|
|
23
28
|
cursorNoDefaultWithoutType,
|
|
24
29
|
geminiNoOptionalWithoutDefault,
|
|
25
30
|
geminiNoNestedObjects,
|
|
26
31
|
vscodeMaxParams,
|
|
32
|
+
windsurfNoUnionTypes,
|
|
33
|
+
clineDescriptionMaxLength,
|
|
34
|
+
openaiNoAdditionalProperties,
|
|
35
|
+
openaiStrictTypes,
|
|
27
36
|
];
|
|
28
37
|
//# sourceMappingURL=index.js.map
|
package/dist/rules/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AACzE,OAAO,EAAE,8BAA8B,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpG,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AACzE,OAAO,EAAE,8BAA8B,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpG,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,4BAA4B,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAE9F,MAAM,CAAC,MAAM,QAAQ,GAAW;IAC9B,eAAe;IACf,iBAAiB;IACjB,iBAAiB;IACjB,WAAW;IACX,QAAQ;IACR,eAAe;IACf,qBAAqB;IACrB,oBAAoB;IACpB,iBAAiB;IACjB,uBAAuB;IACvB,0BAA0B;IAC1B,8BAA8B;IAC9B,qBAAqB;IACrB,eAAe;IACf,oBAAoB;IACpB,yBAAyB;IACzB,4BAA4B;IAC5B,iBAAiB;CAClB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "mcp-lint",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Lint MCP server tool schemas for cross-client compatibility",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"bin": {
|
|
7
|
-
"mcp-lint": "./dist/index.js"
|
|
8
|
-
},
|
|
9
|
-
"main": "./dist/core/engine.js",
|
|
10
|
-
"types": "./dist/core/engine.d.ts",
|
|
11
|
-
"files": [
|
|
12
|
-
"dist/"
|
|
13
|
-
],
|
|
14
|
-
"keywords": [
|
|
15
|
-
"mcp",
|
|
16
|
-
"model-context-protocol",
|
|
17
|
-
"lint",
|
|
18
|
-
"schema",
|
|
19
|
-
"validation"
|
|
20
|
-
],
|
|
21
|
-
"license": "MIT",
|
|
22
|
-
"engines": {
|
|
23
|
-
"node": ">=
|
|
24
|
-
},
|
|
25
|
-
"scripts": {
|
|
26
|
-
"build": "tsc",
|
|
27
|
-
"dev": "tsc --watch",
|
|
28
|
-
"test": "vitest run",
|
|
29
|
-
"test:watch": "vitest",
|
|
30
|
-
"test:coverage": "vitest run --coverage",
|
|
31
|
-
"prepublishOnly": "npm run build && npm run test"
|
|
32
|
-
},
|
|
33
|
-
"dependencies": {
|
|
34
|
-
"@modelcontextprotocol/sdk": "^1.28.0",
|
|
35
|
-
"chalk": "^5.6.2",
|
|
36
|
-
"commander": "^14.0.3",
|
|
37
|
-
"yaml": "^2.8.3"
|
|
38
|
-
},
|
|
39
|
-
"devDependencies": {
|
|
40
|
-
"@types/node": "^25.5.0",
|
|
41
|
-
"typescript": "^6.0.2",
|
|
42
|
-
"vitest": "^4.1.1"
|
|
43
|
-
}
|
|
44
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "mcp-lint",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Lint MCP server tool schemas for cross-client compatibility",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mcp-lint": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/core/engine.js",
|
|
10
|
+
"types": "./dist/core/engine.d.ts",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist/"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"mcp",
|
|
16
|
+
"model-context-protocol",
|
|
17
|
+
"lint",
|
|
18
|
+
"schema",
|
|
19
|
+
"validation"
|
|
20
|
+
],
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=20"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc",
|
|
27
|
+
"dev": "tsc --watch",
|
|
28
|
+
"test": "vitest run",
|
|
29
|
+
"test:watch": "vitest",
|
|
30
|
+
"test:coverage": "vitest run --coverage",
|
|
31
|
+
"prepublishOnly": "npm run build && npm run test"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@modelcontextprotocol/sdk": "^1.28.0",
|
|
35
|
+
"chalk": "^5.6.2",
|
|
36
|
+
"commander": "^14.0.3",
|
|
37
|
+
"yaml": "^2.8.3"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^25.5.0",
|
|
41
|
+
"typescript": "^6.0.2",
|
|
42
|
+
"vitest": "^4.1.1"
|
|
43
|
+
}
|
|
44
|
+
}
|