apprecio-mcp-base 1.1.1 → 1.1.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.
package/README.md CHANGED
@@ -1,137 +1,283 @@
1
- # @apprecio/mcp-base
1
+ # apprecio-mcp-base
2
2
 
3
3
  Base package para crear servidores MCP (Model Context Protocol) de Apprecio con consistencia y reutilización de código.
4
4
 
5
5
  ## 🚀 Características
6
6
 
7
7
  - **Servidor Base Abstracto**: Clase `McpBaseServer` que encapsula toda la lógica común
8
+ - **Sistema de Features**: Arquitectura modular con `FeatureModule`
8
9
  - **Configuración Centralizada**: Sistema de configuración con validación Zod
9
10
  - **Logger Unificado**: Winston logger con niveles configurables y rotación de archivos
10
- - **Middlewares Reutilizables**: Autenticación, Rate Limiting, CORS, Helmet
11
+ - **Middlewares Reutilizables**: Autenticación Bearer Token, Rate Limiting, CORS, Helmet
11
12
  - **Conectores Database**: MongoDB y Redis pre-configurados
12
13
  - **Port Management**: Búsqueda automática de puertos disponibles
13
14
  - **Graceful Shutdown**: Manejo automático de señales SIGINT/SIGTERM
14
15
  - **TypeScript First**: Completamente tipado con soporte para path aliases
16
+ - **CLI Generator**: Generador de proyectos y features automático
15
17
 
16
18
  ## 📦 Instalación
17
19
 
18
20
  ```bash
19
- npm install @apprecio/mcp-base
21
+ npm install apprecio-mcp-base
20
22
  # o
21
- pnpm add @apprecio/mcp-base
23
+ pnpm add apprecio-mcp-base
22
24
  ```
23
25
 
24
- ## 🎯 Uso Básico
26
+ ## 🎯 Quick Start
25
27
 
26
- ### 1. Crear un nuevo servidor MCP
28
+ ### Opción 1: Usar el CLI (Recomendado)
29
+
30
+ ```bash
31
+ # 1. Setup global link (una vez)
32
+ cd apprecio-mcp-base
33
+ npm run build
34
+ npm link
35
+
36
+ # 2. Generar nuevo proyecto
37
+ mcp-generate init
38
+
39
+ # Responder wizard:
40
+ # - Nombre del proyecto
41
+ # - Ruta
42
+ # - Usar MongoDB (sí/no)
43
+ # - Base URL de tu API
44
+ # ¿Instalar dependencias? Yes
45
+ # ¿Linkear apprecio-mcp-base? Yes
46
+
47
+ # 3. Ejecutar
48
+ cd my-project
49
+ npm run dev
50
+ ```
51
+
52
+ ### Opción 2: Manual
27
53
 
28
54
  ```typescript
29
55
  import {
30
56
  McpBaseServer,
31
- createExpressServer,
57
+ createServer,
32
58
  findAvailablePort,
33
- createMongoDBConnector
34
- } from '@apprecio/mcp-base';
35
- import type { FeatureModule } from '@apprecio/mcp-base';
59
+ createMongoDBConnector,
60
+ logger,
61
+ type MongoDBConnector
62
+ } from 'apprecio-mcp-base';
36
63
 
37
- // Definir tu servidor MCP personalizado
38
- class MyCustomMcpServer extends McpBaseServer {
64
+ class MyMcpServer extends McpBaseServer {
39
65
  private dbConnector?: MongoDBConnector;
40
66
 
41
67
  protected async registerFeatures(): Promise<void> {
42
- // Registrar tus features personalizadas
43
- this.registerFeature('myFeature', myFeatureModule);
68
+ // Registrar tus features
69
+ this.registerFeature('users', usersFeature);
44
70
  }
45
71
 
46
72
  protected async onBeforeStart(): Promise<void> {
47
- // Conectar a MongoDB si es necesario
48
- if (this.config.mongodbUri) {
49
- this.dbConnector = createMongoDBConnector(this.config.mongodbUri);
73
+ const mongoUri = this.config.mongodbUri;
74
+ if (mongoUri) {
75
+ this.dbConnector = createMongoDBConnector(mongoUri);
50
76
  await this.dbConnector.connect();
51
77
  }
52
78
  }
53
79
 
54
80
  protected async onBeforeShutdown(): Promise<void> {
55
- // Cleanup
56
81
  if (this.dbConnector) {
57
82
  await this.dbConnector.disconnect();
58
83
  }
59
84
  }
60
85
  }
61
86
 
62
- // Iniciar el servidor
63
87
  async function main() {
64
- const server = new MyCustomMcpServer({
65
- name: 'my-custom-mcp',
88
+ const server = new MyMcpServer({
89
+ name: 'my-mcp-server',
66
90
  version: '1.0.0',
67
91
  });
68
92
 
69
93
  const port = await findAvailablePort(server.getConfig().ssePort);
94
+ const { httpServer, transport } = await createServer(port);
70
95
 
71
- const httpServer = await createExpressServer({
72
- mcpServer: server.getMcpServer(),
73
- config: server.getConfig(),
74
- port,
75
- });
76
-
77
- await server.start(httpServer, port);
96
+ await server.start(httpServer, transport, port);
78
97
  }
79
98
 
80
99
  main();
81
100
  ```
