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"
+ ]
+ }
+ }
+}
+