|
26 | 26 | <a href="README.es.md">Español</a>
|
27 | 27 | </p>
|
28 | 28 |
|
| 29 | +<p align="center"> |
| 30 | + <img src="docs/watch.gif" alt="Laravel MCP Server Demo" height="200"> |
| 31 | +</p> |
| 32 | + |
29 | 33 | ## ⚠️ Información de Versión y Cambios Disruptivos
|
30 | 34 |
|
31 | 35 | ### Cambios en v1.3.0 (Actual)
|
@@ -698,6 +702,281 @@ class WelcomePrompt extends Prompt
|
698 | 702 |
|
699 | 703 | Los prompts pueden embeber recursos y devolver secuencias de mensajes para guiar un LLM. Ve la documentación oficial para ejemplos avanzados y mejores prácticas.
|
700 | 704 |
|
| 705 | +### Trabajando con Notificaciones |
| 706 | + |
| 707 | +Las notificaciones son mensajes fire-and-forget de clientes MCP que siempre devuelven HTTP 202 Accepted sin cuerpo de respuesta. Son perfectas para logging, seguimiento de progreso, manejo de eventos y activación de procesos en segundo plano sin bloquear al cliente. |
| 708 | + |
| 709 | +#### Creando Manejadores de Notificaciones |
| 710 | + |
| 711 | +**Uso básico del comando:** |
| 712 | + |
| 713 | +```bash |
| 714 | +php artisan make:mcp-notification ProgressHandler --method=notifications/progress |
| 715 | +``` |
| 716 | + |
| 717 | +**Características avanzadas del comando:** |
| 718 | + |
| 719 | +```bash |
| 720 | +# Modo interactivo - solicita método si no se especifica |
| 721 | +php artisan make:mcp-notification MyHandler |
| 722 | + |
| 723 | +# Manejo automático de prefijo de método |
| 724 | +php artisan make:mcp-notification StatusHandler --method=status # se convierte en notifications/status |
| 725 | + |
| 726 | +# Normalización de nombre de clase |
| 727 | +php artisan make:mcp-notification "user activity" # se convierte en UserActivityHandler |
| 728 | +``` |
| 729 | + |
| 730 | +El comando proporciona: |
| 731 | +- **Solicitud interactiva de método** cuando no se especifica `--method` |
| 732 | +- **Guía de registro automático** con código listo para copiar y pegar |
| 733 | +- **Ejemplos de prueba incorporados** con comandos curl |
| 734 | +- **Instrucciones de uso completas** y casos de uso comunes |
| 735 | + |
| 736 | +#### Arquitectura de Manejador de Notificaciones |
| 737 | + |
| 738 | +Cada manejador de notificaciones debe implementar la clase abstracta `NotificationHandler`: |
| 739 | + |
| 740 | +```php |
| 741 | +abstract class NotificationHandler |
| 742 | +{ |
| 743 | + // Requerido: Tipo de mensaje (usualmente ProcessMessageType::HTTP) |
| 744 | + protected const MESSAGE_TYPE = ProcessMessageType::HTTP; |
| 745 | + |
| 746 | + // Requerido: El método de notificación a manejar |
| 747 | + protected const HANDLE_METHOD = 'notifications/your_method'; |
| 748 | + |
| 749 | + // Requerido: Ejecutar la lógica de notificación |
| 750 | + abstract public function execute(?array $params = null): void; |
| 751 | +} |
| 752 | +``` |
| 753 | + |
| 754 | +**Componentes arquitectónicos clave:** |
| 755 | + |
| 756 | +- **`MESSAGE_TYPE`**: Usualmente `ProcessMessageType::HTTP` para notificaciones estándar |
| 757 | +- **`HANDLE_METHOD`**: El método JSON-RPC que procesa este manejador (debe comenzar con `notifications/`) |
| 758 | +- **`execute()`**: Contiene tu lógica de notificación - devuelve void (no se envía respuesta) |
| 759 | +- **Validación del constructor**: Valida automáticamente que las constantes requeridas estén definidas |
| 760 | + |
| 761 | +#### Manejadores de Notificaciones Incorporados |
| 762 | + |
| 763 | +El paquete incluye cuatro manejadores pre-construidos para escenarios MCP comunes: |
| 764 | + |
| 765 | +**1. InitializedHandler (`notifications/initialized`)** |
| 766 | +- **Propósito**: Procesa confirmaciones de inicialización del cliente después de handshake exitoso |
| 767 | +- **Parámetros**: Información y capacidades del cliente |
| 768 | +- **Uso**: Seguimiento de sesiones, logging de cliente, eventos de inicialización |
| 769 | + |
| 770 | +**2. ProgressHandler (`notifications/progress`)** |
| 771 | +- **Propósito**: Maneja actualizaciones de progreso para operaciones de larga duración |
| 772 | +- **Parámetros**: |
| 773 | + - `progressToken` (string): Identificador único para la operación |
| 774 | + - `progress` (number): Valor de progreso actual |
| 775 | + - `total` (number, opcional): Valor total de progreso para cálculo de porcentaje |
| 776 | +- **Uso**: Seguimiento de progreso en tiempo real, monitoreo de cargas, finalización de tareas |
| 777 | + |
| 778 | +**3. CancelledHandler (`notifications/cancelled`)** |
| 779 | +- **Propósito**: Procesa notificaciones de cancelación de solicitudes |
| 780 | +- **Parámetros**: |
| 781 | + - `requestId` (string): ID de la solicitud a cancelar |
| 782 | + - `reason` (string, opcional): Razón de cancelación |
| 783 | +- **Uso**: Terminación de trabajos en segundo plano, limpieza de recursos, aborto de operaciones |
| 784 | + |
| 785 | +**4. MessageHandler (`notifications/message`)** |
| 786 | +- **Propósito**: Maneja mensajes generales de logging y comunicación |
| 787 | +- **Parámetros**: |
| 788 | + - `level` (string): Nivel de log (info, warning, error, debug) |
| 789 | + - `message` (string): El contenido del mensaje |
| 790 | + - `logger` (string, opcional): Nombre del logger |
| 791 | +- **Uso**: Logging del lado del cliente, depuración, comunicación general |
| 792 | + |
| 793 | +#### Ejemplos de Manejadores para Escenarios Comunes |
| 794 | + |
| 795 | +```php |
| 796 | +// Seguimiento de progreso de carga de archivos |
| 797 | +class UploadProgressHandler extends NotificationHandler |
| 798 | +{ |
| 799 | + protected const MESSAGE_TYPE = ProcessMessageType::HTTP; |
| 800 | + protected const HANDLE_METHOD = 'notifications/upload_progress'; |
| 801 | + |
| 802 | + public function execute(?array $params = null): void |
| 803 | + { |
| 804 | + $token = $params['progressToken'] ?? null; |
| 805 | + $progress = $params['progress'] ?? 0; |
| 806 | + $total = $params['total'] ?? 100; |
| 807 | + |
| 808 | + if ($token) { |
| 809 | + Cache::put("upload_progress_{$token}", [ |
| 810 | + 'progress' => $progress, |
| 811 | + 'total' => $total, |
| 812 | + 'percentage' => $total ? round(($progress / $total) * 100, 2) : 0, |
| 813 | + 'updated_at' => now() |
| 814 | + ], 3600); |
| 815 | + |
| 816 | + // Transmitir actualización en tiempo real |
| 817 | + broadcast(new UploadProgressUpdated($token, $progress, $total)); |
| 818 | + } |
| 819 | + } |
| 820 | +} |
| 821 | + |
| 822 | +// Actividad de usuario y logging de auditoría |
| 823 | +class UserActivityHandler extends NotificationHandler |
| 824 | +{ |
| 825 | + protected const MESSAGE_TYPE = ProcessMessageType::HTTP; |
| 826 | + protected const HANDLE_METHOD = 'notifications/user_activity'; |
| 827 | + |
| 828 | + public function execute(?array $params = null): void |
| 829 | + { |
| 830 | + UserActivity::create([ |
| 831 | + 'user_id' => $params['userId'] ?? null, |
| 832 | + 'action' => $params['action'] ?? 'unknown', |
| 833 | + 'resource' => $params['resource'] ?? null, |
| 834 | + 'ip_address' => request()->ip(), |
| 835 | + 'user_agent' => request()->userAgent(), |
| 836 | + 'metadata' => $params['metadata'] ?? [], |
| 837 | + 'created_at' => now() |
| 838 | + ]); |
| 839 | + |
| 840 | + // Activar alertas de seguridad para acciones sensibles |
| 841 | + if (in_array($params['action'] ?? '', ['delete', 'export', 'admin_access'])) { |
| 842 | + SecurityAlert::dispatch($params); |
| 843 | + } |
| 844 | + } |
| 845 | +} |
| 846 | + |
| 847 | +// Activación de tareas en segundo plano |
| 848 | +class TaskTriggerHandler extends NotificationHandler |
| 849 | +{ |
| 850 | + protected const MESSAGE_TYPE = ProcessMessageType::HTTP; |
| 851 | + protected const HANDLE_METHOD = 'notifications/trigger_task'; |
| 852 | + |
| 853 | + public function execute(?array $params = null): void |
| 854 | + { |
| 855 | + $taskType = $params['taskType'] ?? null; |
| 856 | + $taskData = $params['data'] ?? []; |
| 857 | + |
| 858 | + match ($taskType) { |
| 859 | + 'send_email' => SendEmailJob::dispatch($taskData), |
| 860 | + 'generate_report' => GenerateReportJob::dispatch($taskData), |
| 861 | + 'sync_data' => DataSyncJob::dispatch($taskData), |
| 862 | + 'cleanup' => CleanupJob::dispatch($taskData), |
| 863 | + default => Log::warning("Unknown task type: {$taskType}") |
| 864 | + }; |
| 865 | + } |
| 866 | +} |
| 867 | +``` |
| 868 | + |
| 869 | +#### Registrando Manejadores de Notificaciones |
| 870 | + |
| 871 | +**En tu proveedor de servicios:** |
| 872 | + |
| 873 | +```php |
| 874 | +// En AppServiceProvider o proveedor de servicios MCP dedicado |
| 875 | +public function boot() |
| 876 | +{ |
| 877 | + $server = app(MCPServer::class); |
| 878 | + |
| 879 | + // Registrar manejadores incorporados (opcional - se registran por defecto) |
| 880 | + $server->registerNotificationHandler(new InitializedHandler()); |
| 881 | + $server->registerNotificationHandler(new ProgressHandler()); |
| 882 | + $server->registerNotificationHandler(new CancelledHandler()); |
| 883 | + $server->registerNotificationHandler(new MessageHandler()); |
| 884 | + |
| 885 | + // Registrar manejadores personalizados |
| 886 | + $server->registerNotificationHandler(new UploadProgressHandler()); |
| 887 | + $server->registerNotificationHandler(new UserActivityHandler()); |
| 888 | + $server->registerNotificationHandler(new TaskTriggerHandler()); |
| 889 | +} |
| 890 | +``` |
| 891 | + |
| 892 | +#### Probando Notificaciones |
| 893 | + |
| 894 | +**Usando curl para probar manejadores de notificaciones:** |
| 895 | + |
| 896 | +```bash |
| 897 | +# Probar notificación de progreso |
| 898 | +curl -X POST http://localhost:8000/mcp \ |
| 899 | + -H "Content-Type: application/json" \ |
| 900 | + -d '{ |
| 901 | + "jsonrpc": "2.0", |
| 902 | + "method": "notifications/progress", |
| 903 | + "params": { |
| 904 | + "progressToken": "upload_123", |
| 905 | + "progress": 75, |
| 906 | + "total": 100 |
| 907 | + } |
| 908 | + }' |
| 909 | +# Esperado: HTTP 202 con cuerpo vacío |
| 910 | + |
| 911 | +# Probar notificación de actividad de usuario |
| 912 | +curl -X POST http://localhost:8000/mcp \ |
| 913 | + -H "Content-Type: application/json" \ |
| 914 | + -d '{ |
| 915 | + "jsonrpc": "2.0", |
| 916 | + "method": "notifications/user_activity", |
| 917 | + "params": { |
| 918 | + "userId": 123, |
| 919 | + "action": "file_download", |
| 920 | + "resource": "document.pdf" |
| 921 | + } |
| 922 | + }' |
| 923 | +# Esperado: HTTP 202 con cuerpo vacío |
| 924 | + |
| 925 | +# Probar notificación de cancelación |
| 926 | +curl -X POST http://localhost:8000/mcp \ |
| 927 | + -H "Content-Type: application/json" \ |
| 928 | + -d '{ |
| 929 | + "jsonrpc": "2.0", |
| 930 | + "method": "notifications/cancelled", |
| 931 | + "params": { |
| 932 | + "requestId": "req_abc123", |
| 933 | + "reason": "User requested cancellation" |
| 934 | + } |
| 935 | + }' |
| 936 | +# Esperado: HTTP 202 con cuerpo vacío |
| 937 | +``` |
| 938 | + |
| 939 | +**Notas importantes de prueba:** |
| 940 | +- Las notificaciones devuelven **HTTP 202** (nunca 200) |
| 941 | +- El cuerpo de respuesta está **siempre vacío** |
| 942 | +- No se envía mensaje de respuesta JSON-RPC |
| 943 | +- Verificar logs del servidor para confirmar procesamiento de notificaciones |
| 944 | + |
| 945 | +#### Manejo de Errores y Validación |
| 946 | + |
| 947 | +**Patrones de validación comunes:** |
| 948 | + |
| 949 | +```php |
| 950 | +public function execute(?array $params = null): void |
| 951 | +{ |
| 952 | + // Validar parámetros requeridos |
| 953 | + if (!isset($params['userId'])) { |
| 954 | + Log::error('UserActivityHandler: Missing required userId parameter', $params); |
| 955 | + return; // No lances excepción - las notificaciones deben ser tolerantes a fallos |
| 956 | + } |
| 957 | + |
| 958 | + // Validar tipos de parámetros |
| 959 | + if (!is_numeric($params['userId'])) { |
| 960 | + Log::warning('UserActivityHandler: userId must be numeric', $params); |
| 961 | + return; |
| 962 | + } |
| 963 | + |
| 964 | + // Extracción segura de parámetros con valores por defecto |
| 965 | + $userId = (int) $params['userId']; |
| 966 | + $action = $params['action'] ?? 'unknown'; |
| 967 | + $metadata = $params['metadata'] ?? []; |
| 968 | + |
| 969 | + // Procesar notificación... |
| 970 | +} |
| 971 | +``` |
| 972 | + |
| 973 | +**Mejores prácticas de manejo de errores:** |
| 974 | +- **Registrar errores** en lugar de lanzar excepciones |
| 975 | +- **Usar programación defensiva** con verificaciones null y valores por defecto |
| 976 | +- **Fallar elegantemente** - no romper el flujo de trabajo del cliente |
| 977 | +- **Validar entradas** pero continuar procesando cuando sea posible |
| 978 | +- **Monitorear notificaciones** a través de logging y métricas |
| 979 | + |
701 | 980 | ### Probando Herramientas MCP
|
702 | 981 |
|
703 | 982 | El paquete incluye un comando especial para probar tus herramientas MCP sin necesidad de un cliente MCP real:
|
|
0 commit comments