#
tokens: 6549/50000 19/19 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── chatbot
│   ├── .gitignore
│   ├── data
│   │   └── install.sql
│   ├── package.json
│   ├── pnpm-lock.yaml
│   ├── README_CN.md
│   ├── README.md
│   └── src
│       ├── db.ts
│       ├── index.ts
│       ├── message.ts
│       ├── types.d.ts
│       └── utils.ts
├── package.json
├── pnpm-lock.yaml
├── preview.png
├── README_CN.md
├── README.md
├── src
│   ├── index.ts
│   ├── models
│   │   ├── chat_message.ts
│   │   └── db.ts
│   ├── services
│   │   ├── chat_message.ts
│   │   └── tools.ts
│   └── types
│       └── chat_message.d.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
1 | node_modules/
2 | build/
3 | *.log
4 | .env*
5 | data/*
6 | .vscode/*
```

--------------------------------------------------------------------------------
/chatbot/.gitignore:
--------------------------------------------------------------------------------

```
1 | node_modules/
2 | .DS_Store
3 | data/chat.db
4 | .vscode/*
5 | .env*
```

--------------------------------------------------------------------------------
/chatbot/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # chatbot
 2 | 
 3 | Save your chat messages to local sqlite database.
 4 | 
 5 | [中文说明](README_CN.md)
 6 | 
 7 | ## Prerequisites
 8 | 
 9 | 1. Install `sqlite3` in your local machine.
10 | 
11 | for macos:
12 | 
13 | ```shell
14 | brew install sqlite3
15 | ```
16 | 
17 | 2. Set your environment variables.
18 | 
19 | create `.env` file in the root directory, and set your chat database path.
20 | 
21 | ```txt
22 | CHAT_DB_PATH=path-to/data/chat.db
23 | ```
24 | 
25 | 3. Init chat database.
26 | 
27 | connect to your chat database with `sqlite3` command
28 | 
29 | ```shell
30 | sqlite3 path-to/data/chat.db
31 | ```
32 | 
33 | create table `chat_messages` with `install.sql`.
34 | 
35 | ```sql
36 | CREATE TABLE chat_messages (
37 |     id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
38 |     created_at INTEGER NOT NULL,
39 |     msg_id TEXT NOT NULL,
40 |     room_id TEXT,
41 |     room_name TEXT,
42 |     room_avatar TEXT,
43 |     talker_id TEXT NOT NULL,
44 |     talker_name TEXT,
45 |     talker_avatar TEXT,
46 |     content TEXT,
47 |     msg_type INTEGER,
48 |     url_title TEXT,
49 |     url_desc TEXT,
50 |     url_link TEXT,
51 |     url_thumb TEXT
52 | );
53 | ```
54 | 
55 | ## Run chatbot
56 | 
57 | 1. Install dependencies.
58 | 
59 | ```shell
60 | pnpm install
61 | ```
62 | 
63 | 2. Start chatbot.
64 | 
65 | ```shell
66 | pnpm start
67 | ```
68 | 
69 | 3. Login with your WeChat
70 | 
71 | scan the QR code with your WeChat app. Let chatbot auto receive and save chat messages.
72 | 
73 | > **Attention:**
74 | >
75 | > - chatbot use `wechaty` with `wechaty-puppet-wechat4u` to run RPA.
76 | > - it may be blocked by WeChat. Be careful with your WeChat account.
77 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # mcp-server-chatsum
 2 | 
 3 | This MCP Server is used to summarize your chat messages.
 4 | 
 5 | [中文说明](README_CN.md)
 6 | 
 7 | ![preview](./preview.png)
 8 | 
 9 | > **Before you start**
10 | >
11 | > move to [chatbot](./chatbot) directory, follow the [README](./chatbot/README.md) to setup the chat database.
12 | >
13 | > start chatbot to save your chat messages.
14 | 
15 | ## Features
16 | 
17 | ### Resources
18 | 
19 | ### Tools
20 | 
21 | - `query_chat_messages` - Query chat messages
22 |   - Query chat messages with given parameters
23 |   - Summarize chat messages based on the query prompt
24 | 
25 | ### Prompts
26 | 
27 | ## Development
28 | 
29 | 1. Set up environment variables:
30 | 
31 | create `.env` file in the root directory, and set your chat database path.
32 | 
33 | ```txt
34 | CHAT_DB_PATH=path-to/chatbot/data/chat.db
35 | ```
36 | 
37 | 2. Install dependencies:
38 | 
39 | ```bash
40 | pnpm install
41 | ```
42 | 
43 | Build the server:
44 | 
45 | ```bash
46 | pnpm build
47 | ```
48 | 
49 | For development with auto-rebuild:
50 | 
51 | ```bash
52 | pnpm watch
53 | ```
54 | 
55 | ## Installation
56 | 
57 | To use with Claude Desktop, add the server config:
58 | 
59 | On MacOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
60 | On Windows: `%APPDATA%/Claude/claude_desktop_config.json`
61 | 
62 | ```json
63 | {
64 |   "mcpServers": {
65 |     "mcp-server-chatsum": {
66 |       "command": "path-to/bin/node",
67 |       "args": ["path-to/mcp-server-chatsum/build/index.js"],
68 |       "env": {
69 |         "CHAT_DB_PATH": "path-to/mcp-server-chatsum/chatbot/data/chat.db"
70 |       }
71 |     }
72 |   }
73 | }
74 | ```
75 | 
76 | ### Debugging
77 | 
78 | Since MCP servers communicate over stdio, debugging can be challenging. We recommend using the [MCP Inspector](https://github.com/modelcontextprotocol/inspector), which is available as a package script:
79 | 
80 | ```bash
81 | pnpm inspector
82 | ```
83 | 
84 | The Inspector will provide a URL to access debugging tools in your browser.
85 | 
86 | ## Community
87 | 
88 | - [MCP Server Telegram](https://t.me/+N0gv4O9SXio2YWU1)
89 | - [MCP Server Discord](https://discord.gg/RsYPRrnyqg)
90 | 
91 | ## About the author
92 | 
93 | - [idoubi](https://bento.me/idoubi)
94 | 
```

--------------------------------------------------------------------------------
/chatbot/src/types.d.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export interface ChatMessage {
 2 |   created_at: number;
 3 |   msg_id: string;
 4 |   room_id?: string;
 5 |   room_name?: string;
 6 |   room_avatar?: string;
 7 |   talker_id: string;
 8 |   talker_name?: string;
 9 |   talker_avatar?: string;
10 |   content?: string;
11 |   msg_type: number;
12 |   url_title?: string;
13 |   url_desc?: string;
14 |   url_link?: string;
15 |   url_thumb?: string;
16 | }
17 | 
```

--------------------------------------------------------------------------------
/src/types/chat_message.d.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export interface ChatMessage {
 2 |   created_at: number;
 3 |   msg_id: string;
 4 |   room_id?: string;
 5 |   room_name?: string;
 6 |   room_avatar?: string;
 7 |   talker_id: string;
 8 |   talker_name?: string;
 9 |   talker_avatar?: string;
10 |   content?: string;
11 |   msg_type: number;
12 |   url_title?: string;
13 |   url_desc?: string;
14 |   url_link?: string;
15 |   url_thumb?: string;
16 | }
17 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2022",
 4 |     "module": "Node16",
 5 |     "moduleResolution": "Node16",
 6 |     "outDir": "./build",
 7 |     "rootDir": "./src",
 8 |     "strict": true,
 9 |     "esModuleInterop": true,
10 |     "skipLibCheck": true,
11 |     "forceConsistentCasingInFileNames": true
12 |   },
13 |   "include": ["src/**/*"],
14 |   "exclude": ["node_modules"]
15 | }
16 | 
```

--------------------------------------------------------------------------------
/src/models/db.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import sqlite3 from "sqlite3";
 2 | 
 3 | export function getDb(): sqlite3.Database {
 4 |   const dbName = process.env.CHAT_DB_PATH || "";
 5 |   if (!dbName) {
 6 |     throw new Error("CHAT_DB_PATH is not set");
 7 |   }
 8 | 
 9 |   const db = new sqlite3.Database(dbName, (err) => {
10 |     if (err) {
11 |       console.error("chat db connect failed: ", dbName, err.message);
12 |       return;
13 |     }
14 |   });
15 | 
16 |   return db;
17 | }
18 | 
```

