feat(lark-mcp): 重构资产确认卡片并更新项目配置

重构 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 环境变量配置
This commit is contained in:
bin
2026-03-03 11:34:45 +08:00
parent 712d9b9aa5
commit fa226733b8
6 changed files with 148 additions and 155 deletions

View File

@@ -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": "**<font color='blue-600'>用户:</font>** <person id=${user_id} show_name=true show_avatar=true style='normal'></person>",
"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": "**<font color='blue-600'>发生时间:</font>** <font color='grey'>${change_time}</font>",
"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": "**<font color='blue-600'>\\*请准确选择属于您的变动项:</font>**",
"content": "**<font color='blue-600'>确认单号:</font>** <font color='grey'>${order_number}</font>",
"text_align": "left",
"text_size": "normal"
},
{
"tag": "markdown",
"content": "**<font color='blue-600'>用户:</font>** <person id=${user_id} show_name=true show_avatar=true style='normal'></person>",
"text_align": "left",
"text_size": "normal"
},
{
"tag": "markdown",
"content": "**<font color='blue-600'>发生时间:</font>** <font color='grey'>${change_time}</font>",
"text_align": "left",
"text_size": "normal"
},
{
"tag": "markdown",
"content": "**<font color='blue-600'>\\*请准确选择关于您的变动项:</font>**",
"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": "**<font color='blue-600'>其他说明:</font>**",
@@ -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"
}
}
],

View File

@@ -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"**<font color='blue-600'>用户:</font>** <person id={normalized_user_id} show_name=true show_avatar=true style='normal'></person>",
"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"**<font color='blue-600'>发生时间:</font>** <font color='grey'>{normalized_time}</font>",
"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": "**<font color='blue-600'>\\*请准确选择属于您的变动项:</font>**",
"content": f"**<font color='blue-600'>确认单号:</font>** <font color='grey'>{normalized_order_number}</font>",
"text_align": "left",
"text_size": "normal"
},
{
"tag": "markdown",
"content": f"**<font color='blue-600'>用户:</font>** <person id={normalized_user_id} show_name=true show_avatar=true style='normal'></person>",
"text_align": "left",
"text_size": "normal"
},
{
"tag": "markdown",
"content": f"**<font color='blue-600'>发生时间:</font>** <font color='grey'>{normalized_time}</font>",
"text_align": "left",
"text_size": "normal"
},
{
"tag": "markdown",
"content": "**<font color='blue-600'>\\*请准确选择关于您的变动项:</font>**",
"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": "**<font color='blue-600'>其他说明:</font>**",
@@ -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)]

View File

@@ -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 @@
}
}
}
}
}

View File

@@ -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"]