82
101
 
83
- ### 2. Crear un Feature Module
102
+ ## 🔧 CLI Generator
103
+
104
+ El paquete incluye un CLI para generar proyectos y features automáticamente.
105
+
106
+ ### Comandos Disponibles
107
+
108
+ ```bash
109
+ # Generar nuevo proyecto
110
+ mcp-generate init
111
+
112
+ # Generar nueva feature
113
+ mcp-generate feature
114
+
115
+ # Help
116
+ mcp-generate --help
117
+ ```
118
+
119
+ ### Generar Proyecto
120
+
121
+ ```bash
122
+ mcp-generate init
123
+
124
+ # Wizard interactivo:
125
+ ? Nombre del proyecto: my-awesome-mcp
126
+ ? Ruta: ./my-awesome-mcp
127
+ ? Descripción: My awesome MCP server
128
+ ? Autor: Tu Nombre
129
+ ? ¿Usar MongoDB? No
130
+ ? Base URL de tu API: https://api.example.com
131
+ ? ¿Instalar dependencias? Yes
132
+ ? ¿Linkear apprecio-mcp-base? Yes
133
+
134
+ # Genera:
135
+ # ✅ Estructura completa del proyecto
136
+ # ✅ Archivos base (main.ts, services, utils)
137
+ # ✅ Scripts de setup (post-install.sh, check-permissions.sh)
138
+ # ✅ Configuración (.env, tsconfig.json, package.json)
139
+ # ✅ README.md completo
140
+ ```
141
+
142
+ ### Generar Feature
143
+
144
+ ```bash
145
+ cd my-project
146
+ npm run generate
147
+
148
+ # Wizard interactivo:
149
+ ? Nombre de la feature: users
150
+ ? Descripción: Manage users
151
+ ? ¿Necesita service? Yes
152
+ ? Tipo de service: API Client
153
+ ? Tools: [x] list, [x] get, [x] create, [x] update
154
+ ? Nombre de la entidad: user
155
+ ? ¿Auto-registrar en main.ts? Yes
156
+
157
+ # Genera:
158
+ # ✅ users.feature.ts - Feature module con tools
159
+ # ✅ users.service.ts - Business logic
160
+ # ✅ users.validation.ts - Zod schemas
161
+ # ✅ Actualiza main.ts automáticamente
162
+ ```
163
+
164
+ ## 📚 Sistema de Features
165
+
166
+ ### Crear un Feature Module
84
167
 
85
168
  ```typescript
86
169
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
87
- import type { FeatureModule } from '@apprecio/mcp-base';
170
+ import { logger, type FeatureModule } from 'apprecio-mcp-base';
88
171
 
89
- export const myFeatureModule: FeatureModule = {
90
- name: 'myFeature',
172
+ export const usersFeature: FeatureModule = {
173
+ name: 'users',
91
174
 
92
175
  register(mcpServer: McpServer): void {
93
- // Registrar tools
176
+ // Registrar tool
94
177
  mcpServer.tool(
95
- 'my_tool',
96
- 'Description of my tool',
178
+ 'list_users',
179
+ 'List all users',
97
180
  {
98
- type: 'object',
99
- properties: {
100
- param: { type: 'string' }
101
- },
102
- required: ['param']
181
+ page: { type: 'number', description: 'Page number' },
182
+ limit: { type: 'number', description: 'Items per page' }
103
183
  },
104
- async (params) => {
105
- // Implementación del tool
184
+ async (args, extra) => {
185
+ // Extraer token de auth
186
+ const req = extra as any;
187
+ const token = req?.requestInfo?.headers?.authorization;
188
+
189
+ // Tu lógica aquí
190
+ const users = await userService.list(args);
191
+
106
192
  return {
107
193
  content: [{
108
194
  type: 'text',
109
- text: `Result: ${params.param}`
195
+ text: JSON.stringify(users)
110
196
  }]
111
197
  };
112
198
  }
113
199
  );
200
+
201
+ logger.info('Users feature registered');
114
202
  },
115
203
 
116
204
  async initialize(): Promise<void> {
117
- // Inicialización opcional
118
- console.log('Feature initialized');
205
+ logger.info('Users feature initialized');
119
206
  },
120
207
 
121
208
  async cleanup(): Promise<void> {
122
- // Cleanup opcional
123
- console.log('Feature cleaned up');
209
+ logger.info('Users feature cleaned up');
124
210
  }
125
211
  };
126
212
  ```