--------------------------------------------------------------------------------
/chatbot/data/install.sql:
--------------------------------------------------------------------------------

```sql
 1 | CREATE TABLE chat_messages (
 2 |     id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
 3 |     created_at INTEGER NOT NULL,
 4 |     msg_id TEXT NOT NULL,
 5 |     room_id TEXT,
 6 |     room_name TEXT,
 7 |     room_avatar TEXT,
 8 |     talker_id TEXT NOT NULL,
 9 |     talker_name TEXT,
10 |     talker_avatar TEXT,
11 |     content TEXT,
12 |     msg_type INTEGER,
13 |     url_title TEXT,
14 |     url_desc TEXT,
15 |     url_link TEXT,
16 |     url_thumb TEXT
17 | );
```

--------------------------------------------------------------------------------
/chatbot/src/message.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import * as PUPPET from "wechaty-puppet";
 2 | 
 3 | import { MessageInterface } from "wechaty/impls";
 4 | import { parseChatMessage } from "./utils";
 5 | import { saveChatMessage } from "./db";
 6 | 
 7 | export async function handleReceiveMessage(msg: MessageInterface) {
 8 |   try {
 9 |     console.log("receive message: ", msg);
10 | 
11 |     const m = await parseChatMessage(msg);
12 | 
13 |     if (
14 |       m.msg_type === PUPPET.types.Message.Text ||
15 |       m.msg_type === PUPPET.types.Message.Url
16 |     ) {
17 |       saveChatMessage(m);
18 |     }
19 |   } catch (e) {
20 |     console.log("parse chat message failed: ", e);
21 |   }
22 | }
23 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "mcp-server-chatsum",
 3 |   "version": "0.1.0",
 4 |   "description": "Summarize your chat messages.",
 5 |   "private": true,
 6 |   "type": "module",
 7 |   "bin": {
 8 |     "mcp-server-chatsum": "./build/index.js"
 9 |   },
