feat(tools): 支持向多个接收者发送卡片消息
重构 send_card_message 为 send_notion_card,支持接收者 ID 列表 更新 .gitignore 以忽略更多临时文件 升级项目版本至 0.1.17 删除未使用的 card.txt 模板文件
This commit is contained in:
@@ -1,199 +0,0 @@
|
||||
{
|
||||
"schema": "2.0",
|
||||
"config": {
|
||||
"update_multi": true,
|
||||
"style": {
|
||||
"text_size": {
|
||||
"normal_v2": {
|
||||
"default": "normal",
|
||||
"pc": "normal",
|
||||
"mobile": "heading"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"direction": "vertical",
|
||||
"elements": [
|
||||
{
|
||||
"tag": "form",
|
||||
"elements": [
|
||||
{
|
||||
"tag": "markdown",
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"tag": "multi_select_static",
|
||||
"placeholder": {
|
||||
"tag": "plain_text",
|
||||
"content": "请选择资产变动项"
|
||||
},
|
||||
"options": "${asset_list}",
|
||||
"type": "default",
|
||||
"width": "fill",
|
||||
"required": false,
|
||||
"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>**",
|
||||
"text_align": "left",
|
||||
"text_size": "normal_v2",
|
||||
"margin": "0px 0px 0px 0px"
|
||||
},
|
||||
{
|
||||
"tag": "input",
|
||||
"placeholder": {
|
||||
"tag": "plain_text",
|
||||
"content": "请输入"
|
||||
},
|
||||
"default_value": "",
|
||||
"width": "fill",
|
||||
"name": "input_remark",
|
||||
"margin": "0px 0px 0px 0px"
|
||||
},
|
||||
{
|
||||
"tag": "column_set",
|
||||
"flex_mode": "flow",
|
||||
"horizontal_spacing": "8px",
|
||||
"horizontal_align": "right",
|
||||
"columns": [
|
||||
{
|
||||
"tag": "column",
|
||||
"width": "auto",
|
||||
"elements": [
|
||||
{
|
||||
"tag": "button",
|
||||
"text": {
|
||||
"tag": "plain_text",
|
||||
"content": "确认"
|
||||
},
|
||||
"type": "primary_filled",
|
||||
"width": "default",
|
||||
"size": "medium",
|
||||
"behaviors": [
|
||||
{
|
||||
"type": "callback",
|
||||
"value": {
|
||||
"action": "card.action.trigger"
|
||||
}
|
||||
}
|
||||
],
|
||||
"form_action_type": "submit",
|
||||
"name": "confirm_button",
|
||||
"margin": "4px 0px 4px 0px"
|
||||
}
|
||||
],
|
||||
"vertical_spacing": "8px",
|
||||
"horizontal_align": "left",
|
||||
"vertical_align": "top"
|
||||
},
|
||||
{
|
||||
"tag": "column",
|
||||
"width": "auto",
|
||||
"elements": [
|
||||
{
|
||||
"tag": "button",
|
||||
"text": {
|
||||
"tag": "plain_text",
|
||||
"content": "反馈问题"
|
||||
},
|
||||
"type": "default",
|
||||
"width": "default",
|
||||
"confirm": {
|
||||
"title": {
|
||||
"tag": "plain_text",
|
||||
"content": "反馈误报并废除该确认单吗?"
|
||||
},
|
||||
"text": {
|
||||
"tag": "plain_text",
|
||||
"content": "${remark}"
|
||||
}
|
||||
},
|
||||
"behaviors": [
|
||||
{
|
||||
"type": "callback",
|
||||
"value": {
|
||||
"action": "card.action.trigger"
|
||||
}
|
||||
}
|
||||
],
|
||||
"form_action_type": "submit",
|
||||
"name": "feedback_button",
|
||||
"margin": "4px 0px 4px 0px"
|
||||
}
|
||||
],
|
||||
"vertical_spacing": "8px",
|
||||
"horizontal_align": "left",
|
||||
"vertical_align": "top"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"direction": "vertical",
|
||||
"horizontal_align": "left",
|
||||
"vertical_align": "top",
|
||||
"padding": "12px 12px 12px 12px",
|
||||
"margin": "0px 0px 0px 0px",
|
||||
"name": "asset_confirmation_form"
|
||||
},
|
||||
{
|
||||
"tag": "hr",
|
||||
"margin": "0px 0px 0px 0px"
|
||||
}
|
||||
]
|
||||
},
|
||||
"header": {
|
||||
"title": {
|
||||
"tag": "plain_text",
|
||||
"content": "资产变动单"
|
||||
},
|
||||
"subtitle": {
|
||||
"tag": "plain_text",
|
||||
"content": ""
|
||||
},
|
||||
"text_tag_list": [
|
||||
{
|
||||
"tag": "text_tag",
|
||||
"text": {
|
||||
"tag": "plain_text",
|
||||
"content": "待确认"
|
||||
},
|
||||
"color": "orange"
|
||||
}
|
||||
],
|
||||
"template": "blue",
|
||||
"icon": {
|
||||
"tag": "standard_icon",
|
||||
"token": "googledrive_outlined"
|
||||
},
|
||||
"padding": "12px 8px 12px 8px"
|
||||
}
|
||||
}
|
||||
@@ -51,14 +51,17 @@ tools = [
|
||||
}
|
||||
),
|
||||
Tool(
|
||||
name="send_card_message",
|
||||
description="发送消息卡片,入参为receiver_id、person_id和image_key",
|
||||
name="send_notion_card",
|
||||
description="发送消息卡片,入参为receiver_ids、person_id和image_key",
|
||||
inputSchema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"receiver_id": {
|
||||
"type": "string",
|
||||
"description": "消息接收者ID"
|
||||
"receiver_ids": {
|
||||
"type": "array",
|
||||
"description": "消息接收者ID列表",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"person_id": {
|
||||
"type": "string",
|
||||
@@ -69,7 +72,7 @@ tools = [
|
||||
"description": "图片image_key"
|
||||
}
|
||||
},
|
||||
"required": ["receiver_id", "image_key"]
|
||||
"required": ["receiver_ids", "image_key"]
|
||||
}
|
||||
),
|
||||
Tool(
|
||||
@@ -1768,8 +1771,25 @@ def send_feedback_card(
|
||||
raise RuntimeError("failed to send message to any receiver")
|
||||
|
||||
return json.dumps(message_ids, ensure_ascii=False)
|
||||
|
||||
|
||||
|
||||
|
||||
def send_notion_card(token: str, receiver_ids: List[str], person_id: str, image_key: str) -> str:
|
||||
message_ids: List[str] = []
|
||||
for receiver_id in receiver_ids:
|
||||
normalized_receiver_id = str(receiver_id).strip()
|
||||
if not normalized_receiver_id:
|
||||
continue
|
||||
try:
|
||||
message_id = send_card_message(token, normalized_receiver_id, person_id, image_key)
|
||||
if message_id:
|
||||
message_ids.append(message_id)
|
||||
except Exception:
|
||||
pass
|
||||
if not message_ids:
|
||||
raise RuntimeError("failed to send message to any receiver")
|
||||
return json.dumps(message_ids, ensure_ascii=False)
|
||||
|
||||
|
||||
def send_card_message(token: str, receiver_id: str, person_id: str, image_key: str) -> str:
|
||||
utc_now = datetime.now(timezone.utc)
|
||||
cst_now = utc_now + timedelta(hours=8)
|
||||
@@ -1958,16 +1978,29 @@ async def handle_call_tool(name: str, arguments: Dict[str, object], token: str)
|
||||
result = upload_image_by_url(token, image_source, image_type)
|
||||
else:
|
||||
result = upload_image_by_file(token, image_source, image_type)
|
||||
elif name == "send_card_message":
|
||||
elif name == "send_notion_card":
|
||||
image_key = str(arguments.get("image_key", "")).strip()
|
||||
receiver_id = str(arguments.get("receiver_id", "")).strip()
|
||||
receiver_ids_value = arguments.get("receiver_ids")
|
||||
raw_person_id = arguments.get("person_id")
|
||||
person_id = str(raw_person_id).strip() if raw_person_id is not None else ""
|
||||
if not receiver_id:
|
||||
raise ValueError("missing receiver_id")
|
||||
if not receiver_ids_value:
|
||||
raise ValueError("missing receiver_ids")
|
||||
if isinstance(receiver_ids_value, str):
|
||||
normalized = receiver_ids_value.strip()
|
||||
receiver_ids = [normalized] if normalized else []
|
||||
elif isinstance(receiver_ids_value, list):
|
||||
receiver_ids = [
|
||||
str(item).strip()
|
||||
for item in receiver_ids_value
|
||||
if str(item).strip()
|
||||
]
|
||||
else:
|
||||
raise ValueError("receiver_ids must be string or list of string")
|
||||
if not receiver_ids:
|
||||
raise ValueError("missing receiver_ids")
|
||||
if not image_key:
|
||||
raise ValueError("missing image_key")
|
||||
result = send_card_message(token, receiver_id, person_id, image_key)
|
||||
result = send_notion_card(token, receiver_ids, person_id, image_key)
|
||||
elif name == "send_confirmation_card":
|
||||
user_id = str(arguments.get("user_id", "")).strip()
|
||||
order_number = str(arguments.get("order_number", "")).strip()
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "lzwcai-lark-mcp"
|
||||
version = "0.1.16"
|
||||
version = "0.1.17"
|
||||
description = "Lark MCP server"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
|
||||
@@ -35,7 +35,7 @@ def main() -> None:
|
||||
mcp_module.types = types_module
|
||||
sys.modules["mcp"] = mcp_module
|
||||
sys.modules["mcp.types"] = types_module
|
||||
from lzwcai_lark_mcp.tools import send_card_message, send_stranger_card
|
||||
from lzwcai_lark_mcp.tools import send_notion_card, send_stranger_card
|
||||
app_id = os.getenv("app_id", "")
|
||||
app_secret = os.getenv("app_secret", "")
|
||||
auth_url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"
|
||||
@@ -53,18 +53,16 @@ def main() -> None:
|
||||
if not token:
|
||||
raise RuntimeError(f"lark auth response missing token: {data}")
|
||||
user_id = "gegg1d78"
|
||||
receiver_id = os.getenv("receiver_id", user_id)
|
||||
person_id = os.getenv("person_id", "")
|
||||
image_key = os.getenv("image_key", "").strip()
|
||||
if not image_key:
|
||||
raise RuntimeError("missing image_key")
|
||||
card_message_id = send_card_message(
|
||||
receiver_ids = ["843ga2gb", "gegg1d78"]
|
||||
person_id = "gegg1d78"
|
||||
image_key = "img_v3_0210i_94bdf5de-5c89-49f0-a793-c504c7377c7g"
|
||||
card_message_ids = send_notion_card(
|
||||
token,
|
||||
receiver_id,
|
||||
receiver_ids,
|
||||
person_id,
|
||||
image_key
|
||||
)
|
||||
print(card_message_id)
|
||||
print(card_message_ids)
|
||||
result = send_stranger_card(
|
||||
token,
|
||||
user_id,
|
||||
|
||||
Reference in New Issue
Block a user