127
213
 
128
- ### 3. Configuración (.env)
214
+ ### Registrar Features
215
+
216
+ ```typescript
217
+ class MyMcpServer extends McpBaseServer {
218
+ protected async registerFeatures(): Promise<void> {
219
+ this.registerFeature('users', usersFeature);
220
+ this.registerFeature('products', productsFeature);
221
+ this.registerFeature('orders', ordersFeature);
222
+
223
+ logger.info('All features registered');
224
+ }
225
+ }
226
+ ```
227
+
228
+ ## 🔐 Autenticación
229
+
230
+ ### Middleware de Autenticación
231
+
232
+ ```typescript
233
+ import { createAuthMiddleware } from 'apprecio-mcp-base';
234
+
235
+ // Crear middleware
236
+ const auth = createAuthMiddleware({
237
+ apiKey: process.env.API_KEY,
238
+ enabled: process.env.AUTH_ENABLED !== 'false'
239
+ });
240
+
241
+ // Usar en Express
242
+ app.get('/health', handler); // Público
243
+
244
+ app.use('/sse', auth); // Protegido
245
+ app.post('/sse', handler);
246
+ ```
247
+
248
+ ### Usar Token en Features
249
+
250
+ ```typescript
251
+ mcpServer.tool('secure_action', schema, async (args, extra) => {
252
+ // Extraer token
253
+ const req = extra as any;
254
+ const token = req?.requestInfo?.headers?.authorization;
255
+
256
+ if (!token) {
257
+ throw new Error('Unauthorized');
258
+ }
259
+
260
+ // Validar y usar token
261
+ const isValid = await validateToken(token);
262
+ if (!isValid) {
263
+ throw new Error('Invalid token');
264
+ }
265
+
266
+ // Procesar acción
267
+ return { content: [{ type: 'text', text: 'Success' }] };
268
+ });
269
+ ```
270
+
271
+ ## 📝 Configuración
272
+
273
+ ### Variables de Entorno
129
274
 
130
275
  ```env
131
276
  # Authentication
132
- API_KEY=your-secret-api-key
277
+ API_KEY=your-secret-key-here
278
+ AUTH_ENABLED=false
133
279
 
134
- # Database
280
+ # Database (opcional)
135
281
  MONGODB_URI=mongodb://localhost:27017/mydb
136
282
 
137
283
  # Server
@@ -152,150 +298,359 @@ RATE_LIMIT_WINDOW_MS=900000
152
298
  RATE_LIMIT_MAX_REQUESTS=100
153
299
  ```
154
300
 
155
- ## 📚 API Reference
156
-
157
- ### McpBaseServer
158
-
159
- Clase abstracta base para servidores MCP.
301
+ ### Acceder a Configuración
160
302
 
161
303
  ```typescript
162
- abstract class McpBaseServer {
163
- constructor(options: ServerOptions)
164
-
165
- // Métodos abstractos (deben implementarse)
166
- protected abstract registerFeatures(): Promise<void>
167
-
168
- // Hooks opcionales
169
- protected async onBeforeStart?(): Promise<void>
170
- protected async onBeforeShutdown?(): Promise<void>
171
-
172
- // Métodos públicos
173
- public getMcpServer(): McpServer
174
- public getConfig(): BaseConfig
175
- public getFeatures(): Map<string, FeatureModule>
176
-
177
- // Método para iniciar el servidor
178
- async start(httpServer: HttpServer, port: number): Promise<void>
304
+ class MyMcpServer extends McpBaseServer {
305
+ protected async registerFeatures(): Promise<void> {
306
+ // Acceder a config
307
+ const config = this.config;
308
+
309
+ logger.info(`Server port: ${config.ssePort}`);
310
+ logger.info(`MongoDB URI: ${config.mongodbUri}`);
311
+ logger.info(`Log level: ${config.logLevel}`);
312
+ }
179
313
  }
180
314
  ```
181
315
 
182
- ### BaseConfig
316
+ ## 🗄️ Database Connectors
183
317
 
184
- Sistema de configuración con validación.
318
+ ### MongoDB
185
319
 
186
320
  ```typescript
187
- class BaseConfig {
188
- constructor(envPath?: string)
189
-
190
- // Getters
191
- get apiKey(): string
192
- get mongodbUri(): string | undefined
193
- get ssePort(): number
194
- get logLevel(): 'debug' | 'info' | 'warn' | 'error'
195
- // ... más getters
196
-
197
- // Métodos
198
- getAll(): BaseConfigType
199
- extend<T>(customConfig: T): BaseConfigType & T
200
- }
201
- ```
202
-
203
- ### Logger
204
-
205
- Logger centralizado con Winston.
321
+ import { createMongoDBConnector } from 'apprecio-mcp-base';
206
322
 