10 |   "files": [
11 |     "build"
12 |   ],
13 |   "scripts": {
14 |     "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
15 |     "prepare": "npm run build",
16 |     "watch": "tsc --watch",
17 |     "inspector": "npx @modelcontextprotocol/inspector build/index.js"
18 |   },
19 |   "dependencies": {
20 |     "@modelcontextprotocol/sdk": "0.6.0",
21 |     "dotenv": "^16.4.6",
22 |     "sqlite3": "^5.1.7"
23 |   },
24 |   "devDependencies": {
25 |     "@types/node": "^20.17.9",
26 |     "typescript": "^5.3.3"
27 |   }
28 | }
29 | 
```

--------------------------------------------------------------------------------
/src/services/tools.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export const queryChatMessagesTool = {
 2 |   name: "query_chat_messages",
 3 |   description: "query chat messages with given parameters",
 4 |   inputSchema: {
 5 |     type: "object",
 6 |     properties: {
 7 |       room_names: {
 8 |         type: "array",
 9 |         description: "chat room names",
10 |         items: {
11 |           type: "string",
12 |           description: "chat room name",
13 |         },
14 |       },
15 |       talker_names: {
16 |         type: "array",
17 |         description: "talker names",
18 |         items: {
19 |           type: "string",
20 |           description: "talker name",
21 |         },
22 |       },
23 |       limit: {
24 |         type: "number",
25 |         description: "chat messages limit",
26 |         default: 100,
27 |       },
28 |     },
29 |     required: [],
30 |   },
31 | };
32 | 
```

