@loggi87/mcp-custom-xs 1.0.0 → 1.0.3

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.
Files changed (3) hide show
  1. package/README.md +365 -0
  2. package/index.js +131 -43
  3. package/package.json +7 -3
package/README.md ADDED
@@ -0,0 +1,365 @@
1
+ # mcp-custom-xs
2
+
3
+ **MCP Server con reglas de código compartidas para proyectos React + TypeScript.**
4
+
5
+ Un paquete de reglas y estándares que puedes usar en tus proyectos para mantener calidad, consistencia y arquitectura limpia.
6
+
7
+ ---
8
+
9
+ ## 📋 ¿Qué incluye?
10
+
11
+ - ✅ **Max 80 líneas por archivo** - Mantén archivos pequeños y legibles
12
+ - ✅ **Atomic Design** - Estructura de componentes: atoms → molecules → organisms
13
+ - ✅ **Feature-based** - Organiza por features, no por tipo
14
+ - ✅ **TypeScript Strict** - Type safety total
15
+ - ✅ **Validación automática** - Valida tus archivos contra las reglas
16
+
17
+ ---
18
+
19
+ ## 🚀 Instalación
20
+
21
+ ### 1. Instalar el paquete
22
+
23
+ ```bash
24
+ npm install @loggi87/mcp-custom-xs
25
+ ```
26
+
27
+ ### 2. Opción A: Usar en Claude.ai (recomendado para desarrollo)
28
+
29
+ Agrega las reglas a tus **Custom Instructions** en Claude.ai:
30
+
31
+ **Settings → Custom Instructions → Instructions**
32
+
33
+ ````
34
+ # MCP Code Rules (@loggi87/mcp-custom-xs)
35
+
36
+ ## Reglas obligatorias para TODOS los features:
37
+
38
+ 1. **Max 80 líneas por archivo**
39
+ - Si necesitas más, divide en múltiples archivos
40
+ - Excepciones documentadas requieren comentario // LONG_FILE
41
+
42
+ 2. **Atomic Design para componentes**
43
+ ```
44
+ src/components/
45
+ ├── atoms/ (botones, inputs, etiquetas)
46
+ ├── molecules/ (formularios simples, tarjetas)
47
+ └── organisms/ (modales, headers complejos)
48
+ ```
49
+
50
+ 3. **Feature-based structure**
51
+ ```
52
+ src/features/{featureName}/
53
+ ├── components/ (atoms, molecules, organisms)
54
+ ├── hooks/
55
+ ├── services/
56
+ ├── types/
57
+ └── index.ts
58
+ ```
59
+
60
+ 4. **TypeScript Strict Mode**
61
+ - \`tsconfig.json\`: \`"strict": true\`
62
+ - No usar \`any\`
63
+ - Tipear siempre argumentos y retornos
64
+
65
+ 5. **Validar con tsc ANTES de terminar**
66
+ ```bash
67
+ tsc --noEmit
68
+ ```
69
+
70
+ ## Cuando generes código:
71
+ 1. Crea los archivos respetando estas reglas
72
+ 2. Muestra la estructura antes del código
73
+ 3. Al final, ejecuta \`tsc --noEmit\`
74
+ 4. Si hay errores de tipos, arréglalos
75
+ 5. Reporta: ✅ Validado o ❌ Errores encontrados
76
+
77
+ ## Ejemplo de request:
78
+ "Crea el feature de AuthModal usando @loggi87/mcp-custom-xs"
79
+ ````
80
+
81
+ **Listo.** Desde ese momento, cada código que te genere seguirá estas reglas automáticamente.
82
+
83
+ ### 3. Opción B: Usar en tu proyecto (para validación programática)
84
+
85
+ ```javascript
86
+ // En tu proyecto
87
+ const rules = require('@loggi87/mcp-custom-xs');
88
+
89
+ // Validar un archivo
90
+ const validation = rules.validateFile('./src/components/Button.tsx');
91
+
92
+ console.log(validation);
93
+ // {
94
+ // valid: true,
95
+ // errors: [],
96
+ // file: './src/components/Button.tsx',
97
+ // lineCount: 31
98
+ // }
99
+ ```
100
+
101
+ ---
102
+
103
+ ## 📂 Estructura recomendada
104
+
105
+ ```
106
+ proyecto/
107
+ ├── src/
108
+ │ ├── components/
109
+ │ │ ├── atoms/
110
+ │ │ │ ├── Button.tsx (30 líneas)
111
+ │ │ │ └── Input.tsx (28 líneas)
112
+ │ │ ├── molecules/
113
+ │ │ │ └── LoginForm.tsx (65 líneas)
114
+ │ │ └── organisms/
115
+ │ │ └── AuthModal.tsx (72 líneas)
116
+ │ ├── features/
117
+ │ │ ├── Auth/
118
+ │ │ │ ├── components/
119
+ │ │ │ ├── hooks/
120
+ │ │ │ ├── services/
121
+ │ │ │ ├── types/
122
+ │ │ │ └── index.ts
123
+ │ │ └── Dashboard/
124
+ │ │ └── ...
125
+ │ ├── hooks/
126
+ │ ├── services/
127
+ │ ├── types/
128
+ │ └── index.ts
129
+ ├── tsconfig.json
130
+ ├── .eslintrc.json
131
+ └── package.json
132
+ ```
133
+
134
+ ---
135
+
136
+ ## 🔧 Configuración recomendada
137
+
138
+ ### tsconfig.json
139
+
140
+ ```json
141
+ {
142
+ "compilerOptions": {
143
+ "strict": true,
144
+ "esModuleInterop": true,
145
+ "skipLibCheck": true,
146
+ "forceConsistentCasingInFileNames": true,
147
+ "resolveJsonModule": true,
148
+ "moduleResolution": "node",
149
+ "target": "ES2020",
150
+ "module": "ESNext",
151
+ "lib": ["ES2020", "DOM", "DOM.Iterable"]
152
+ }
153
+ }
154
+ ```
155
+
156
+ ### .eslintrc.json
157
+
158
+ ```json
159
+ {
160
+ "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
161
+ "parser": "@typescript-eslint/parser",
162
+ "rules": {
163
+ "max-lines": ["error", { "max": 80 }],
164
+ "@typescript-eslint/no-explicit-any": "error",
165
+ "no-unused-vars": "warn"
166
+ }
167
+ }
168
+ ```
169
+
170
+ ---
171
+
172
+ ## 💡 Ejemplos
173
+
174
+ ### ✅ Buen componente (respeta las reglas)
175
+
176
+ **src/components/atoms/Button.tsx**
177
+ ```typescript
178
+ import React from 'react';
179
+
180
+ interface ButtonProps {
181
+ label: string;
182
+ onClick: () => void;
183
+ variant?: 'primary' | 'secondary';
184
+ }
185
+
186
+ export const Button: React.FC<ButtonProps> = ({
187
+ label,
188
+ onClick,
189
+ variant = 'primary',
190
+ }) => {
191
+ const baseStyle = 'px-4 py-2 rounded font-semibold';
192
+ const variantStyle =
193
+ variant === 'primary'
194
+ ? 'bg-blue-500 text-white'
195
+ : 'bg-gray-200 text-black';
196
+
197
+ return (
198
+ <button
199
+ className={\`\${baseStyle} \${variantStyle}\`}
200
+ onClick={onClick}
201
+ >
202
+ {label}
203
+ </button>
204
+ );
205
+ };
206
+ ```
207
+
208
+ **Cumple:**
209
+ - ✅ 31 líneas (< 80)
210
+ - ✅ En \`atoms/\` (Atomic Design)
211
+ - ✅ TypeScript tipado correctamente
212
+ - ✅ Componente simple y reutilizable
213
+
214
+ ### ❌ Mal componente (no respeta reglas)
215
+
216
+ ```typescript
217
+ // ❌ 120 líneas (> 80)
218
+ // ❌ Lógica compleja + UI mezcladas
219
+ // ❌ No está en estructura atómica
220
+ // ❌ any types
221
+ ```
222
+
223
+ ---
224
+
225
+ ## 🤝 Mejoras y contribuciones
226
+
227
+ ¿Querés mejorar las reglas? ¡Excelente!
228
+
229
+ 1. **Fork el repo**
230
+ 2. **Crea una rama** (\`git checkout -b feature/nueva-regla\`)
231
+ 3. **Modifica \`index.js\`**
232
+ 4. **Testea** (\`npm test\`)
233
+ 5. **Haz PR** con descripción clara
234
+
235
+ ### Cambios comunes que podrías hacer:
236
+
237
+ ```javascript
238
+ // En index.js, puedes agregar:
239
+
240
+ // - Cambiar límite de líneas
241
+ max_lines_per_file: 100, // Era 80
242
+
243
+ // - Agregar nuevas validaciones
244
+ no_console_logs: true,
245
+
246
+ // - Permitir excepciones
247
+ exceptions: {
248
+ "src/utils/constants.ts": { max_lines: 200 }
249
+ }
250
+ ```
251
+
252
+ ---
253
+
254
+ ## 📦 Cómo se usa en un proyecto real
255
+
256
+ ### Paso 1: Instalar
257
+
258
+ ```bash
259
+ npm install @loggi87/mcp-custom-xs
260
+ ```
261
+
262
+ ### Paso 2: Agregar a Claude Custom Instructions
263
+
264
+ Copia el contenido arriba y pégalo en Claude.ai Settings.
265
+
266
+ ### Paso 3: Pedir features
267
+
268
+ ```
269
+ "Crea el feature de LoginForm con:
270
+ - Validación de email
271
+ - Password con toggle visibility
272
+ - Remember me checkbox
273
+
274
+ Usa @loggi87/mcp-custom-xs"
275
+ ```
276
+
277
+ Claude automáticamente:
278
+ - ✅ Divide en atoms/molecules si es necesario
279
+ - ✅ Mantiene archivos < 80 líneas
280
+ - ✅ Usa TypeScript strict
281
+ - ✅ Corre \`tsc --noEmit\`
282
+ - ✅ Reporta si todo está ✅
283
+
284
+ ---
285
+
286
+ ## 📋 API
287
+
288
+ ### \`rules\`
289
+
290
+ Objeto con todas las reglas definidas:
291
+
292
+ ```javascript
293
+ const { rules } = require('@loggi87/mcp-custom-xs');
294
+
295
+ console.log(rules);
296
+ // {
297
+ // max_lines_per_file: 80,
298
+ // architecture: 'atomic',
299
+ // project_structure: 'feature-based',
300
+ // typescript_strict: true,
301
+ // run_tsc_before_finish: true
302
+ // }
303
+ ```
304
+
305
+ ### \`validateFile(filePath)\`
306
+
307
+ Valida un archivo contra las reglas:
308
+
309
+ ```javascript
310
+ const { validateFile } = require('@loggi87/mcp-custom-xs');
311
+
312
+ const result = validateFile('./src/components/atoms/Button.tsx');
313
+
314
+ console.log(result);
315
+ // {
316
+ // valid: true,
317
+ // errors: [],
318
+ // file: './src/components/atoms/Button.tsx',
319
+ // lineCount: 31
320
+ // }
321
+ ```
322
+
323
+ ---
324
+
325
+ ## 🐛 Troubleshooting
326
+
327
+ ### "Cannot find module '@loggi87/mcp-custom-xs'"
328
+
329
+ ```bash
330
+ npm install @loggi87/mcp-custom-xs
331
+ ```
332
+
333
+ ### "TypeScript errors después de instalar"
334
+
335
+ Verifica que \`tsconfig.json\` tiene \`"strict": true\`
336
+
337
+ ### "Claude no sigue las reglas"
338
+
339
+ 1. Verifica que copiaste las Custom Instructions correctamente
340
+ 2. Pide explícitamente: "usa @loggi87/mcp-custom-xs"
341
+ 3. Si no funciona, menciona las reglas en el mensaje
342
+
343
+ ---
344
+
345
+ ## 📞 Contacto
346
+
347
+ ¿Preguntas, bugs, o mejoras?
348
+
349
+ - **Issues**: Abre un issue en GitHub
350
+ - **Mejoras**: Haz un PR
351
+ - **Contacto directo**: [@loggi87](https://github.com/loggi87)
352
+
353
+ ---
354
+
355
+ ## 📄 Licencia
356
+
357
+ MIT - Úsalo libremente en tus proyectos
358
+
359
+ ---
360
+
361
+ ## Versión
362
+
363
+ **@loggi87/mcp-custom-xs@1.0.0**
364
+
365
+ Última actualización: Marzo 2026
package/index.js CHANGED
@@ -1,56 +1,144 @@
1
- // index.js - MCP Server
1
+ // index.js - MCP Server (@loggi87/mcp-custom-xs)
2
+ const { McpServer } = require("@modelcontextprotocol/sdk/server/mcp.js");
3
+ const { StdioServerTransport } = require("@modelcontextprotocol/sdk/server/stdio.js");
4
+ const { z } = require("zod");
2
5
  const fs = require("fs");
6
+ const path = require("path");
3
7
 
4
- class CodeRulesMCP {
5
- constructor() {
6
- this.rules = {
7
- max_lines_per_file: 80,
8
- architecture: "atomic",
9
- project_structure: "feature-based",
10
- typescript_strict: true,
11
- run_tsc_before_finish: true
12
- };
8
+ const RULES = {
9
+ max_lines_per_file: 80,
10
+ architecture: "atomic",
11
+ project_structure: "feature-based",
12
+ typescript_strict: true,
13
+ run_tsc_before_finish: true
14
+ };
15
+
16
+ function validateFile(filePath) {
17
+ try {
18
+ const content = fs.readFileSync(filePath, "utf-8");
19
+ const lines = content.split("\n").length;
20
+ const errors = [];
21
+
22
+ if (lines > RULES.max_lines_per_file) {
23
+ errors.push({
24
+ type: "TOO_MANY_LINES",
25
+ message: `❌ ${lines} líneas (máx ${RULES.max_lines_per_file})`,
26
+ severity: "error"
27
+ });
13
28
  }
14
29
 
15
- // Valida un archivo
16
- validateFile(filePath) {
17
- const content = fs.readFileSync(filePath, "utf-8");
18
- const lines = content.split("\n").length;
30
+ if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) {
31
+ if (!content.includes("// @ts-check") && !content.includes("strict")) {
32
+ errors.push({
33
+ type: "NO_TYPESCRIPT_STRICT",
34
+ message: "❌ Falta TypeScript strict mode",
35
+ severity: "warn",
36
+ suggestion: "Agrega 'strict': true en tsconfig.json"
37
+ });
38
+ }
39
+ }
19
40
 
20
- const errors = [];
41
+ if (filePath.includes("components")) {
42
+ const validDirs = ["/atoms/", "/molecules/", "/organisms/"];
43
+ if (!validDirs.some((dir) => filePath.includes(dir))) {
44
+ errors.push({
45
+ type: "WRONG_COMPONENT_STRUCTURE",
46
+ message: "❌ Componente no está en atoms/molecules/organisms",
47
+ severity: "error",
48
+ suggestion: "Estructura correcta: src/components/{atoms|molecules|organisms}/"
49
+ });
50
+ }
51
+ }
21
52
 
22
- // Validar líneas
23
- if (lines > this.rules.max_lines_per_file) {
24
- errors.push(`❌ ${lines} líneas (máx ${this.rules.max_lines_per_file})`);
25
- }
53
+ return {
54
+ valid: errors.length === 0,
55
+ file: filePath,
56
+ lineCount: lines,
57
+ errors,
58
+ summary: errors.length === 0
59
+ ? "✅ Archivo válido"
60
+ : `❌ ${errors.length} error(es) encontrado(s)`
61
+ };
62
+ } catch (error) {
63
+ return {
64
+ valid: false,
65
+ file: filePath,
66
+ errors: [{ type: "FILE_READ_ERROR", message: error.message, severity: "error" }]
67
+ };
68
+ }
69
+ }
26
70
 
27
- // Validar TypeScript strict
28
- if (!content.includes('// @ts-check')) {
29
- errors.push("❌ Falta // @ts-check para TypeScript strict");
30
- }
71
+ function validateFeature(featureDir) {
72
+ const results = [];
31
73
 
32
- // Validar estructura atómica
33
- if (filePath.includes("components")) {
34
- const validDirs = ["/atoms/", "/molecules/", "/organisms/"];
35
- if (!validDirs.some((dir) => filePath.includes(dir))) {
36
- errors.push("❌ Componente no está en atomic/molecules/organisms");
37
- }
74
+ const walkDir = (dir) => {
75
+ try {
76
+ fs.readdirSync(dir).forEach((file) => {
77
+ const filePath = path.join(dir, file);
78
+ const stat = fs.statSync(filePath);
79
+ if (stat.isDirectory() && !file.startsWith(".")) {
80
+ walkDir(filePath);
81
+ } else if (/\.(ts|tsx|js)$/.test(file)) {
82
+ results.push(validateFile(filePath));
38
83
  }
84
+ });
85
+ } catch (e) {}
86
+ };
39
87
 
40
- return {
41
- valid: errors.length === 0,
42
- errors,
43
- suggestions: this.getSuggestions(errors)
44
- };
45
- }
88
+ walkDir(featureDir);
46
89
 
47
- getSuggestions(errors) {
48
- return {
49
- tooManyLines: "Divide en múltiples archivos más pequeños",
50
- noTypeScript: "Agrega strict mode a tsconfig.json",
51
- wrongFolder: "Mueve a la carpeta de atomic design correcta"
52
- };
53
- }
90
+ const totalErrors = results.reduce((sum, r) => sum + r.errors.length, 0);
91
+ return {
92
+ valid: totalErrors === 0,
93
+ featureDir,
94
+ filesValidated: results.length,
95
+ totalErrors,
96
+ files: results,
97
+ summary: totalErrors === 0
98
+ ? `✅ Feature válido (${results.length} archivos)`
99
+ : `❌ ${totalErrors} error(es) en ${results.length} archivo(s)`
100
+ };
101
+ }
102
+
103
+ function getFormattedRules() {
104
+ return `# Reglas del proyecto (@loggi87/mcp-custom-xs)
105
+
106
+ 1. **Max ${RULES.max_lines_per_file} líneas por archivo**
107
+ 2. **Atomic Design** para componentes (atoms / molecules / organisms)
108
+ 3. **Feature-based** project structure
109
+ 4. **TypeScript Strict Mode**
110
+ 5. **Ejecutar tsc** antes de terminar cualquier tarea`;
54
111
  }
55
112
 
56
- module.exports = new CodeRulesMCP();
113
+ // Servidor MCP
114
+ const server = new McpServer({ name: "mcp-custom-xs", version: "1.0.3" });
115
+
116
+ server.tool(
117
+ "validate_file",
118
+ "Valida un archivo contra las reglas del proyecto (líneas, atomic design, TypeScript)",
119
+ { filePath: z.string().describe("Ruta absoluta o relativa al archivo a validar") },
120
+ async ({ filePath }) => ({
121
+ content: [{ type: "text", text: JSON.stringify(validateFile(filePath), null, 2) }]
122
+ })
123
+ );
124
+
125
+ server.tool(
126
+ "validate_feature",
127
+ "Valida todos los archivos de un directorio/feature contra las reglas del proyecto",
128
+ { featureDir: z.string().describe("Ruta al directorio del feature a validar") },
129
+ async ({ featureDir }) => ({
130
+ content: [{ type: "text", text: JSON.stringify(validateFeature(featureDir), null, 2) }]
131
+ })
132
+ );
133
+
134
+ server.tool(
135
+ "get_rules",
136
+ "Devuelve las reglas de código del proyecto",
137
+ {},
138
+ async () => ({
139
+ content: [{ type: "text", text: getFormattedRules() }]
140
+ })
141
+ );
142
+
143
+ const transport = new StdioServerTransport();
144
+ server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loggi87/mcp-custom-xs",
3
- "version": "1.0.0",
3
+ "version": "1.0.3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -10,5 +10,9 @@
10
10
  "mcp",
11
11
  "rules",
12
12
  "atomic-design"
13
- ]
14
- }
13
+ ],
14
+ "dependencies": {
15
+ "@modelcontextprotocol/sdk": "^1.28.0",
16
+ "zod": "^4.3.6"
17
+ }
18
+ }