207
- ```typescript
208
- import { logger, createChildLogger, setLogLevel } from '@apprecio/mcp-base';
323
+ // Crear conector
324
+ const db = createMongoDBConnector('mongodb://localhost:27017/db');
209
325
 
210
- // Uso básico
211
- logger.info('Message');
212
- logger.error('Error', error);
213
- logger.debug('Debug info', { metadata });
326
+ // Conectar
327
+ await db.connect();
214
328
 
215
- // Logger con contexto
216
- const childLogger = createChildLogger('MyFeature');
217
- childLogger.info('Feature message');
329
+ // Usar mongoose
330
+ const connection = db.getConnection();
331
+ const User = connection.model('User', userSchema);
218
332
 
219
- // Cambiar nivel dinámicamente
220
- setLogLevel('debug');
333
+ // Desconectar
334
+ await db.disconnect();
221
335
  ```
222
336
 
223
- ### Middlewares
337
+ ### Redis
224
338
 
225
339
  ```typescript
226
- import { createAuthMiddleware } from '@apprecio/mcp-base';
340
+ import { createRedisConnector } from 'apprecio-mcp-base';
341
+
342
+ // Crear conector
343
+ const redis = createRedisConnector('redis://localhost:6379');
344
+
345
+ // Conectar
346
+ await redis.connect();
227
347
 
228
- const authMiddleware = createAuthMiddleware(apiKey);
348
+ // Usar
349
+ const client = redis.getClient();
350
+ await client.set('key', 'value');
351
+ const value = await client.get('key');
229
352
 
230
- app.use('/protected', authMiddleware.authenticate);
231
- app.use('/optional', authMiddleware.optionalAuth);
353
+ // Desconectar
354
+ await redis.disconnect();
232
355
  ```
233
356
 
234
- ### Database Connectors
357
+ ## 📊 Logger
235
358
 
236
359
  ```typescript
237
- import { createMongoDBConnector } from '@apprecio/mcp-base';
360
+ import { logger, createChildLogger, setLogLevel } from 'apprecio-mcp-base';
238
361
 
239
- const db = createMongoDBConnector('mongodb://localhost:27017/db');
240
- await db.connect();
362
+ // Uso básico
363
+ logger.info('Server started');
364
+ logger.error('Error occurred', error);
365
+ logger.debug('Debug info', { metadata });
366
+ logger.warn('Warning message');
241
367
 
242
- // Usar mongoose normalmente
243
- const connection = db.getConnection();
368
+ // Logger con contexto
369
+ const featureLogger = createChildLogger('UsersFeature');
370
+ featureLogger.info('User created', { userId: 123 });
244
371
 
245
- await db.disconnect();
372
+ // Cambiar nivel dinámicamente
373
+ setLogLevel('debug');
246
374
  ```
247
375
 
248
- ## 🔧 Desarrollo
376
+ ## 🛠️ Desarrollo
249
377
 
250
- ### Estructura del proyecto base
378
+ ### Estructura del Proyecto
251
379
 
252
380
  ```
253
- @apprecio/mcp-base/
381
+ apprecio-mcp-base/
382
+ ├── cli/ # CLI generator
383
+ │ ├── generators/
384
+ │ │ ├── init-generator.ts # Generador de proyectos
385
+ │ │ ├── feature-generator.ts # Generador de features
386
+ │ │ ├── service-generator.ts # Generador de services
387
+ │ │ ├── router-generator.ts # Generador de routers
388
+ │ │ └── main-updater.ts # Actualizador de main.ts
389
+ │ ├── templates/
390
+ │ │ ├── post-install.sh
391
+ │ │ └── check-permissions.sh
392
+ │ └── generate-feature.ts # Entry point del CLI
254
393
  ├── src/
255
394
  │ ├── core/ # Núcleo del framework
256
395
  │ │ ├── McpBaseServer.ts # Clase base
257
- │ │ ├── config.ts # Configuración
258
- │ │ ├── logger.ts # Logger
396
+ │ │ ├── config.ts # Sistema de configuración
397
+ │ │ ├── logger.ts # Logger centralizado
259
398
  │ │ └── types.ts # Tipos compartidos
260
399
  │ ├── middleware/ # Middlewares Express
400
+ │ │ ├── auth.ts # Autenticación Bearer
401
+ │ │ ├── rate-limit.ts # Rate limiting
402
+ │ │ └── cors.ts # CORS config
261
403
  │ ├── database/ # Conectores DB
404
+ │ │ ├── mongodb.ts
405
+ │ │ └── redis.ts
262
406
  │ ├── server/ # Server builders
407
+ │ │ └── express.ts
263
408
  │ ├── utils/ # Utilidades
409
+ │ │ ├── port.ts # Port finder
410
+ │ │ └── shutdown.ts # Graceful shutdown
264
411
  │ └── index.ts # Exports principales
412
+ ├── examples/ # Ejemplos de uso
265
413
  ├── package.json
266
414
  ├── tsconfig.json
267
415
  └── README.md
268
416
  ```