--------------------------------------------------------------------------------
/chatbot/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "mcp-server-chatsum-bot",
 3 |   "version": "1.0.0",
 4 |   "description": "chatbot to save chat messages.",
 5 |   "main": "index.ts",
 6 |   "scripts": {
 7 |     "start": "ts-node src/index.ts"
 8 |   },
 9 |   "repository": {
10 |     "type": "git",
11 |     "url": "git+https://github.com/mcpservers/mcp-server-chatsum.git"
12 |   },
13 |   "keywords": [],
14 |   "author": "",
15 |   "bugs": {
16 |     "url": "https://github.com/mcpservers/mcp-server-chatsum/issues"
17 |   },
18 |   "homepage": "https://github.com/mcpservers/mcp-server-chatsum#readme",
19 |   "dependencies": {
20 |     "dotenv": "^16.4.7",
21 |     "qrcode-terminal": "^0.12.0",
22 |     "sqlite3": "^5.1.6",
23 |     "ts-node": "^10.9.2",
24 |     "wechaty": "^1.20.2",
25 |     "wechaty-puppet": "^1.20.2",
26 |     "wechaty-puppet-padlocal": "^1.20.1"
27 |   },
28 |   "devDependencies": {
29 |     "@types/qrcode-terminal": "^0.12.0"
30 |   }
31 | }
32 | 
```

--------------------------------------------------------------------------------
/src/services/chat_message.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { ChatMessage } from "../types/chat_message.js";
 2 | import { queryChatMessages } from "../models/chat_message.js";
 3 | 
 4 | export async function getChatMessages(params: any): Promise<ChatMessage[]> {
 5 |   const room_names: string[] = [];
 6 |   const talker_names: string[] = [];
 7 |   let page = 1;
 8 |   let limit = 100;
 9 | 
10 |   if (params.limit && params.limit > 0 && params.limit < 1000) {
11 |     limit = params.limit;
12 |   }
13 | 
14 |   if (params.room_names) {
15 |     if (Array.isArray(params.room_names)) {
16 |       room_names.push(...params.room_names);
17 |     } else {
18 |       room_names.push(params.room_names);
19 |     }
20 |   }
21 | 
22 |   if (params.talker_names) {
23 |     if (Array.isArray(params.talker_names)) {
24 |       talker_names.push(...params.talker_names);
25 |     } else {
26 |       talker_names.push(params.talker_names);
27 |     }
28 |   }
29 | 
30 |   try {
31 |     const result: ChatMessage[] = await queryChatMessages({
32 |       room_names,
33 |       talker_names,
34 |       page,
35 |       limit,
36 |     });
37 | 
38 |     return result;
39 |   } catch (error) {
40 |     console.error("get chat messages failed: ", error);
41 |     return [];
42 |   }
43 | }
44 | 
```

--------------------------------------------------------------------------------
/chatbot/src/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { ScanStatus, WechatyBuilder } from "wechaty";
 2 | 
 3 | import QrcodeTerminal from "qrcode-terminal";
 4 | import dotenv from "dotenv";
 5 | import { handleReceiveMessage } from "./message";
 6 | 
 7 | dotenv.config();
 8 | 
 9 | const token = "";
10 | const bot = WechatyBuilder.build({
11 |   puppet: "wechaty-puppet-wechat4u",
12 |   // puppet: 'wechaty-puppet-service',
13 |   // puppet: "wechaty-puppet-padlocal",
14 |   puppetOptions: {
15 |     token,
16 |     timeoutSeconds: 60,
17 |     tls: {
18 |       disable: true,
19 |       // currently we are not using TLS since most puppet-service versions does not support it. See: https://github.com/wechaty/puppet-service/issues/160
20 |     },
21 |   },
22 | });
23 | 
24 | bot
25 |   .on("scan", (qrcode, status, data) => {
26 |     console.log(`
27 |   ============================================================
28 |   qrcode : ${qrcode}, status: ${status}, data: ${data}
29 |   ============================================================
30 |   `);
31 |     if (status === ScanStatus.Waiting) {
32 |       QrcodeTerminal.generate(qrcode, {
33 |         small: true,
34 |       });
35 |     }
36 |   })
37 |   .on("login", (user) => {
38 |     console.log(`
39 |   ============================================
40 |   user: ${JSON.stringify(user)}, friend: ${user.friend()}, ${user.coworker()}
41 |   ============================================
42 |   `);
43 |   })
44 |   .on("message", handleReceiveMessage)
45 |   .on("error", (err) => {
46 |     console.log(err);
47 |   });
48 | 
49 | bot.start();
50 | 
```

--------------------------------------------------------------------------------
/src/models/chat_message.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { ChatMessage } from "../types/chat_message.js";
 2 | import { getDb } from "./db.js";
 3 | 
 4 | export async function queryChatMessages({
 5 |   room_names,
 6 |   talker_names,
 7 |   page = 1,
 8 |   limit = 100,
 9 | }: {
10 |   room_names?: string[];
11 |   talker_names?: string[];
12 |   page?: number;
13 |   limit?: number;
14 | }): Promise<ChatMessage[]> {
15 |   try {
16 |     const db = getDb();
17 |     if (!db) {
18 |       throw new Error("db is not connected");
19 |     }
20 | 
21 |     const offset = (page - 1) * limit;
22 | 
23 |     let sql = `SELECT * FROM chat_messages`;
24 |     let values: any[] = [];
25 | 
26 |     if (room_names && room_names.length > 0) {
27 |       sql += ` WHERE room_name IN (${room_names.map(() => "?").join(",")})`;
28 |       values.push(...room_names);
29 |     }
30 | 
31 |     if (talker_names && talker_names.length > 0) {
32 |       sql += ` WHERE talker_name IN (${talker_names.map(() => "?").join(",")})`;
33 |       values.push(...talker_names);
34 |     }
35 | 
36 |     sql += ` ORDER BY created_at DESC LIMIT ? OFFSET ?`;
37 |     values.push(limit, offset);
38 | 
39 |     console.error("query chat messages sql: ", sql, values);
40 | 
41 |     return new Promise((resolve, reject) => {
42 |       db.all(sql, values, (err, rows) => {
43 |         if (err) {
44 |           console.error("query chat messages failed: ", err);
45 |           reject(err);
46 |         } else {
47 |           resolve(rows as ChatMessage[]);
48 |         }
49 |       });
50 |     });
51 |   } catch (error) {
52 |     console.error("query chat messages failed: ", error);
53 |     throw error;
54 |   }
55 | }
56 | 
```

