morpheus-cli 0.2.6 → 0.2.7

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
@@ -209,7 +209,8 @@ The Morpheus Telegram bot supports several commands for interacting with the age
209
209
  - `/help` - Show available commands
210
210
  - `/zaion` - Show system configurations
211
211
  - `/sati <qnt>` - Show specific memories
212
- - `/restart` - **New!** Restart the Morpheus agent
212
+ - `/restart` - Restart the Morpheus agent
213
+ - `/mcp` or `/mcps` - List registered MCP servers
213
214
 
214
215
  ## Development Setup
215
216
 
@@ -316,6 +317,230 @@ Morpheus supports external tools via **MCP (Model Context Protocol)**. Configure
316
317
 
317
318
  Morpheus exposes several API endpoints for programmatic access to its features:
318
319
 
320
+ ### Health Check Endpoints
321
+
322
+ #### GET `/health`
323
+ Public health check endpoint without authentication.
324
+
325
+ * **Response:**
326
+ ```json
327
+ {
328
+ "status": "healthy",
329
+ "timestamp": "2026-02-05T21:30:00.000Z",
330
+ "uptime": 123.45
331
+ }
332
+ ```
333
+
334
+ #### GET `/api/health`
335
+ Health check endpoint for the API (requires authentication).
336
+
337
+ * **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
338
+ * **Response:**
339
+ ```json
340
+ {
341
+ "status": "healthy",
342
+ "timestamp": "2026-02-05T21:30:00.000Z",
343
+ "uptime": 123.45
344
+ }
345
+ ```
346
+
347
+ ### Status Endpoint
348
+
349
+ #### GET `/api/status`
350
+ Get the current status of the Morpheus agent.
351
+
352
+ * **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
353
+ * **Response:**
354
+ ```json
355
+ {
356
+ "status": "online",
357
+ "uptimeSeconds": 1234.56,
358
+ "pid": 12345,
359
+ "projectVersion": "1.0.0",
360
+ "nodeVersion": "v18.17.0",
361
+ "agentName": "Morpheus",
362
+ "llmProvider": "openai",
363
+ "llmModel": "gpt-4-turbo"
364
+ }
365
+ ```
366
+
367
+ ### Configuration Endpoints
368
+
369
+ #### GET `/api/config`
370
+ Retrieve the current configuration.
371
+
372
+ * **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
373
+ * **Response:**
374
+ ```json
375
+ {
376
+ "agent": {
377
+ "name": "Morpheus",
378
+ "personality": "stoic, wise, and helpful"
379
+ },
380
+ "llm": {
381
+ "provider": "openai",
382
+ "model": "gpt-4-turbo",
383
+ "temperature": 0.7,
384
+ "context_window": 100,
385
+ "api_key": "***"
386
+ },
387
+ "santi": {
388
+ "provider": "openai",
389
+ "model": "gpt-4o",
390
+ "memory_limit": 1000
391
+ },
392
+ "channels": {
393
+ "telegram": {
394
+ "enabled": true,
395
+ "token": "***",
396
+ "allowedUsers": ["123456789"]
397
+ },
398
+ "discord": {
399
+ "enabled": false
400
+ }
401
+ },
402
+ "ui": {
403
+ "enabled": true,
404
+ "port": 3333
405
+ },
406
+ "audio": {
407
+ "enabled": true,
408
+ "apiKey": "***",
409
+ "maxDurationSeconds": 300
410
+ }
411
+ }
412
+ ```
413
+
414
+ #### POST `/api/config`
415
+ Update the configuration.
416
+
417
+ * **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
418
+ * **Body:** Complete configuration object (same structure as GET response).
419
+ * **Response:**
420
+ ```json
421
+ {
422
+ "agent": {
423
+ "name": "Morpheus",
424
+ "personality": "stoic, wise, and helpful"
425
+ },
426
+ "llm": {
427
+ "provider": "openai",
428
+ "model": "gpt-4-turbo",
429
+ "temperature": 0.7,
430
+ "context_window": 100,
431
+ "api_key": "***"
432
+ },
433
+ "santi": {
434
+ "provider": "openai",
435
+ "model": "gpt-4o",
436
+ "memory_limit": 1000
437
+ },
438
+ "channels": {
439
+ "telegram": {
440
+ "enabled": true,
441
+ "token": "***",
442
+ "allowedUsers": ["123456789"]
443
+ },
444
+ "discord": {
445
+ "enabled": false
446
+ }
447
+ },
448
+ "ui": {
449
+ "enabled": true,
450
+ "port": 3333
451
+ },
452
+ "audio": {
453
+ "enabled": true,
454
+ "apiKey": "***",
455
+ "maxDurationSeconds": 300
456
+ }
457
+ }
458
+ ```
459
+
460
+ #### GET `/api/config/sati`
461
+ Retrieve the Sati (long-term memory) configuration.
462
+
463
+ * **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
464
+ * **Response:**
465
+ ```json
466
+ {
467
+ "provider": "openai",
468
+ "model": "gpt-4o",
469
+ "memory_limit": 1000
470
+ }
471
+ ```
472
+
473
+ #### POST `/api/config/sati`
474
+ Update the Sati (long-term memory) configuration.
475
+
476
+ * **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
477
+ * **Body:**
478
+ ```json
479
+ {
480
+ "provider": "openai",
481
+ "model": "gpt-4o",
482
+ "memory_limit": 1000
483
+ }
484
+ ```
485
+ * **Response:**
486
+ ```json
487
+ {
488
+ "success": true
489
+ }
490
+ ```
491
+
492
+ #### DELETE `/api/config/sati`
493
+ Remove the Sati (long-term memory) configuration (falls back to Oracle config).
494
+
495
+ * **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
496
+ * **Response:**
497
+ ```json
498
+ {
499
+ "success": true
500
+ }
501
+ ```
502
+
503
+ ### Statistics Endpoints
504
+
505
+ #### GET `/api/stats/usage`
506
+ Get global token usage statistics.
507
+
508
+ * **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
509
+ * **Response:**
510
+ ```json
511
+ {
512
+ "totalInputTokens": 12345,
513
+ "totalOutputTokens": 6789,
514
+ "totalTokens": 19134
515
+ }
516
+ ```
517
+
518
+ #### GET `/api/stats/usage/grouped`
519
+ Get token usage statistics grouped by provider and model.
520
+
521
+ * **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
522
+ * **Response:**
523
+ ```json
524
+ [
525
+ {
526
+ "provider": "openai",
527
+ "model": "gpt-4-turbo",
528
+ "totalTokens": 12345,
529
+ "inputTokens": 10000,
530
+ "outputTokens": 2345,
531
+ "messageCount": 100
532
+ },
533
+ {
534
+ "provider": "anthropic",
535
+ "model": "claude-3-opus",
536
+ "totalTokens": 6789,
537
+ "inputTokens": 5000,
538
+ "outputTokens": 1789,
539
+ "messageCount": 50
540
+ }
541
+ ]
542
+ ```
543
+
319
544
  ### Sati Memories Endpoints