269
417
 
270
- ### Build
418
+ ### Scripts Disponibles
419
+
420
+ ```bash
421
+ # Build del paquete
422
+ npm run build
423
+
424
+ # Build con watch
425
+ npm run build:watch
426
+
427
+ # Build CLI
428
+ npm run build:cli
429
+
430
+ # Build todo
431
+ npm run build:all
432
+
433
+ # Link global
434
+ npm link
435
+
436
+ # Generate feature (si estás en un proyecto)
437
+ npm run generate
438
+ ```
439
+
440
+ ### Desarrollo del CLI
271
441
 
272
442
  ```bash
443
+ # Build CLI
444
+ npm run build:cli
445
+
446
+ # Link globalmente
447
+ npm link
448
+
449
+ # Usar en cualquier lugar
450
+ mcp-generate init
451
+ ```
452
+
453
+ ## 🚀 Setup para Desarrollo
454
+
455
+ ### 1. Setup Inicial
456
+
457
+ ```bash
458
+ # Clone repo
459
+ git clone https://github.com/apprecio/apprecio-mcp-base.git
460
+ cd apprecio-mcp-base
461
+
462
+ # Instalar dependencias
463
+ npm install
464
+
465
+ # Build
273
466
  npm run build
467
+
468
+ # Link global
469
+ npm link
274
470
  ```
275
471
 
276
- ### Desarrollo
472
+ ### 2. Crear Proyecto de Prueba
277
473
 
278
474
  ```bash
475
+ # Generar proyecto
476
+ mcp-generate init
477
+
478
+ # Configurar
479
+ cd my-test-project
480
+ npm install
481
+ npm link apprecio-mcp-base
482
+
483
+ # Ejecutar
279
484
  npm run dev
280
485
  ```
281
486
 
282
- ## 🎨 Ejemplos Completos
487
+ ### 3. Desarrollo Iterativo
283
488
 
284
- Ver el directorio `examples/` para ejemplos completos de:
489
+ ```bash
490
+ # Terminal 1: Watch mode en apprecio-mcp-base
491
+ cd apprecio-mcp-base
492
+ npm run build:watch
493
+
494
+ # Terminal 2: Tu proyecto
495
+ cd my-test-project
496
+ npm run dev
497
+
498
+ # Los cambios en apprecio-mcp-base se reflejan automáticamente
499
+ ```
500
+
501
+ ## 📚 API Reference
502
+
503
+ ### McpBaseServer
504
+
505
+ ```typescript
506
+ abstract class McpBaseServer {
507
+ constructor(options: ServerOptions)
508
+
509
+ // Métodos abstractos
510
+ protected abstract registerFeatures(): Promise<void>
511
+
512
+ // Hooks opcionales
513
+ protected async onBeforeStart?(): Promise<void>
514
+ protected async onBeforeShutdown?(): Promise<void>
515
+
516
+ // Métodos públicos
517
+ getMcpServer(): McpServer
518
+ getConfig(): BaseConfig
519
+ getFeatures(): Map<string, FeatureModule>
520
+
521
+ // Lifecycle
522
+ async start(httpServer: HttpServer, transport: Transport, port: number): Promise<void>
523
+ }
524
+ ```
525
+
526
+ ### FeatureModule
527
+
528
+ ```typescript
529
+ interface FeatureModule {
530
+ name: string;
531
+ register(mcpServer: McpServer): void;
532
+ initialize?(): Promise<void>;
533
+ cleanup?(): Promise<void>;
534
+ }
535
+ ```
536
+
537
+ ### BaseConfig
538
+
539
+ ```typescript
540
+ class BaseConfig {
541
+ get apiKey(): string
542
+ get mongodbUri(): string | undefined
543
+ get ssePort(): number
544
+ get logLevel(): 'debug' | 'info' | 'warn' | 'error'
545
+ get mcpTimeout(): number
546
+ get sseTimeout(): number
547
+ get corsAllowOrigin(): string
548
+ get rateLimitWindowMs(): number
549
+ get rateLimitMaxRequests(): number
550
+ }
551
+ ```
552
+
553
+ ## 🆘 Troubleshooting
554
+
555
+ ### Error: Cannot find module 'apprecio-mcp-base'
556
+
557
+ ```bash
558
+ # Verificar link global
559
+ npm list -g apprecio-mcp-base --depth=0
560
+
561
+ # Si no está linkeado:
562
+ cd apprecio-mcp-base
563
+ npm run build
564
+ npm link
565
+
566
+ # En tu proyecto:
567
+ npm link apprecio-mcp-base
568
+ ```
569
+
570
+ ### Error: EACCES (Permission Denied)
571
+
572
+ ```bash
573
+ # En el proyecto generado
574
+ ./check-permissions.sh
575
+
576
+ # Arreglar permisos
577
+ sudo chown -R $(whoami) .
578
+ chmod -R 755 .
579
+ ```
580
+
581
+ ### Error: npm cache EACCES
582
+
583
+ ```bash
584
+ # Arreglar caché de npm
585
+ sudo chown -R $(whoami) ~/.npm
586
+ npm cache clean --force
587
+ npm install
588
+ ```
589
+
590
+ ### Cambios no se reflejan
591
+
592
+ ```bash
593
+ # Rebuild apprecio-mcp-base
594
+ cd apprecio-mcp-base
595
+ npm run build
596
+
597
+ # Los proyectos linkeados ven cambios automáticamente
598
+ ```
599
+
600
+ ## 💡 Best Practices
601
+
602
+ ### ✅ DO:
603
+
604
+ - Usa el CLI para generar proyectos y features
605
+ - Mantén features pequeños y enfocados
606
+ - Usa el logger en lugar de console.log
607
+ - Implementa cleanup en features con recursos
608
+ - Usa TypeScript strict mode
609
+ - Valida inputs con Zod
610
+
611
+ ### ❌ DON'T:
612
+
613
+ - No uses `sudo npm install`
614
+ - No modifies archivos generados manualmente
615
+ - No uses console.log en producción
616
+ - No olvides implementar cleanup
617
+ - No hardcodees configuración
618
+
619
+ ## 🎯 Ejemplos
620
+
621
+ Ver `examples/` para:
285
622
 
