Monday.com MCP Server
by sakce
Verified
- mcp-server-monday
- src
- mcp_server_monday
from __future__ import annotations
import json
from typing import Optional
from mcp import types
from monday import MondayClient
from mcp_server_monday.constants import MONDAY_WORKSPACE_URL
async def handle_monday_list_items_in_groups(
boardId: str,
groupIds: list[str],
limit: int,
monday_client: MondayClient,
cursor: Optional[str] = None,
) -> list[types.TextContent]:
"""List all items in the specified groups of a Monday.com board"""
if groupIds and not cursor:
formatted_group_ids = ", ".join([f'"{group_id}"' for group_id in groupIds])
items_page_params = f"""
query_params: {{
rules: [
{{column_id: "group", compare_value: [{formatted_group_ids}], operator: any_of}}
]
}}
"""
else:
items_page_params = f'cursor: "{cursor}"'
items_page_params += f" limit: {limit}"
query = f"""
query {{
boards (ids: {boardId}) {{
items_page ({items_page_params}) {{
cursor
items {{
id
name
updates {{
id
body
}}
column_values {{
id
text
value
}}
}}
}}
}}
}}
"""
response = monday_client.custom._query(query)
return [
types.TextContent(
type="text",
text=f"Items in groups {groupIds} of Monday.com board {boardId}: {json.dumps(response)}",
)
]
async def handle_monday_list_subitems_in_items(
itemIds: list[str],
monday_client: MondayClient,
) -> list[types.TextContent]:
formatted_item_ids = ", ".join(itemIds)
get_subitems_in_item_query = f"""query
{{
items (ids: [{formatted_item_ids}]) {{
subitems {{
id
name
parent_item {{
id
}}
updates {{
id
body
}}
column_values {{
id
text
value
}}
}}
}}
}}"""
response = monday_client.custom._query(get_subitems_in_item_query)
return [
types.TextContent(
type="text",
text=f"Sub-items of Monday.com items {itemIds}: {json.dumps(response)}",
)
]
async def handle_monday_create_item(
boardId: str,
itemTitle: str,
monday_client: MondayClient,
groupId: Optional[str] = None,
parentItemId: Optional[str] = None,
columnValues: Optional[dict] = None,
) -> list[types.TextContent]:
"""Create a new item in a Monday.com Board. Optionally, specify the parent Item ID to create a Sub-item."""
if parentItemId is None and groupId is not None:
response = monday_client.items.create_item(
board_id=boardId,
group_id=groupId,
item_name=itemTitle,
column_values=columnValues,
)
elif parentItemId is not None and groupId is None:
response = monday_client.items.create_subitem(
parent_item_id=parentItemId,
subitem_name=itemTitle,
column_values=columnValues,
)
else:
return [
types.TextContent(
type="text",
text="You can set either groupId or parentItemId argument, but not both.",
)
]
try:
data = response["data"]
id_key = "create_item" if parentItemId is None else "create_subitem"
item_url = f"{MONDAY_WORKSPACE_URL}/boards/{boardId}/pulses/{data.get(id_key).get('id')}"
return [
types.TextContent(
type="text",
text=f"Created a new Monday.com item. URL: {item_url}",
)
]
except Exception as e:
return [
types.TextContent(
type="text",
text=f"Error creating Monday.com item: {e}",
)
]
async def handle_monday_update_item(
boardId: str,
itemId: str,
columnValues: dict[str],
monday_client: MondayClient,
):
response = monday_client.items.change_multiple_column_values(
board_id=boardId, item_id=itemId, column_values=columnValues
)
return [
types.TextContent(
type="text", text=f"Updated Monday.com item. {json.dumps(response)}"
)
]
async def handle_monday_create_update_on_item(
itemId: str,
updateText: str,
monday_client: MondayClient,
) -> list[types.TextContent]:
monday_client.updates.create_update(item_id=itemId, update_value=updateText)
return [
types.TextContent(
type="text", text=f"Created new update on Monday.com item: {updateText}"
)
]
async def handle_monday_get_item_by_id(
itemId: str,
monday_client: MondayClient,
) -> list[types.TextContent]:
"""Fetch specific Monday.com items by their IDs"""
try:
response = monday_client.items.fetch_items_by_id(ids=itemId)
return [
types.TextContent(
type="text",
text=f"Monday.com items: {json.dumps(response)}",
)
]
except Exception as e:
return [
types.TextContent(
type="text",
text=f"Error fetching Monday.com items: {e}",
)
]
async def handle_monday_get_item_updates(
itemId: str,
monday_client: MondayClient,
limit: int = 25,
) -> list[types.TextContent]:
"""Get updates for a specific item in Monday.com"""
query = f"""
query {{
items (ids: {itemId}) {{
updates (limit: {limit}) {{
id
body
created_at
creator {{
id
name
}}
assets {{
id
name
url
}}
}}
}}
}}
"""
# Setting no_log flag to true if it exists to prevent activity tracking
# Note: This is a preventative measure as the _query method might accept this parameter
try:
response = monday_client.custom._query(query, no_log=True)
except TypeError:
# If no_log param doesn't exist, try with default params
response = monday_client.custom._query(query)
if (
not response
or "data" not in response
or not response["data"]["items"]
or not response["data"]["items"][0]["updates"]
):
return [
types.TextContent(type="text", text=f"No updates found for item {itemId}.")
]
updates = response["data"]["items"][0]["updates"]
formatted_updates = []
for update in updates:
update_text = f"Update ID: {update['id']}\n"
update_text += f"Created: {update['created_at']}\n"
update_text += (
f"Creator: {update['creator']['name']} (ID: {update['creator']['id']})\n"
)
update_text += f"Body: {update['body']}\n"
# Add information about attached files if present
if update.get("assets"):
update_text += "\nAttached Files:\n"
for asset in update["assets"]:
update_text += f"- {asset['name']}: {asset['url']}\n"
update_text += "\n\n"
formatted_updates.append(update_text)
return [
types.TextContent(
type="text",
text=f"Updates for item {itemId}:\n\n{''.join(formatted_updates)}",
)
]
async def handle_monday_move_item_to_group(
monday_client: MondayClient, item_id: str, group_id: str
) -> list[types.TextContent]:
"""
Move an item to a group in a Monday.com board.
Args:
monday_client (MondayClient): The Monday.com client.
item_id (str): The ID of the item to move.
group_id (str): The ID of the group to move the item to.
"""
item = monday_client.items.move_item_to_group(item_id=item_id, group_id=group_id)
return [
types.TextContent(
type="text",
text=f"Moved item {item_id} to group {group_id}. ID of the moved item: {item['data']['move_item_to_group']['id']}",
)
]
async def handle_monday_delete_item(
monday_client: MondayClient, item_id: str
) -> list[types.TextContent]:
"""
Delete an item from a Monday.com board.
Args:
monday_client (MondayClient): The Monday.com client.
item_id (str): The ID of the item to delete.
"""
monday_client.items.delete_item_by_id(item_id=item_id)
return [types.TextContent(type="text", text=f"Deleted item {item_id}.")]
async def handle_monday_archive_item(
monday_client: MondayClient, item_id: str
) -> list[types.TextContent]:
"""
Archive an item from a Monday.com board.
Args:
monday_client (MondayClient): The Monday.com client.
item_id (str): The ID of the item to archive.
"""
monday_client.items.archive_item_by_id(item_id=item_id)
return [types.TextContent(type="text", text=f"Archived item {item_id}.")]