Skip to content

Commit e3013f2

Browse files
author
Wilson
committed
Update package version to 0.0.1-alpha.3, refactor server implementation to use a more modular approach, and enhance validation error handling. Simplify tool parameter definitions and improve default configuration settings.
1 parent e09e77b commit e3013f2

File tree

6 files changed

+198
-141
lines changed

6 files changed

+198
-141
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "markdownlint-mcp-server",
3-
"version": "0.0.1-alpha.1",
3+
"version": "0.0.1-alpha.3",
44
"description": "MCP server implementation for markdownlint that validates markdown content against markdownlint rules",
55
"type": "module",
66
"main": "dist/index.js",

src/bin.ts

Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,3 @@
11
#!/usr/bin/env node
22

3-
import { markdownlintMcpServer } from './index.js';
4-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5-
6-
async function main() {
7-
const server = markdownlintMcpServer();
8-
const transport = new StdioServerTransport();
9-
10-
try {
11-
console.log('Starting markdownlint MCP server...');
12-
13-
// Connect the server
14-
await server.connect(transport);
15-
console.log('Server connected successfully');
16-
17-
// Handle process signals
18-
process.on('SIGINT', cleanup);
19-
process.on('SIGTERM', cleanup);
20-
21-
// Handle process errors
22-
process.on('uncaughtException', (error) => {
23-
console.error('Uncaught exception:', error);
24-
cleanup();
25-
});
26-
27-
process.on('unhandledRejection', (error) => {
28-
console.error('Unhandled rejection:', error);
29-
cleanup();
30-
});
31-
32-
} catch (error) {
33-
console.error('Failed to start markdownlint MCP server:', error);
34-
cleanup();
35-
process.exit(1);
36-
}
37-
38-
function cleanup() {
39-
console.log('Cleaning up...');
40-
try {
41-
transport.close();
42-
server.disconnect();
43-
} catch (error) {
44-
console.error('Error during cleanup:', error);
45-
}
46-
process.exit(0);
47-
}
48-
}
49-
50-
main().catch((error) => {
51-
console.error('Unhandled error:', error);
52-
process.exit(1);
53-
});
3+
import './index.js';

src/config.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
// Default configuration based on markdownlint.md rules
22
export const defaultConfig = {
3+
'default': true,
34
'MD001': true, // Heading levels should only increment by one level at a time
4-
'MD003': { style: 'consistent' }, // Heading style
5-
'MD004': { style: 'consistent' }, // Unordered list style
5+
'MD002': true, // First heading should be a top level heading
6+
'MD003': true, // Heading style
7+
'MD004': true, // Unordered list style
68
'MD005': true, // Inconsistent indentation for list items at the same level
7-
'MD007': { indent: 2 }, // Unordered list indentation
9+
'MD006': true, // Consider starting bulleted lists at the beginning of the line
10+
'MD007': true, // Unordered list indentation
811
'MD009': true, // Trailing spaces
912
'MD010': true, // Hard tabs
1013
'MD011': true, // Reversed link syntax
@@ -34,10 +37,10 @@ export const defaultConfig = {
3437
'MD038': true, // Spaces inside code span elements
3538
'MD039': true, // Spaces inside link text
3639
'MD040': true, // Fenced code blocks should have a language specified
37-
'MD041': true, // First line should be a top level heading
40+
'MD041': true, // First line in file should be a top level heading
3841
'MD042': true, // No empty links
3942
'MD043': true, // Required heading structure
40-
'MD044': true, // Proper names should have proper capitalization
43+
'MD044': true, // Proper names should have the correct capitalization
4144
'MD045': true, // Images should have alternate text (alt text)
4245
'MD046': true, // Code block style
4346
'MD047': true, // Files should end with a single newline character

src/index.ts

Lines changed: 130 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,149 @@
1-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2-
import { defaultConfig } from './config.js';
3-
import { toolParamsSchema } from './types.js';
1+
#!/usr/bin/env node
2+
3+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5+
import {
6+
CallToolRequestSchema,
7+
ListToolsRequestSchema,
8+
Tool,
9+
} from "@modelcontextprotocol/sdk/types.js";
410
import { validateMarkdown } from './validation.js';
5-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
11+
import { defaultConfig } from './config.js';
12+
13+
const VALIDATE_TOOL: Tool = {
14+
name: "validate",
15+
description:
16+
"Validates markdown content against markdownlint rules. " +
17+
"Checks for common markdown style and formatting issues. " +
18+
"Returns validation results including any errors found. " +
19+
"Can be configured with custom markdownlint rules.",
20+
inputSchema: {
21+
type: "object",
22+
properties: {
23+
content: {
24+
type: "string",
25+
description: "The markdown content to validate"
26+
},
27+
config: {
28+
type: "object",
29+
description: "Optional markdownlint configuration",
30+
additionalProperties: true
31+
}
32+
},
33+
required: ["content"]
34+
}
35+
};
36+
37+
const RULES_TOOL: Tool = {
38+
name: "rules",
39+
description:
40+
"Returns the available markdownlint rules and their configurations. " +
41+
"Each rule includes its default settings and description.",
42+
inputSchema: {
43+
type: "object",
44+
properties: {},
45+
additionalProperties: false
46+
}
47+
};
48+
49+
// Server implementation
50+
const server = new Server(
51+
{
52+
name: "markdownlint-server",
53+
version: "1.0.0",
54+
},
55+
{
56+
capabilities: {
57+
tools: {},
58+
},
59+
}
60+
);
61+
62+
function isValidateArgs(args: unknown): args is { content: string; config?: Record<string, any> } {
63+
return (
64+
typeof args === "object" &&
65+
args !== null &&
66+
"content" in args &&
67+
typeof (args as { content: string }).content === "string" &&
68+
(!("config" in args) || typeof (args as { config: unknown }).config === "object")
69+
);
70+
}
71+
72+
function isRulesArgs(args: unknown): args is Record<string, never> {
73+
return (
74+
typeof args === "object" &&
75+
args !== null &&
76+
Object.keys(args).length === 0
77+
);
78+
}
679

7-
export class MarkdownlintMcpServer extends McpServer {
8-
private currentTransport: StdioServerTransport | null = null;
80+
// Tool handlers
81+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
82+
tools: [VALIDATE_TOOL, RULES_TOOL],
83+
}));
984