320
545
 
321
546
  #### GET `/api/sati/memories`
@@ -375,6 +600,174 @@ Archive (soft delete) multiple memories from the Sati agent at once.
375
600
  }
376
601
  ```
377
602
 
603
+ ### MCP Server Endpoints
604
+
605
+ #### GET `/api/mcp/servers`
606
+ List all registered MCP servers.
607
+
608
+ * **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
609
+ * **Response:**
610
+ ```json
611
+ {
612
+ "servers": [
613
+ {
614
+ "name": "coolify",
615
+ "config": {
616
+ "transport": "stdio",
617
+ "command": "npx",
618
+ "args": ["-y", "@coolify/mcp-server"],
619
+ "env": {
620
+ "COOLIFY_URL": "https://app.coolify.io",
621
+ "COOLIFY_TOKEN": "your-token"
622
+ }
623
+ },
624
+ "enabled": true
625
+ },
626
+ {
627
+ "name": "coingecko",
628
+ "config": {
629
+ "transport": "http",
630
+ "url": "https://mcps.mnunes.xyz/coingecko/mcp"
631
+ },
632
+ "enabled": false
633
+ }
634
+ ]
635
+ }
636
+ ```
637
+
638
+ #### POST `/api/mcp/servers`
639
+ Add a new MCP server.
640
+
641
+ * **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
642
+ * **Body:**
643
+ ```json
644
+ {
645
+ "name": "new-server",
646
+ "config": {
647
+ "transport": "stdio",
648
+ "command": "npx",
649
+ "args": ["-y", "@new-mcp-server"],
650
+ "env": {
651
+ "NEW_SERVER_URL": "https://example.com",
652
+ "NEW_SERVER_TOKEN": "your-token"
653
+ }
654
+ }
655
+ }
656
+ ```
657
+ * **Response:**
658
+ ```json
659
+ {
660
+ "ok": true
661
+ }
662
+ ```
663
+
664
+ #### PUT `/api/mcp/servers/:name`
665
+ Update an existing MCP server.
666
+
667
+ * **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
668
+ * **Parameters:** `name` - Name of the server to update.
669
+ * **Body:**
670
+ ```json
671
+ {
672
+ "transport": "stdio",
673
+ "command": "npx",
674
+ "args": ["-y", "@updated-mcp-server"],
675
+ "env": {
676
+ "UPDATED_SERVER_URL": "https://example.com",
677
+ "UPDATED_SERVER_TOKEN": "your-updated-token"
678
+ }
679
+ }
680
+ ```
681
+ * **Response:**
682
+ ```json
683
+ {
684
+ "ok": true
685
+ }
686
+ ```
687
+
688
+ #### DELETE `/api/mcp/servers/:name`
689
+ Delete an MCP server.
690
+
691
+ * **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
692
+ * **Parameters:** `name` - Name of the server to delete.
693
+ * **Response:**
694
+ ```json
695
+ {
696
+ "ok": true
697
+ }
698
+ ```
699
+
700
+ #### PATCH `/api/mcp/servers/:name/toggle`
701
+ Enable or disable an MCP server.
702
+
703
+ * **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
704
+ * **Parameters:** `name` - Name of the server to toggle.
705
+ * **Body:**
706
+ ```json
707
+ {
708
+ "enabled": true
709
+ }
710
+ ```
711
+ * **Response:**
712
+ ```json
713
+ {
714
+ "ok": true
715
+ }
716
+ ```
717
+
718
+ ### Logging Endpoints
719
+
720
+ #### GET `/api/logs`
721
+ List all log files.
722
+
723
+ * **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
724
+ * **Response:**
725
+ ```json
726
+ [
727
+ {
728
+ "name": "morpheus.log",
729
+ "size": 10240,
730
+ "modified": "2026-02-05T21:30:00.000Z"
731
+ },
732
+ {
733
+ "name": "morpheus-2026-02-04.log",
734
+ "size": 20480,
735
+ "modified": "2026-02-04T21:30:00.000Z"
736
+ }
737
+ ]
738
+ ```
739
+
740
+ #### GET `/api/logs/:filename`
741
+ Get the last lines of a specific log file.
742
+
743
+ * **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
744
+ * **Parameters:** `filename` - Name of the log file to read.
745
+ * **Query Parameters:** `limit` - Number of lines to return (default: 50).
746
+ * **Response:**
747
+ ```json
748
+ {
749
+ "lines": [
750
+ "2026-02-05T21:30:00.000Z INFO: Starting Morpheus agent...",
751
+ "2026-02-05T21:30:01.000Z DEBUG: Connected to OpenAI API",
752
+ "2026-02-05T21:30:02.000Z INFO: Telegram bot initialized"
753
+ ]
754
+ }
755
+ ```
756
+
757
+ ### Control Endpoints
758
+
759
+ #### POST `/api/restart`
760
+ Restart the Morpheus agent.
761
+
762
+ * **Authentication:** Requires `Authorization` header with the password set in `THE_ARCHITECT_PASS`.
763
+ * **Response:**
764
+ ```json
765
+ {
766
+ "success": true,
767
+ "message": "Restart initiated. Process will shut down and restart shortly."
768
+ }
769
+ ```
770
+
378
771
  ## Testing
379
772
 
380
773
  We use **Vitest** for testing.
@@ -11,6 +11,7 @@ import { Telephonist } from '../runtime/telephonist.js';
11
11
  import { readPid, isProcessRunning, checkStalePid } from '../runtime/lifecycle.js';
12
12
  import { SQLiteChatMessageHistory } from '../runtime/memory/sqlite.js';
13
13
  import { SatiRepository } from '../runtime/memory/sati/repository.js';
14
+ import { MCPManager } from '../config/mcp-manager.js';
14
15
  export class TelegramAdapter {
15
16
  bot = null;
16
17
  isConnected = false;
@@ -215,6 +216,10 @@ export class TelegramAdapter {
215
216
  case '/restart':
216
217
  await this.handleRestartCommand(ctx, user);
217
218
  break;
219
+ case '/mcp':
220
+ case '/mcps':
221
+ await this.handleMcpListCommand(ctx, user);
222
+ break;
218
223
  default:
219
224
  await this.handleDefaultCommand(ctx, user, command);
220
225
  }
@@ -333,7 +338,7 @@ How can I assist you today?`;
333
338
  async handleDefaultCommand(ctx, user, command) {
334
339
  const prompt = `O usuário envio o comando: ${command},
335
340
  Não entendemos o comando
336
- temos os seguintes comandos disponíveis: /start, /status, /doctor, /stats, /help, /zaion, /sati <qnt>, /restart
341
+ temos os seguintes comandos disponíveis: /start, /status, /doctor, /stats, /help, /zaion, /sati <qnt>, /restart, /mcp, /mcps
337
342
  Identifique se ele talvez tenha errado o comando e pergunte se ele não quis executar outro comando.
338
343
  Só faça isso agora.`;
339
344
  let response = await this.oracle.chat(prompt);
@@ -354,8 +359,9 @@ How can I assist you today?`;
354
359
  /zaion - Show system configurations
355
360
  /sati <qnt> - Show specific memories
356
361
  /restart - Restart the Morpheus agent
362
+ /mcp or /mcps - List registered MCP servers
357
363
 
358
- How can I assist you today?`;
364
+ How can I assist you today? `;
359
365
  await ctx.reply(helpMessage, { parse_mode: 'Markdown' });
360
366
  }
361
367
  async handleZaionCommand(ctx, user) {
@@ -473,4 +479,36 @@ How can I assist you today?`;
473
479
  this.display.log(`Error checking restart notification: ${error.message}`, { source: 'Telegram', level: 'error' });
474
480
  }