--------------------------------------------------------------------------------
/chatbot/src/db.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { ChatMessage } from "./types";
 2 | import sqlite3 from "sqlite3";
 3 | 
 4 | export async function saveChatMessage(msg: ChatMessage) {
 5 |   try {
 6 |     const db = getDb();
 7 |     if (!db) {
 8 |       throw new Error("db is not connected");
 9 |     }
10 | 
11 |     const {
12 |       msg_type,
13 |       msg_id,
14 |       created_at,
15 |       room_id,
16 |       room_name,
17 |       room_avatar,
18 |       talker_id,
19 |       talker_name,
20 |       talker_avatar,
21 |       content,
22 |       url_title,
23 |       url_desc,
24 |       url_link,
25 |       url_thumb,
26 |     } = msg;
27 | 
28 |     let sql = `INSERT INTO chat_messages(
29 |       created_at,
30 |       msg_id,
31 |       room_id,
32 |       room_name,
33 |       room_avatar,
34 |       talker_id,
35 |       talker_name,
36 |       talker_avatar,
37 |       content,
38 |       msg_type,
39 |       url_title,
40 |       url_desc,
41 |       url_link,
42 |       url_thumb
43 |     ) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)`;
44 | 
45 |     db.run(sql, [
46 |       created_at,
47 |       msg_id,
48 |       room_id,
49 |       room_name,
50 |       room_avatar,
51 |       talker_id,
52 |       talker_name,
53 |       talker_avatar,
54 |       content,
55 |       msg_type,
56 |       url_title,
57 |       url_desc,
58 |       url_link,
59 |       url_thumb,
60 |     ]);
61 | 
62 |     console.error("save message ok");
63 |   } catch (error) {
64 |     console.error("save message failed: ", error);
65 |     throw error;
66 |   }
67 | }
68 | 
69 | export function getDb(): sqlite3.Database {
70 |   const dbName = process.env.CHAT_DB_PATH || "";
71 |   if (!dbName) {
72 |     throw new Error("CHAT_DB_PATH is not set");
73 |   }
74 | 
75 |   const db = new sqlite3.Database(dbName, (err) => {
76 |     if (err) {
77 |       console.error("chat db connect failed: ", dbName, err.message);
78 |       return;
79 |     }
80 |   });
81 | 
82 |   return db;
83 | }
84 | 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | #!/usr/bin/env node
 2 | 
 3 | import {
 4 |   CallToolRequestSchema,
 5 |   ListToolsRequestSchema,
 6 | } from "@modelcontextprotocol/sdk/types.js";
 7 | 
 8 | import { ChatMessage } from "./types/chat_message.js";
 9 | import { Server } from "@modelcontextprotocol/sdk/server/index.js";