286
623
  - Servidor MCP simple
287
624
  - Servidor con MongoDB
288
625
  - Servidor con múltiples features
289
- - Servidor con autenticación personalizada
626
+ - Feature con autenticación
627
+ - Feature con validación Zod
290
628
 
291
- ## 📝 Licencia
629
+ ## 📖 Documentación
292
630
 
293
- MIT
631
+ - [Model Context Protocol](https://modelcontextprotocol.io) - Especificación MCP
632
+ - [TypeScript](https://www.typescriptlang.org/) - TypeScript docs
633
+ - [Winston](https://github.com/winstonjs/winston) - Logger docs
634
+ - [Zod](https://zod.dev/) - Validation docs
294
635
 
295
636
  ## 🤝 Contribuir
296
637
 
297
638
  1. Fork el proyecto
298
- 2. Crea una branch para tu feature
299
- 3. Commit tus cambios
300
- 4. Push a la branch
639
+ 2. Crea una branch: `git checkout -b feature/amazing-feature`
640
+ 3. Commit cambios: `git commit -m 'Add amazing feature'`
641
+ 4. Push: `git push origin feature/amazing-feature`
301
642
  5. Abre un Pull Request
643
+
644
+ ## 📄 Licencia
645
+
646
+ MIT © Apprecio
647
+
648
+ ## 🔗 Links
649
+
650
+ - [GitHub](https://github.com/apprecio/apprecio-mcp-base)
651
+ - [npm](https://www.npmjs.com/package/apprecio-mcp-base)
652
+ - [Issues](https://github.com/apprecio/apprecio-mcp-base/issues)
653
+
654
+ ---
655
+
656
+ **Hecho con ❤️ por el equipo de Apprecio**
@@ -12,9 +12,6 @@ program
12
12
  .name('mcp-generate')
13
13
  .description('CLI para generar proyectos y features MCP automáticamente')
14
14
  .version('1.2.0');
15
- // ==========================================
16
- // COMANDO: init
17
- // ==========================================
18
15
  program
19
16
  .command('init')
20
17
  .description('Inicializa un nuevo proyecto MCP con estructura completa')
@@ -87,11 +84,112 @@ program
87
84
  apiBaseUrl: answers.apiBaseUrl
88
85
  });
89
86
  console.log(chalk.green('\n✅ ¡Proyecto creado exitosamente!\n'));
87
+ // Preguntar si quiere instalar dependencias automáticamente
88
+ const installAnswer = await inquirer.prompt([
89
+ {
90
+ type: 'confirm',
91
+ name: 'installDeps',
92
+ message: '¿Instalar dependencias ahora? (npm install)',
93
+ default: true
94
+ }
95
+ ]);
96
+ if (installAnswer.installDeps) {
97
+ console.log(chalk.yellow('\n📦 Instalando dependencias (esto puede tomar unos minutos)...\n'));
98
+ try {
99
+ const { execSync } = await import('child_process');
100
+ // Verificar y limpiar caché de npm si hay problemas de permisos
101
+ try {
102
+ console.log(chalk.gray('Verificando caché de npm...\n'));
103
+ execSync('npm cache verify', {
104
+ stdio: 'pipe',
105
+ encoding: 'utf-8'
106
+ });
107
+ }
108
+ catch (cacheError) {
109
+ // Si hay error de permisos en caché, intentar limpiar
110
+ if (cacheError.message.includes('EACCES')) {
111
+ console.log(chalk.yellow('⚠️ Detectado problema de permisos en caché de npm\n'));
112
+ console.log(chalk.gray('Intentando limpiar caché...\n'));
113
+ try {
114
+ // Intentar limpiar caché sin sudo primero
115
+ execSync('npm cache clean --force', {
116
+ stdio: 'pipe',
117
+ encoding: 'utf-8'
118
+ });
119
+ console.log(chalk.green('✅ Caché limpiado\n'));
120
+ }
121
+ catch (cleanError) {
122
+ console.log(chalk.yellow('⚠️ No se pudo limpiar caché automáticamente\n'));
123
+ console.log(chalk.white('Ejecuta manualmente:\n'));
124
+ console.log(chalk.cyan(' sudo chown -R $(whoami) ~/.npm\n'));
125
+ console.log(chalk.cyan(' npm cache clean --force\n'));
126
+ }
127
+ }
128
+ }
129
+ // Ejecutar npm install de forma síncrona para esperar a que termine
130
+ execSync('sudo npm install', {
131
+ cwd: answers.projectPath,
132
+ stdio: 'inherit', // Muestra el output en tiempo real
133
+ encoding: 'utf-8'
134
+ });
135
+ console.log(chalk.green('\n✅ Dependencias instaladas correctamente\n'));
136
+ // Preguntar si quiere linkear apprecio-mcp-base
137
+ const linkAnswer = await inquirer.prompt([
138
+ {
139
+ type: 'confirm',
140
+ name: 'linkBase',
141
+ message: '¿Linkear apprecio-mcp-base local? (npm link apprecio-mcp-base)',
142
+ default: true
143
+ }
144
+ ]);
145
+ if (linkAnswer.linkBase) {
146
+ console.log(chalk.yellow('\n🔗 Linkeando apprecio-mcp-base...\n'));
147
+ try {
148
+ execSync('npm link apprecio-mcp-base', {
149
+ cwd: answers.projectPath,
150
+ stdio: 'inherit',
151
+ encoding: 'utf-8'
152
+ });
153
+ console.log(chalk.green('\n✅ apprecio-mcp-base linkeado correctamente\n'));
154
+ }
155
+ catch (linkError) {
156
+ console.log(chalk.yellow('\n⚠️ Error linkeando apprecio-mcp-base'));
157
+ console.log(chalk.white(' Asegúrate de haber ejecutado en apprecio-mcp-base:'));
158
+ console.log(chalk.cyan(' cd apprecio-mcp-base && npm run build && npm link\n'));
159
+ }
160
+ }
161
+ }
162
+ catch (error) {
163
+ console.log(chalk.red('\n❌ Error instalando dependencias:', error.message));
164
+ // Detectar error de permisos de npm
165
+ if (error.message.includes('EACCES') && error.message.includes('.npm')) {
166
+ console.log(chalk.yellow('\n⚠️ Problema de permisos en caché de npm detectado\n'));
167
+ console.log(chalk.white('Solución:\n'));
168
+ console.log(chalk.cyan(' sudo chown -R $(whoami) ~/.npm'));
169
+ console.log(chalk.cyan(' npm cache clean --force'));
170
+ console.log(chalk.cyan(` cd ${answers.projectPath}`));
171
+ console.log(chalk.cyan(' npm install\n'));
172
+ }
173
+ else {
174
+ console.log(chalk.white('\nEjecuta manualmente:'));
175
+ console.log(chalk.cyan(` cd ${answers.projectPath}`));
176
+ console.log(chalk.cyan(' npm install\n'));
177
+ }
178
+ }
179
+ }
90
180
  console.log(chalk.blue.bold('📚 Próximos pasos:\n'));
91
- console.log(chalk.white(`1. cd ${answers.projectPath}`));
92
- console.log(chalk.white(`2. npm install`));
93
- console.log(chalk.white(`3. Edita .env con tu configuración`));
94
- console.log(chalk.white(`4. npm run dev\n`));
181
+ if (!installAnswer.installDeps) {
182
+ console.log(chalk.white(`1. cd ${answers.projectPath}`));
183
+ console.log(chalk.white(`2. npm install`));
184
+ console.log(chalk.white(`3. npm link apprecio-mcp-base`));
185
+ console.log(chalk.white(`4. Edita .env con tu configuración`));
186
+ console.log(chalk.white(`5. npm run dev\n`));
187
+ }
188
+ else {
189
+ console.log(chalk.white(`1. cd ${answers.projectPath}`));
190
+ console.log(chalk.white(`2. Edita .env con tu configuración`));
191
+ console.log(chalk.white(`3. npm run dev\n`));
192
+ }
95
193
  console.log(chalk.blue.bold('🔧 Comandos útiles:\n'));
96
194
  console.log(chalk.white(` npm run generate - Generar nueva feature`));
97
195
  console.log(chalk.white(` npm run dev - Ejecutar en desarrollo`));
@@ -102,52 +200,6 @@ program
102
200
  process.exit(1);
103
201
  }
104
202
  });
105
- program
106
- .command('tool')
107
- .description('Agrega un tool a una feature existente')
108
- .action(async () => {
109
- console.log(chalk.blue.bold('\n🔧 Agregar Tool a Feature\n'));
110
- // Listar features existentes
111
- const featuresPath = path.join(process.cwd(), 'src', 'features');
112
- const features = await fs.readdir(featuresPath);
113
- if (features.length === 0) {
114
- console.log(chalk.red('No hay features disponibles. Crea una primero con: mcp-generate feature'));
115
- process.exit(1);
116
- }
117
- const answers = await inquirer.prompt([
118
- {
119
- type: 'list',
120
- name: 'feature',
121
- message: 'Selecciona la feature:',
122
- choices: features
123
- },
124
- {
125
- type: 'input',
126
- name: 'toolName',
127
- message: 'Nombre del tool (ej: approve_item):',
128
- validate: (input) => {
129
- if (!input)
130
- return 'El nombre es requerido';
131
- if (!/^[a-z_]+$/.test(input)) {
132
- return 'El nombre debe ser snake_case';
133
- }
134
- return true;
135
- }
136
- },
137
- {
138
- type: 'input',
139
- name: 'toolDescription',
140
- message: 'Descripción del tool:',
141
- },
142
- {
143
- type: 'confirm',
144
- name: 'addToService',
145
- message: '¿Agregar método al service?',
146
- default: true
147
- }
148
- ]);
149
- console.log(chalk.green(`\n✅ Tool ${answers.toolName} agregado a ${answers.feature}\n`));
150
- });
151
203
  // ==========================================
152
204
  // COMANDO: feature
153
205
  // ==========================================
@@ -262,5 +314,51 @@ program
262
314
  process.exit(1);
263
315
  }
264
316
  });