475
481
  }
482
+ async handleMcpListCommand(ctx, user) {
483
+ try {
484
+ const servers = await MCPManager.listServers();
485
+ if (servers.length === 0) {
486
+ await ctx.reply('*No MCP Servers Configured*\n\nThere are currently no MCP servers configured in the system.', { parse_mode: 'Markdown' });
487
+ return;
488
+ }
489
+ let response = `*MCP Servers (${servers.length})*\n\n`;
490
+ servers.forEach((server, index) => {
491
+ const status = server.enabled ? '✅ Enabled' : '❌ Disabled';
492
+ const transport = server.config.transport.toUpperCase();
493
+ response += `*${index + 1}. ${server.name}*\n`;
494
+ response += `Status: ${status}\n`;
495
+ response += `Transport: ${transport}\n`;
496
+ if (server.config.transport === 'stdio') {
497
+ response += `Command: \`${server.config.command}\`\n`;
498
+ if (server.config.args && server.config.args.length > 0) {
499
+ response += `Args: \`${server.config.args.join(' ')}\`\n`;
500
+ }
501
+ }
502
+ else if (server.config.transport === 'http') {
503
+ response += `URL: \`${server.config.url}\`\n`;
504
+ }
505
+ response += '\n';
506
+ });
507
+ await ctx.reply(response, { parse_mode: 'Markdown' });
508
+ }
509
+ catch (error) {
510
+ this.display.log('Error listing MCP servers: ' + (error instanceof Error ? error.message : String(error)), { source: 'Telegram', level: 'error' });
511
+ await ctx.reply('An error occurred while retrieving the list of MCP servers. Please check the logs for more details.', { parse_mode: 'Markdown' });
512
+ }
513
+ }
476
514
  }