From fa226733b810ea72d6f1417ac255916dc9e1d39d Mon Sep 17 00:00:00 2001
From: bin <632190820@qq.com>
Date: Tue, 3 Mar 2026 11:34:45 +0800
Subject: [PATCH] =?UTF-8?q?feat(lark-mcp):=20=E9=87=8D=E6=9E=84=E8=B5=84?=
=?UTF-8?q?=E4=BA=A7=E7=A1=AE=E8=AE=A4=E5=8D=A1=E7=89=87=E5=B9=B6=E6=9B=B4?=
=?UTF-8?q?=E6=96=B0=E9=A1=B9=E7=9B=AE=E9=85=8D=E7=BD=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
重构 send_asset_confirmation_card 工具,使用新的卡片模板和参数结构
- 将卡片布局从 column_set 改为 form,简化结构
- 更新参数:inputs/outputs 合并为 asset_list,新增 order_number 和 remark
- 卡片交互按钮现在传递 order_number 和 user_id 到回调
- 更新工具描述和必填字段
同时更新 MCP 服务器配置:
- 统一重命名项目为 lzwcai-lark-mcp 和 lzwcai-file-tools-mcp
- 更新版本号和配置文件中的命令名称
- 更新 file-tools 的 MinIO 环境变量配置
---
file_tools/mcp-server-file-tools.json | 10 +-
file_tools/pyproject.toml | 6 +-
lzwcai_lark_mcp/card.txt | 96 ++++--------
lzwcai_lark_mcp/lzwcai_lark_mcp/tools.py | 179 +++++++++++++----------
lzwcai_lark_mcp/mcp-server.json | 6 +-
lzwcai_lark_mcp/pyproject.toml | 6 +-
6 files changed, 148 insertions(+), 155 deletions(-)
diff --git a/file_tools/mcp-server-file-tools.json b/file_tools/mcp-server-file-tools.json
index f7fe1fb..ad78554 100644
--- a/file_tools/mcp-server-file-tools.json
+++ b/file_tools/mcp-server-file-tools.json
@@ -1,17 +1,17 @@
{
"mcpServers": {
- "lzwcai-mcpskills-file-tools-mcp": {
+ "lzwcai-file-tools-mcp": {
"disabled": false,
"type": "stdio",
"timeout": 30,
"command": "uvx",
"args": [
- "lzwcai-mcpskills-file-tools-mcp"
+ "lzwcai-file-tools-mcp"
],
"env": {
- "minio_endpoint": "http://sceneminios3.lzwcai.com:9000",
- "minio_access_key": "TgPBBz0OdlvEVzG3",
- "minio_secret_key": "AgpliEB6L7UWXXeBaAN0gL4xiRCGCE03"
+ "minio_endpoint": "http://192.168.11.24:9000",
+ "minio_access_key": "cXk8WPR3ix86J9aGK6tH",
+ "minio_secret_key": "FSH8g3tx8bTR4w8BZmwl35WvWbOXZvfvCcivRRJE"
}
}
}
diff --git a/file_tools/pyproject.toml b/file_tools/pyproject.toml
index fb51064..9156580 100644
--- a/file_tools/pyproject.toml
+++ b/file_tools/pyproject.toml
@@ -3,8 +3,8 @@ requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
-name = "lzwcai-mcpskills-file-tools-mcp"
-version = "0.1.12"
+name = "lzwcai-file-tools-mcp"
+version = "0.1.0"
description = "File tools MCP server"
requires-python = ">=3.10"
dependencies = [
@@ -15,7 +15,7 @@ dependencies = [
]
[project.scripts]
-lzwcai-mcpskills-file-tools-mcp = "file_tools.main:main"
+lzwcai-file-tools-mcp = "file_tools.main:main"
[tool.hatch.build.targets.wheel]
packages = ["file_tools"]
diff --git a/lzwcai_lark_mcp/card.txt b/lzwcai_lark_mcp/card.txt
index 44d8395..6a07418 100644
--- a/lzwcai_lark_mcp/card.txt
+++ b/lzwcai_lark_mcp/card.txt
@@ -15,57 +15,30 @@
"body": {
"direction": "vertical",
"elements": [
- {
- "tag": "column_set",
- "flex_mode": "stretch",
- "horizontal_spacing": "12px",
- "horizontal_align": "left",
- "columns": [
- {
- "tag": "column",
- "width": "weighted",
- "elements": [
- {
- "tag": "markdown",
- "content": "**用户:** ",
- "text_align": "left",
- "text_size": "normal"
- }
- ],
- "vertical_spacing": "8px",
- "horizontal_align": "left",
- "vertical_align": "top",
- "weight": 1
- },
- {
- "tag": "column",
- "width": "weighted",
- "elements": [
- {
- "tag": "markdown",
- "content": "**发生时间:** ${change_time}",
- "text_align": "left",
- "text_size": "normal"
- }
- ],
- "vertical_spacing": "8px",
- "horizontal_align": "left",
- "vertical_align": "top",
- "weight": 1
- }
- ],
- "margin": "0px 0px 0px 0px"
- },
- {
- "tag": "hr",
- "margin": "0px 0px 0px 0px"
- },
{
"tag": "form",
"elements": [
{
"tag": "markdown",
- "content": "**\\*请准确选择属于您的变动项:**",
+ "content": "**确认单号:** ${order_number}",
+ "text_align": "left",
+ "text_size": "normal"
+ },
+ {
+ "tag": "markdown",
+ "content": "**用户:** ",
+ "text_align": "left",
+ "text_size": "normal"
+ },
+ {
+ "tag": "markdown",
+ "content": "**发生时间:** ${change_time}",
+ "text_align": "left",
+ "text_size": "normal"
+ },
+ {
+ "tag": "markdown",
+ "content": "**\\*请准确选择关于您的变动项:**",
"text_align": "left",
"text_size": "normal",
"margin": "0px 0px 8px 0px"
@@ -76,29 +49,18 @@
"tag": "plain_text",
"content": "请选择资产变动项"
},
- "options": [
- {
- "text": {
- "tag": "plain_text",
- "content": "资产项1"
- },
- "value": "item1"
- },
- {
- "text": {
- "tag": "plain_text",
- "content": "资产项2"
- },
- "value": "item2"
- }
- ],
+ "options": "${asset_list}",
"type": "default",
"width": "fill",
"required": false,
- "name": "asset_changes",
+ "name": "input_assets",
"margin": "0px 0px 16px 0px",
"element_id": "cIiptD7Z4hCtAeR5Rb0b"
},
+ {
+ "tag": "hr",
+ "margin": "0px 0px 0px 0px"
+ },
{
"tag": "markdown",
"content": "**其他说明:**",
@@ -114,7 +76,7 @@
},
"default_value": "",
"width": "fill",
- "name": "Input_3h27n7woqci",
+ "name": "input_remark",
"margin": "0px 0px 0px 0px"
},
{
@@ -140,7 +102,7 @@
{
"type": "callback",
"value": {
- "action": "confirm_asset_changes"
+ "action": "card.action.trigger"
}
}
],
@@ -168,7 +130,7 @@
"confirm": {
"title": {
"tag": "plain_text",
- "content": "反馈并废除该确认单吗?"
+ "content": "反馈误报并废除该确认单吗?"
},
"text": {
"tag": "plain_text",
@@ -179,7 +141,7 @@
{
"type": "callback",
"value": {
- "": ""
+ "action": "card.action.trigger"
}
}
],
diff --git a/lzwcai_lark_mcp/lzwcai_lark_mcp/tools.py b/lzwcai_lark_mcp/lzwcai_lark_mcp/tools.py
index 4592134..e6c118c 100644
--- a/lzwcai_lark_mcp/lzwcai_lark_mcp/tools.py
+++ b/lzwcai_lark_mcp/lzwcai_lark_mcp/tools.py
@@ -2,7 +2,7 @@ import json
import mimetypes
import os
import re
-from datetime import datetime
+from datetime import datetime, timezone, timedelta
from typing import Dict, List
from urllib.parse import urlparse
@@ -77,7 +77,7 @@ tools = [
),
Tool(
name="send_asset_confirmation_card",
- description="发送资产变动确认卡片,入参为user_id、time、inputs和outputs",
+ description="发送定制资产确认卡片,入参为user_id、order_number、change_time、asset_list和remark",
inputSchema={
"type": "object",
"properties": {
@@ -85,26 +85,27 @@ tools = [
"type": "string",
"description": "消息接收者ID,同时用于卡片内person组件"
},
- "time": {
+ "order_number": {
+ "type": "string",
+ "description": "确认单号"
+ },
+ "change_time": {
"type": "string",
"description": "资产变动发生时间"
},
- "inputs": {
+ "asset_list": {
"type": "array",
- "description": "入库资产列表",
+ "description": "可选择的资产变动项列表",
"items": {
- "type": "string"
+ "type": "object"
}
},
- "outputs": {
- "type": "array",
- "description": "出库资产列表",
- "items": {
- "type": "string"
- }
+ "remark": {
+ "type": "string",
+ "description": "反馈确认弹窗内容"
}
},
- "required": ["user_id", "time"]
+ "required": ["user_id", "order_number"]
}
)
]
@@ -280,16 +281,53 @@ def _build_asset_options(inputs: List[str], outputs: List[str]) -> tuple[list[Di
return options, "、".join(labels)
-def send_asset_confirmation_card(token: str, user_id: str, change_time: str, inputs: object, outputs: object) -> str:
+def _build_select_options(items: List[str]) -> list[Dict[str, object]]:
+ options: list[Dict[str, object]] = []
+ for item in items:
+ label = str(item).strip()
+ if not label:
+ continue
+ options.append({
+ "text": {"tag": "plain_text", "content": label},
+ "value": label
+ })
+ return options
+
+
+def send_asset_confirmation_card(
+ token: str,
+ user_id: str,
+ order_number: str,
+ change_time: str,
+ asset_list: object,
+ remark: object = ""
+) -> str:
normalized_user_id = str(user_id).strip()
if not normalized_user_id:
raise ValueError("missing user_id")
+ normalized_order_number = str(order_number).strip()
+ if not normalized_order_number:
+ raise ValueError("missing order_number")
normalized_time = str(change_time or "").strip()
if not normalized_time:
normalized_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- input_items = _normalize_asset_items(inputs)
- output_items = _normalize_asset_items(outputs)
- options, summary = _build_asset_options(input_items, output_items)
+ normalized_remark = str(remark or "").strip()
+
+ options = []
+ if isinstance(asset_list, list):
+ for item in asset_list:
+ if isinstance(item, dict):
+ for k, v in item.items():
+ options.append({
+ "text": {"tag": "plain_text", "content": str(k)},
+ "value": str(v)
+ })
+ elif isinstance(item, str):
+ options.append({
+ "text": {"tag": "plain_text", "content": item},
+ "value": item
+ })
+
content = {
"schema": "2.0",
"config": {
@@ -307,57 +345,30 @@ def send_asset_confirmation_card(token: str, user_id: str, change_time: str, inp
"body": {
"direction": "vertical",
"elements": [
- {
- "tag": "column_set",
- "flex_mode": "stretch",
- "horizontal_spacing": "12px",
- "horizontal_align": "left",
- "columns": [
- {
- "tag": "column",
- "width": "weighted",
- "elements": [
- {
- "tag": "markdown",
- "content": f"**用户:** ",
- "text_align": "left",
- "text_size": "normal"
- }
- ],
- "vertical_spacing": "8px",
- "horizontal_align": "left",
- "vertical_align": "top",
- "weight": 1
- },
- {
- "tag": "column",
- "width": "weighted",
- "elements": [
- {
- "tag": "markdown",
- "content": f"**发生时间:** {normalized_time}",
- "text_align": "left",
- "text_size": "normal"
- }
- ],
- "vertical_spacing": "8px",
- "horizontal_align": "left",
- "vertical_align": "top",
- "weight": 1
- }
- ],
- "margin": "0px 0px 0px 0px"
- },
- {
- "tag": "hr",
- "margin": "0px 0px 0px 0px"
- },
{
"tag": "form",
"elements": [
{
"tag": "markdown",
- "content": "**\\*请准确选择属于您的变动项:**",
+ "content": f"**确认单号:** {normalized_order_number}",
+ "text_align": "left",
+ "text_size": "normal"
+ },
+ {
+ "tag": "markdown",
+ "content": f"**用户:** ",
+ "text_align": "left",
+ "text_size": "normal"
+ },
+ {
+ "tag": "markdown",
+ "content": f"**发生时间:** {normalized_time}",
+ "text_align": "left",
+ "text_size": "normal"
+ },
+ {
+ "tag": "markdown",
+ "content": "**\\*请准确选择关于您的变动项:**",
"text_align": "left",
"text_size": "normal",
"margin": "0px 0px 8px 0px"
@@ -372,10 +383,14 @@ def send_asset_confirmation_card(token: str, user_id: str, change_time: str, inp
"type": "default",
"width": "fill",
"required": False,
- "name": "asset_changes",
+ "name": "input_assets",
"margin": "0px 0px 16px 0px",
"element_id": "cIiptD7Z4hCtAeR5Rb0b"
},
+ {
+ "tag": "hr",
+ "margin": "0px 0px 0px 0px"
+ },
{
"tag": "markdown",
"content": "**其他说明:**",
@@ -391,7 +406,7 @@ def send_asset_confirmation_card(token: str, user_id: str, change_time: str, inp
},
"default_value": "",
"width": "fill",
- "name": "Input_3h27n7woqci",
+ "name": "input_remark",
"margin": "0px 0px 0px 0px"
},
{
@@ -417,7 +432,9 @@ def send_asset_confirmation_card(token: str, user_id: str, change_time: str, inp
{
"type": "callback",
"value": {
- "action": "confirm_asset_changes"
+ "action": "card.action.trigger",
+ "order_number": normalized_order_number,
+ "user_id": normalized_user_id
}
}
],
@@ -445,18 +462,20 @@ def send_asset_confirmation_card(token: str, user_id: str, change_time: str, inp
"confirm": {
"title": {
"tag": "plain_text",
- "content": "反馈并废除该确认单吗?"
+ "content": "反馈误报并废除该确认单吗?"
},
"text": {
"tag": "plain_text",
- "content": summary
+ "content": normalized_remark
}
},
"behaviors": [
{
"type": "callback",
"value": {
- "": ""
+ "action": "card.action.trigger",
+ "order_number": normalized_order_number,
+ "user_id": normalized_user_id
}
}
],
@@ -543,7 +562,9 @@ def send_asset_confirmation_card(token: str, user_id: str, change_time: str, inp
def send_card_message(token: str, receiver_id: str, person_id: str, image_key: str) -> str:
- current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+ utc_now = datetime.now(timezone.utc)
+ cst_now = utc_now + timedelta(hours=8)
+ current_time = cst_now.strftime("%Y-%m-%d %H:%M:%S")
content = {
"schema": "2.0",
"config": {
@@ -746,12 +767,22 @@ async def handle_call_tool(name: str, arguments: Dict[str, object], token: str)
result = send_card_messages(token, receiver_ids, person_id, image_key)
elif name == "send_asset_confirmation_card":
user_id = str(arguments.get("user_id", "")).strip()
- change_time = str(arguments.get("time", "")).strip()
- inputs = arguments.get("inputs")
- outputs = arguments.get("outputs")
+ order_number = str(arguments.get("order_number", "")).strip()
+ change_time = str(arguments.get("change_time", "")).strip()
+ asset_list = arguments.get("asset_list")
+ remark = str(arguments.get("remark", "")).strip()
if not user_id:
raise ValueError("missing user_id")
- result = send_asset_confirmation_card(token, user_id, change_time, inputs, outputs)
+ if not order_number:
+ raise ValueError("missing order_number")
+ result = send_asset_confirmation_card(
+ token,
+ user_id,
+ order_number,
+ change_time,
+ asset_list,
+ remark
+ )
else:
raise ValueError(f"unknown tool name: {name}")
return [TextContent(type="text", text=result)]
diff --git a/lzwcai_lark_mcp/mcp-server.json b/lzwcai_lark_mcp/mcp-server.json
index 63c2aaf..d28667a 100644
--- a/lzwcai_lark_mcp/mcp-server.json
+++ b/lzwcai_lark_mcp/mcp-server.json
@@ -1,12 +1,12 @@
{
"mcpServers": {
- "lzwcai-mcpskills-lark-mcp": {
+ "lzwcai-lark-mcp": {
"disabled": false,
"type": "stdio",
"timeout": 30,
"command": "uvx",
"args": [
- "lzwcai-mcpskills-lark-mcp"
+ "lzwcai-lark-mcp"
],
"env": {
"app_id": "cli_a8d0e0c140169013",
@@ -14,4 +14,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/lzwcai_lark_mcp/pyproject.toml b/lzwcai_lark_mcp/pyproject.toml
index ae5e863..472b035 100644
--- a/lzwcai_lark_mcp/pyproject.toml
+++ b/lzwcai_lark_mcp/pyproject.toml
@@ -3,8 +3,8 @@ requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
-name = "lzwcai-mcpskills-lark-mcp"
-version = "0.1.10"
+name = "lzwcai-lark-mcp"
+version = "0.1.3"
description = "Lark MCP server"
requires-python = ">=3.10"
dependencies = [
@@ -15,7 +15,7 @@ dependencies = [
]
[project.scripts]
-lzwcai-mcpskills-lark-mcp = "lzwcai_lark_mcp.main:main"
+lzwcai-lark-mcp = "lzwcai_lark_mcp.main:main"
[tool.hatch.build.targets.wheel]
packages = ["lzwcai_lark_mcp"]