317
+ program
318
+ .command('tool')
319
+ .description('Agrega un tool a una feature existente')
320
+ .action(async () => {
321
+ console.log(chalk.blue.bold('\n🔧 Agregar Tool a Feature\n'));
322
+ // Listar features existentes
323
+ const featuresPath = path.join(process.cwd(), 'src', 'features');
324
+ const features = await fs.readdir(featuresPath);
325
+ if (features.length === 0) {
326
+ console.log(chalk.red('No hay features disponibles. Crea una primero con: mcp-generate feature'));
327
+ process.exit(1);
328
+ }
329
+ const answers = await inquirer.prompt([
330
+ {
331
+ type: 'list',
332
+ name: 'feature',
333
+ message: 'Selecciona la feature:',
334
+ choices: features
335
+ },
336
+ {
337
+ type: 'input',
338
+ name: 'toolName',
339
+ message: 'Nombre del tool (ej: approve_item):',
340
+ validate: (input) => {
341
+ if (!input)
342
+ return 'El nombre es requerido';
343
+ if (!/^[a-z_]+$/.test(input)) {
344
+ return 'El nombre debe ser snake_case';
345
+ }
346
+ return true;
347
+ }
348
+ },
349
+ {
350
+ type: 'input',
351
+ name: 'toolDescription',
352
+ message: 'Descripción del tool:',
353
+ },
354
+ {
355
+ type: 'confirm',
356
+ name: 'addToService',
357
+ message: '¿Agregar método al service?',
358
+ default: true
359
+ }
360
+ ]);
361
+ console.log(chalk.green(`\n✅ Tool ${answers.toolName} agregado a ${answers.feature}\n`));
362
+ });
265
363
  program.parse();
266
364
  //# sourceMappingURL=generate-feature.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apprecio-mcp-base",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "Base package for creating Apprecio MCP servers with consistency",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",