diff --git a/.gitignore b/.gitignore index ba0430d..95d9cfc 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ -__pycache__/ \ No newline at end of file +__pycache__/ +*.txt +.DS* + +test* \ No newline at end of file diff --git a/lzwcai_lark_mcp/card.txt b/lzwcai_lark_mcp/card.txt deleted file mode 100644 index 6a07418..0000000 --- a/lzwcai_lark_mcp/card.txt +++ /dev/null @@ -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": "**确认单号:** ${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" - }, - { - "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": "**其他说明:**", - "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" - } -} \ No newline at end of file diff --git a/lzwcai_lark_mcp/lzwcai_lark_mcp/tools.py b/lzwcai_lark_mcp/lzwcai_lark_mcp/tools.py index 6b40a9e..52d1c58 100644 --- a/lzwcai_lark_mcp/lzwcai_lark_mcp/tools.py +++ b/lzwcai_lark_mcp/lzwcai_lark_mcp/tools.py @@ -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() diff --git a/lzwcai_lark_mcp/pyproject.toml b/lzwcai_lark_mcp/pyproject.toml index cc5b42a..6e625a2 100644 --- a/lzwcai_lark_mcp/pyproject.toml +++ b/lzwcai_lark_mcp/pyproject.toml @@ -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 = [ diff --git a/lzwcai_lark_mcp/test.py b/lzwcai_lark_mcp/test.py index 0fecc1c..2657ed6 100644 --- a/lzwcai_lark_mcp/test.py +++ b/lzwcai_lark_mcp/test.py @@ -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, diff --git a/mcp.json b/mcp.json new file mode 100644 index 0000000..3f161d4 --- /dev/null +++ b/mcp.json @@ -0,0 +1,17 @@ +{ + "mcpServers": { + "lark-mcp": { + "command": "npx", + "args": [ + "-y", + "@larksuiteoapi/lark-mcp", + "mcp", + "-a", + "cli_a8d0e0c140169013", + "-s", + "yEc0E8Aoo8Mo9NPPzphidez51xB71HXW" + ] + } + } +} +