10-
constructor() {
11-
super({
12-
name: 'markdownlint-server',
13-
version: '1.0.0'
14-
});
85+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
86+
try {
87+
const { name, arguments: args } = request.params;
1588

16-
// Define the validate tool
17-
this.tool(
18-
'validate',
19-
toolParamsSchema,
20-
async (params) => {
21-
const result = await validateMarkdown(params);
89+
if (!args) {
90+
throw new Error("No arguments provided");
91+
}
92+
93+
switch (name) {
94+
case "validate": {
95+
if (!isValidateArgs(args)) {
96+
throw new Error("Invalid arguments for validate tool");
97+
}
98+
const result = await validateMarkdown(args);
2299
return {
23100
content: [{
24-
type: 'text',
101+
type: "text",
25102
text: JSON.stringify(result, null, 2)
26103
}],
27104
isError: !result.isValid
28105
};
29106
}
30-
);
31107

32-
// Define the rules tool
33-
this.tool(
34-
'rules',
35-
{},
36-
async () => {
37-
try {
38-
return {
39-
content: [{
40-
type: 'text',
41-
text: JSON.stringify(defaultConfig, null, 2)
42-
}]
43-
};
44-
} catch (error) {
45-
return {
46-
content: [{
47-
type: 'text',
48-
text: JSON.stringify({
49-
error: error instanceof Error ? error.message : 'Unknown error'
50-
}, null, 2)
51-
}],
52-
isError: true
53-
};
108+
case "rules": {
109+
if (!isRulesArgs(args)) {
110+
throw new Error("Invalid arguments for rules tool");
54111
}
112+
return {
113+
content: [{
114+
type: "text",
115+
text: JSON.stringify(defaultConfig, null, 2)
116+
}],
117+
isError: false
118+
};
55119
}
56-
);
57-
}
58-
59-
async connect(transport: StdioServerTransport): Promise<void> {
60-
this.currentTransport = transport;
61-
await super.connect(transport);
62-
}
63120

64-
disconnect(): void {
65-
if (this.currentTransport) {
66-
this.currentTransport.close();
67-
this.currentTransport = null;
121+
default:
122+
return {
123+
content: [{ type: "text", text: `Unknown tool: ${name}` }],
124+
isError: true,
125+
};
68126
}
127+
} catch (error) {
128+
return {
129+
content: [
130+
{
131+
type: "text",
132+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
133+
},
134+
],
135+
isError: true,
136+
};
69137
}
138+
});
139+
140+
async function runServer() {
141+
const transport = new StdioServerTransport();
142+
await server.connect(transport);
143+
console.error("Markdownlint MCP Server running on stdio");
70144
}
71145

72-
export function markdownlintMcpServer() {
73-
return new MarkdownlintMcpServer();
74-
}
146+
runServer().catch((error) => {
147+
console.error("Fatal error running server:", error);
148+
process.exit(1);
149+
});

src/types.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { z } from 'zod';
2-
31
export interface ValidationError {
42
lineNumber: number;
53
ruleDescription: string;
@@ -18,9 +16,4 @@ export interface ValidationResult {
1816
export interface ToolParams {
1917
content: string;
2018
config?: Record<string, any>;
21-
}
22-
23-
export const toolParamsSchema = {
24-
content: z.string(),
25-
config: z.record(z.any()).optional()
26-
};
19+
}

0 commit comments

Comments
 (0)