10 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
11 | import dotenv from "dotenv";
12 | import { getChatMessages } from "./services/chat_message.js";
13 | import { queryChatMessagesTool } from "./services/tools.js";
14 | 
15 | const server = new Server(
16 |   {
17 |     name: "mcp-server-chatsum",
18 |     version: "0.1.0",
19 |   },
20 |   {
21 |     capabilities: {
22 |       resources: {},
23 |       tools: {},
24 |       prompts: {},
25 |     },
26 |   }
27 | );
28 | 
29 | server.setRequestHandler(ListToolsRequestSchema, async () => {
30 |   return {
31 |     tools: [queryChatMessagesTool],
32 |   };
33 | });
34 | 
35 | server.setRequestHandler(CallToolRequestSchema, async (request) => {
36 |   console.error("call tool request:", request);
37 |   switch (request.params.name) {
38 |     case "query_chat_messages": {
39 |       const messages: ChatMessage[] = await getChatMessages(
40 |         request.params.arguments
41 |       );
42 |       console.error("query chat messages result:", messages);
43 | 
44 |       return {
45 |         content: [
46 |           {
47 |             type: "text",
48 |             text: JSON.stringify(messages),
49 |           },
50 |         ],
51 |       };
52 |     }
53 | 
54 |     default:
55 |       throw new Error("Unknown tool");
56 |   }
57 | });
58 | 
59 | async function main() {
60 |   const transport = new StdioServerTransport();
61 |   await server.connect(transport);
62 | }
63 | 
64 | dotenv.config();
65 | 
66 | main().catch((error) => {
67 |   console.error("Server error:", error);
68 |   process.exit(1);
69 | });
70 | 
```

--------------------------------------------------------------------------------
/chatbot/src/utils.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import * as PUPPET from "wechaty-puppet";
 2 | 
 3 | import { ChatMessage } from "./types";
 4 | import { MessageInterface } from "wechaty/impls";
 5 | 
 6 | export async function parseChatMessage(
 7 |   msg: MessageInterface
 8 | ): Promise<ChatMessage> {
 9 |   const msg_type = msg.type();
10 |   const msg_id = msg.id;
11 |   const payload = msg.payload;
12 |   const talker = msg.talker();
13 | 
14 |   if (!msg_id || !payload || !talker) {
15 |     console.log("invalid msg: ", msg);
16 |     return Promise.reject("invalid msg");
17 |   }
18 | 
19 |   let room_id = "";
20 |   let room_name = "";
21 |   let room_avatar = "";
22 | 
23 |   const room = msg.room();
24 | 
25 |   if (room) {
26 |     room_id = room.id;
27 |     room_name = (await room.topic()).trim();
28 |     room_avatar = room.payload?.avatar || "";
29 |   }
30 | 
31 |   const talker_id = talker.id;
32 |   const talker_name = talker.name().trim();
33 |   const talker_avatar = talker.payload?.avatar;
34 |   const created_at = payload.timestamp;
35 | 
36 |   let content = "";
37 | 
38 |   let url_title = "";
39 |   let url_desc = "";
40 |   let url_link = "";
41 |   let url_thumb = "";
42 | 
43 |   switch (msg_type) {
44 |     case PUPPET.types.Message.Text:
45 |       content = msg.text().trim();
46 |       break;
47 |     case PUPPET.types.Message.Url:
48 |       const urlMsg = await msg.toUrlLink();
49 | 
50 |       url_title = urlMsg.title();
51 |       url_desc = urlMsg.description() || "";
52 |       url_link = urlMsg.url();
53 |       url_thumb = urlMsg.thumbnailUrl() || "";
54 |       break;
55 |     default:
56 |       console.log("msg type not support");
57 |       return Promise.reject(`msg type not support: ${msg_type}`);
58 |   }
59 | 
60 |   return Promise.resolve({
61 |     msg_type,
62 |     msg_id,
63 |     created_at,
64 |     talker_id,
65 |     talker_name,
66 |     talker_avatar,
67 |     room_id,
68 |     room_name,
69 |     room_avatar,
70 |     content,
71 |     url_title,
72 |     url_desc,
73 |     url_link,
74 |     url_thumb,
75 |   });
76 | }
77 | 
```