From 4b9949362d08ade5a56867757f024bb77c4479cf Mon Sep 17 00:00:00 2001 From: ChanYoungHan Date: Wed, 18 Jun 2025 12:37:40 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8=20Add=20source=20field=20to=20msg?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chat_logger.py | 29 +++++++++++++++------- utils/rabbitmq_publisher.py | 49 +++++++++++++++++++++++++++++++------ 2 files changed, 61 insertions(+), 17 deletions(-) diff --git a/chat_logger.py b/chat_logger.py index 21080c5..3b0f809 100644 --- a/chat_logger.py +++ b/chat_logger.py @@ -1,5 +1,6 @@ -from typing import List, Dict, Any +from typing import List, Dict, Any, Optional import os +import re from datetime import datetime from dotenv import load_dotenv from mcp.server.fastmcp import FastMCP @@ -69,10 +70,15 @@ async def save_chat_history(messages: List[Dict[str, Any]], conversation_id: str timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"chat_logs/chat_{conversation_id}_{timestamp}.md" if conversation_id else f"chat_logs/chat_{timestamp}.md" - # Format all messages + # Get source from environment variable + source = os.getenv('MCP_SOURCE', 'claude') + + # Format content according to design specification formatted_content = "# Chat History\n\n" - formatted_content += f"Conversation ID: {conversation_id}\n" if conversation_id else "" - formatted_content += f"Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n" + if conversation_id: + formatted_content += f"Conversation ID: {conversation_id}\n" + formatted_content += f"Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n" + formatted_content += f"Source: {source}\n\n" for message in messages: formatted_content += format_message(message) @@ -90,33 +96,38 @@ async def save_chat_history(messages: List[Dict[str, Any]], conversation_id: str "filename": filename, "file_size": os.path.getsize(filename), "message_count": len(messages), - "save_timestamp": timestamp + "save_timestamp": timestamp, + "source": source } publish_success = publish_chat_message( messages=messages, conversation_id=conversation_id, + message_type="chat", additional_metadata=additional_metadata ) if publish_success: - result_message += "\n✓ RabbitMQ message published successfully" + result_message += f"\n✓ RabbitMQ message published successfully (source: {source})" else: result_message += "\n⚠ RabbitMQ message publish failed (file saved successfully)" except Exception as e: result_message += f"\n⚠ RabbitMQ publish error: {str(e)} (file saved successfully)" else: - result_message += "\nℹ RabbitMQ not configured - file-only mode" + result_message += f"\nℹ RabbitMQ not configured - file-only mode (source: {source})" return result_message if __name__ == "__main__": + # Get source for startup message + source = os.getenv('MCP_SOURCE', 'claude') + # Print startup message based on AMQP configuration if USE_AMQP: - print("🔧 MCP Chat Logger starting with RabbitMQ enabled") + print(f"🔧 MCP Chat Logger starting with RabbitMQ enabled (source: {source})") else: - print("🔧 MCP Chat Logger starting in file-only mode (RabbitMQ not configured)") + print(f"🔧 MCP Chat Logger starting in file-only mode (source: {source})") # Initialize and run the server mcp.run(transport='stdio') \ No newline at end of file diff --git a/utils/rabbitmq_publisher.py b/utils/rabbitmq_publisher.py index 92ada37..4b467f9 100644 --- a/utils/rabbitmq_publisher.py +++ b/utils/rabbitmq_publisher.py @@ -28,7 +28,8 @@ def __init__(self): self.username = os.getenv('RABBITMQ_USERNAME', 'guest') self.password = os.getenv('RABBITMQ_PASSWORD', 'guest') self.virtual_host = os.getenv('RABBITMQ_VIRTUAL_HOST', '/') - self.exchange = os.getenv('RABBITMQ_EXCHANGE', 'llmLogger') + # Updated to use 'pkms' exchange as per design specification + self.exchange = os.getenv('RABBITMQ_EXCHANGE', 'pkms') self.routing_key = os.getenv('RABBITMQ_ROUTING_KEY', 'llm_logger') self.queue_name = os.getenv('RABBITMQ_QUEUE_NAME', 'llm_logger') @@ -105,13 +106,15 @@ def _close_connection(self): def publish_chat_log(self, messages: list, conversation_id: Optional[str] = None, + message_type: str = "chat", additional_metadata: Optional[Dict[str, Any]] = None) -> bool: """ - Publish chat log to RabbitMQ + Publish chat log to RabbitMQ according to design specification Args: messages: List of chat messages conversation_id: Conversation ID (optional) + message_type: Type of message (chat, analysis, etc.) additional_metadata: Additional metadata (optional) Returns: @@ -123,14 +126,19 @@ def publish_chat_log(self, if not self._create_connection(): return False - # Compose message payload + # Get source from environment variable (MCP_SOURCE) + source = os.getenv('MCP_SOURCE', 'claude') + + # Compose message payload according to design specification payload = { - "timestamp": datetime.now().isoformat(), + "source": source, + "type": message_type, "conversation_id": conversation_id, - "messages": messages, + "sending_at": datetime.now().strftime("%Y%m%d %H%M%S"), + "contents": messages, "metadata": additional_metadata or {} } - + # Serialize to JSON message_body = json.dumps(payload, ensure_ascii=False, indent=2) @@ -147,7 +155,7 @@ def publish_chat_log(self, ) ) - logger.info(f"Chat log published successfully - Conversation ID: {conversation_id}, Message count: {len(messages)}") + logger.info(f"Message published successfully - Source: {source}, Type: {message_type}, Conversation ID: {conversation_id}, Message count: {len(messages)}") return True except AMQPChannelError as e: @@ -178,6 +186,29 @@ def test_connection(self) -> bool: logger.error(f"Error during connection test: {e}") return False + def get_configuration(self) -> str: + """ + Get current RabbitMQ configuration as formatted string + + Returns: + str: Configuration information + """ + config = f"""RabbitMQ Configuration: +Host: {self.host}:{self.port} +Virtual Host: {self.virtual_host} +Exchange: {self.exchange} (direct) +Queue: {self.queue_name} +Routing Key: {self.routing_key} +Username: {self.username} +Source: {os.getenv('MCP_SOURCE', 'claude')} + +Connection Settings: +- Connection Timeout: {self.connection_timeout}s +- Heartbeat: {self.heartbeat}s +- Blocked Connection Timeout: {self.blocked_connection_timeout}s""" + + return config + def __enter__(self): """Context manager entry""" self._create_connection() @@ -207,6 +238,7 @@ def get_publisher() -> RabbitMQPublisher: def publish_chat_message(messages: list, conversation_id: Optional[str] = None, + message_type: str = "chat", additional_metadata: Optional[Dict[str, Any]] = None) -> bool: """ Convenient function to publish chat messages @@ -214,10 +246,11 @@ def publish_chat_message(messages: list, Args: messages: List of chat messages conversation_id: Conversation ID (optional) + message_type: Type of message (chat, analysis, etc.) additional_metadata: Additional metadata (optional) Returns: bool: Whether publishing was successful """ publisher = get_publisher() - return publisher.publish_chat_log(messages, conversation_id, additional_metadata) + return publisher.publish_chat_log(messages, conversation_id, message_type, additional_metadata) From 6f7c37ea1de067e09d6d5636dd3213fe3a443dd0 Mon Sep 17 00:00:00 2001 From: ChanYoungHan Date: Wed, 18 Jun 2025 12:38:00 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=E2=9E=95=20Apply=20test-rabbitmq?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dev-tools/test_rabbitmq.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-tools/test_rabbitmq.py b/dev-tools/test_rabbitmq.py index de02498..adb13d1 100644 --- a/dev-tools/test_rabbitmq.py +++ b/dev-tools/test_rabbitmq.py @@ -8,7 +8,7 @@ import os import sys from dotenv import load_dotenv -from rabbitmq_publisher import RabbitMQPublisher +from MCP_Chat_Logger.utils.rabbitmq_publisher import RabbitMQPublisher def main(): """Main function""" From 923b8324f157d39045e9297e36df6cdc186f087e Mon Sep 17 00:00:00 2001 From: ChanYoungHan Date: Wed, 18 Jun 2025 12:38:16 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=93=9D=20Update=20readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++------ README_en.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++------ README_ko.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 144 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 7496e16..4bdc29a 100644 --- a/README.md +++ b/README.md @@ -106,9 +106,14 @@ RABBITMQ_PORT=5672 RABBITMQ_USERNAME=guest RABBITMQ_PASSWORD=guest RABBITMQ_VIRTUAL_HOST=/ -RABBITMQ_EXCHANGE=llmLogger + +# Message Queue Routing (Design Specification) +RABBITMQ_EXCHANGE=pkms RABBITMQ_ROUTING_KEY=llm_logger RABBITMQ_QUEUE_NAME=llm_logger + +# Source Configuration (Required) +MCP_SOURCE=claude ``` #### Docker命令 @@ -153,10 +158,15 @@ RABBITMQ_PORT=5672 RABBITMQ_USERNAME=your-username RABBITMQ_PASSWORD=your-password RABBITMQ_VIRTUAL_HOST=your-vhost -RABBITMQ_EXCHANGE=llmLogger + +# Message Queue Routing (Design Specification) +RABBITMQ_EXCHANGE=pkms RABBITMQ_ROUTING_KEY=llm_logger RABBITMQ_QUEUE_NAME=llm_logger +# Source Configuration (Required) +MCP_SOURCE=claude + # 可选连接设置 RABBITMQ_CONNECTION_TIMEOUT=30 RABBITMQ_HEARTBEAT=600 @@ -173,13 +183,41 @@ RABBITMQ_BLOCKED_CONNECTION_TIMEOUT=300 - 🛠️ **环境变量**:通过`.env`文件进行配置管理 - ☁️ **多环境支持**:支持开发环境(Docker)和生产环境(CloudAMQP) -### Exchange设计 +### Message Queue设计 -- **Exchange名称**:`llmLogger` +- **Exchange名称**:`pkms` - **Exchange类型**:`direct` - **路由键**:`llm_logger` - **队列名称**:`llm_logger` -- **绑定**:队列`llm_logger`通过路由键`llm_logger`绑定到Exchange `llmLogger` +- **绑定**:队列`llm_logger`通过路由键`llm_logger`绑定到Exchange `pkms` + +### 消息结构 + +```json +{ + "source": "claude", + "type": "chat" | "analysis", + "conversation_id": "str", + "sending_at": "YYYYmmdd HHMMSS", + "contents": [], + "metadata": {} +} +``` + +### 文件格式 + +```markdown +# Chat History +Conversation ID: 20250618_000500_001 +Date: 2025-06-18 00:06:02 +Source: claude + +### User - 2025-06-18 00:06:02 +... + +### Assistant - 2025-06-18 00:06:02 +... +``` ### 可用的MCP工具 @@ -202,6 +240,7 @@ RABBITMQ_BLOCKED_CONNECTION_TIMEOUT=300 "chat_logger.py" ], "env": { + "MCP_SOURCE": "claude", "RABBITMQ_HOST": "your-rabbitmq-host", "RABBITMQ_PORT": "5672", "RABBITMQ_USERNAME": "your-username", @@ -224,7 +263,10 @@ RABBITMQ_BLOCKED_CONNECTION_TIMEOUT=300 "/path/to/MCP_Chat_Logger", "run", "chat_logger.py" - ] + ], + "env": { + "MCP_SOURCE": "claude" + } } } ``` diff --git a/README_en.md b/README_en.md index 222249a..5017c29 100644 --- a/README_en.md +++ b/README_en.md @@ -106,9 +106,14 @@ RABBITMQ_PORT=5672 RABBITMQ_USERNAME=guest RABBITMQ_PASSWORD=guest RABBITMQ_VIRTUAL_HOST=/ -RABBITMQ_EXCHANGE=llmLogger + +# Message Queue Routing (Design Specification) +RABBITMQ_EXCHANGE=pkms RABBITMQ_ROUTING_KEY=llm_logger RABBITMQ_QUEUE_NAME=llm_logger + +# Source Configuration (Required) +MCP_SOURCE=claude ``` #### Docker Commands @@ -153,10 +158,15 @@ RABBITMQ_PORT=5672 RABBITMQ_USERNAME=your-username RABBITMQ_PASSWORD=your-password RABBITMQ_VIRTUAL_HOST=your-vhost -RABBITMQ_EXCHANGE=llmLogger + +# Message Queue Routing (Design Specification) +RABBITMQ_EXCHANGE=pkms RABBITMQ_ROUTING_KEY=llm_logger RABBITMQ_QUEUE_NAME=llm_logger +# Source Configuration (Required) +MCP_SOURCE=claude + # Optional connection settings RABBITMQ_CONNECTION_TIMEOUT=30 RABBITMQ_HEARTBEAT=600 @@ -173,13 +183,41 @@ RABBITMQ_BLOCKED_CONNECTION_TIMEOUT=300 - 🛠️ **Environment Variables**: Configuration management through `.env` files - ☁️ **Multi-Environment Support**: Support for development (Docker) and production (CloudAMQP) environments -### Exchange Design +### Message Queue Design -- **Exchange Name**: `llmLogger` +- **Exchange Name**: `pkms` - **Exchange Type**: `direct` - **Routing Key**: `llm_logger` - **Queue Name**: `llm_logger` -- **Binding**: Queue `llm_logger` bound to Exchange `llmLogger` with Routing Key `llm_logger` +- **Binding**: Queue `llm_logger` bound to Exchange `pkms` with Routing Key `llm_logger` + +### Message Structure + +```json +{ + "source": "claude", + "type": "chat" | "analysis", + "conversation_id": "str", + "sending_at": "YYYYmmdd HHMMSS", + "contents": [], + "metadata": {} +} +``` + +### File Format + +```markdown +# Chat History +Conversation ID: 20250618_000500_001 +Date: 2025-06-18 00:06:02 +Source: claude + +### User - 2025-06-18 00:06:02 +... + +### Assistant - 2025-06-18 00:06:02 +... +``` ### Available MCP Tool @@ -202,6 +240,7 @@ RABBITMQ_BLOCKED_CONNECTION_TIMEOUT=300 "chat_logger.py" ], "env": { + "MCP_SOURCE": "claude", "RABBITMQ_HOST": "your-rabbitmq-host", "RABBITMQ_PORT": "5672", "RABBITMQ_USERNAME": "your-username", @@ -224,7 +263,10 @@ RABBITMQ_BLOCKED_CONNECTION_TIMEOUT=300 "/path/to/MCP_Chat_Logger", "run", "chat_logger.py" - ] + ], + "env": { + "MCP_SOURCE": "claude" + } } } ``` diff --git a/README_ko.md b/README_ko.md index 73df5d1..9fb2022 100644 --- a/README_ko.md +++ b/README_ko.md @@ -106,9 +106,14 @@ RABBITMQ_PORT=5672 RABBITMQ_USERNAME=guest RABBITMQ_PASSWORD=guest RABBITMQ_VIRTUAL_HOST=/ -RABBITMQ_EXCHANGE=llmLogger + +# Message Queue Routing (Design Specification) +RABBITMQ_EXCHANGE=pkms RABBITMQ_ROUTING_KEY=llm_logger RABBITMQ_QUEUE_NAME=llm_logger + +# Source Configuration (Required) +MCP_SOURCE=claude ``` #### Docker 명령어 @@ -153,10 +158,15 @@ RABBITMQ_PORT=5672 RABBITMQ_USERNAME=your-username RABBITMQ_PASSWORD=your-password RABBITMQ_VIRTUAL_HOST=your-vhost -RABBITMQ_EXCHANGE=llmLogger + +# Message Queue Routing (Design Specification) +RABBITMQ_EXCHANGE=pkms RABBITMQ_ROUTING_KEY=llm_logger RABBITMQ_QUEUE_NAME=llm_logger +# Source Configuration (Required) +MCP_SOURCE=claude + # 선택적 연결 설정 RABBITMQ_CONNECTION_TIMEOUT=30 RABBITMQ_HEARTBEAT=600 @@ -173,13 +183,41 @@ RABBITMQ_BLOCKED_CONNECTION_TIMEOUT=300 - 🛠️ **환경변수**: `.env` 파일을 통한 설정 관리 - ☁️ **다중 환경**: 개발환경(Docker)과 운영환경(CloudAMQP) 지원 -### Exchange 설계 +### Message Queue 설계 -- **Exchange 이름**: `llmLogger` +- **Exchange 이름**: `pkms` - **Exchange 타입**: `direct` - **라우팅 키**: `llm_logger` - **큐 이름**: `llm_logger` -- **바인딩**: 큐 `llm_logger`가 Exchange `llmLogger`에 라우팅 키 `llm_logger`로 바인딩됨 +- **바인딩**: 큐 `llm_logger`가 Exchange `pkms`에 라우팅 키 `llm_logger`로 바인딩됨 + +### 메시지 구조 + +```json +{ + "source": "claude", + "type": "chat" | "analysis", + "conversation_id": "str", + "sending_at": "YYYYmmdd HHMMSS", + "contents": [], + "metadata": {} +} +``` + +### 파일 형식 + +```markdown +# Chat History +Conversation ID: 20250618_000500_001 +Date: 2025-06-18 00:06:02 +Source: claude + +### User - 2025-06-18 00:06:02 +... + +### Assistant - 2025-06-18 00:06:02 +... +``` ### 사용 가능한 MCP 도구 @@ -202,6 +240,7 @@ RABBITMQ_BLOCKED_CONNECTION_TIMEOUT=300 "chat_logger.py" ], "env": { + "MCP_SOURCE": "claude", "RABBITMQ_HOST": "your-rabbitmq-host", "RABBITMQ_PORT": "5672", "RABBITMQ_USERNAME": "your-username", @@ -224,7 +263,10 @@ RABBITMQ_BLOCKED_CONNECTION_TIMEOUT=300 "/path/to/MCP_Chat_Logger", "run", "chat_logger.py" - ] + ], + "env": { + "MCP_SOURCE": "claude", + } } } ```