Merge PR #11: Add todo tools to client, FastMCP, and CLI
This commit is contained in:
@@ -159,6 +159,147 @@ class BasecampClient:
|
|||||||
else:
|
else:
|
||||||
raise Exception(f"Failed to get todo: {response.status_code} - {response.text}")
|
raise Exception(f"Failed to get todo: {response.status_code} - {response.text}")
|
||||||
|
|
||||||
|
def create_todo(self, project_id, todolist_id, content, description=None, assignee_ids=None,
|
||||||
|
completion_subscriber_ids=None, notify=False, due_on=None, starts_on=None):
|
||||||
|
"""
|
||||||
|
Create a new todo item in a todolist.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_id (str): Project ID
|
||||||
|
todolist_id (str): Todolist ID
|
||||||
|
content (str): The todo item's text (required)
|
||||||
|
description (str, optional): HTML description
|
||||||
|
assignee_ids (list, optional): List of person IDs to assign
|
||||||
|
completion_subscriber_ids (list, optional): List of person IDs to notify on completion
|
||||||
|
notify (bool, optional): Whether to notify assignees
|
||||||
|
due_on (str, optional): Due date in YYYY-MM-DD format
|
||||||
|
starts_on (str, optional): Start date in YYYY-MM-DD format
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: The created todo
|
||||||
|
"""
|
||||||
|
endpoint = f'buckets/{project_id}/todolists/{todolist_id}/todos.json'
|
||||||
|
data = {'content': content}
|
||||||
|
|
||||||
|
if description is not None:
|
||||||
|
data['description'] = description
|
||||||
|
if assignee_ids is not None:
|
||||||
|
data['assignee_ids'] = assignee_ids
|
||||||
|
if completion_subscriber_ids is not None:
|
||||||
|
data['completion_subscriber_ids'] = completion_subscriber_ids
|
||||||
|
if notify is not None:
|
||||||
|
data['notify'] = notify
|
||||||
|
if due_on is not None:
|
||||||
|
data['due_on'] = due_on
|
||||||
|
if starts_on is not None:
|
||||||
|
data['starts_on'] = starts_on
|
||||||
|
|
||||||
|
response = self.post(endpoint, data)
|
||||||
|
if response.status_code == 201:
|
||||||
|
return response.json()
|
||||||
|
else:
|
||||||
|
raise Exception(f"Failed to create todo: {response.status_code} - {response.text}")
|
||||||
|
|
||||||
|
def update_todo(self, project_id, todo_id, content=None, description=None, assignee_ids=None,
|
||||||
|
completion_subscriber_ids=None, notify=None, due_on=None, starts_on=None):
|
||||||
|
"""
|
||||||
|
Update an existing todo item.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_id (str): Project ID
|
||||||
|
todo_id (str): Todo ID
|
||||||
|
content (str, optional): The todo item's text
|
||||||
|
description (str, optional): HTML description
|
||||||
|
assignee_ids (list, optional): List of person IDs to assign
|
||||||
|
completion_subscriber_ids (list, optional): List of person IDs to notify on completion
|
||||||
|
notify (bool, optional): Whether to notify assignees
|
||||||
|
due_on (str, optional): Due date in YYYY-MM-DD format
|
||||||
|
starts_on (str, optional): Start date in YYYY-MM-DD format
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: The updated todo
|
||||||
|
"""
|
||||||
|
endpoint = f'buckets/{project_id}/todos/{todo_id}.json'
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
if content is not None:
|
||||||
|
data['content'] = content
|
||||||
|
if description is not None:
|
||||||
|
data['description'] = description
|
||||||
|
if assignee_ids is not None:
|
||||||
|
data['assignee_ids'] = assignee_ids
|
||||||
|
if completion_subscriber_ids is not None:
|
||||||
|
data['completion_subscriber_ids'] = completion_subscriber_ids
|
||||||
|
if notify is not None:
|
||||||
|
data['notify'] = notify
|
||||||
|
if due_on is not None:
|
||||||
|
data['due_on'] = due_on
|
||||||
|
if starts_on is not None:
|
||||||
|
data['starts_on'] = starts_on
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
raise ValueError("No fields provided to update")
|
||||||
|
|
||||||
|
response = self.put(endpoint, data)
|
||||||
|
if response.status_code == 200:
|
||||||
|
return response.json()
|
||||||
|
else:
|
||||||
|
raise Exception(f"Failed to update todo: {response.status_code} - {response.text}")
|
||||||
|
|
||||||
|
def delete_todo(self, project_id, todo_id):
|
||||||
|
"""
|
||||||
|
Delete a todo item.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_id (str): Project ID
|
||||||
|
todo_id (str): Todo ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if successful
|
||||||
|
"""
|
||||||
|
endpoint = f'buckets/{project_id}/todos/{todo_id}.json'
|
||||||
|
response = self.delete(endpoint)
|
||||||
|
if response.status_code == 204:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
raise Exception(f"Failed to delete todo: {response.status_code} - {response.text}")
|
||||||
|
|
||||||
|
def complete_todo(self, project_id, todo_id):
|
||||||
|
"""
|
||||||
|
Mark a todo as complete.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_id (str): Project ID
|
||||||
|
todo_id (str): Todo ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Completion details
|
||||||
|
"""
|
||||||
|
endpoint = f'buckets/{project_id}/todos/{todo_id}/completion.json'
|
||||||
|
response = self.post(endpoint)
|
||||||
|
if response.status_code == 201:
|
||||||
|
return response.json()
|
||||||
|
else:
|
||||||
|
raise Exception(f"Failed to complete todo: {response.status_code} - {response.text}")
|
||||||
|
|
||||||
|
def uncomplete_todo(self, project_id, todo_id):
|
||||||
|
"""
|
||||||
|
Mark a todo as incomplete.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_id (str): Project ID
|
||||||
|
todo_id (str): Todo ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if successful
|
||||||
|
"""
|
||||||
|
endpoint = f'buckets/{project_id}/todos/{todo_id}/completion.json'
|
||||||
|
response = self.delete(endpoint)
|
||||||
|
if response.status_code == 204:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
raise Exception(f"Failed to uncomplete todo: {response.status_code} - {response.text}")
|
||||||
|
|
||||||
# People methods
|
# People methods
|
||||||
def get_people(self):
|
def get_people(self):
|
||||||
"""Get all people in the account."""
|
"""Get all people in the account."""
|
||||||
|
|||||||
@@ -254,6 +254,218 @@ async def get_todos(project_id: str, todolist_id: str) -> Dict[str, Any]:
|
|||||||
"message": str(e)
|
"message": str(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def create_todo(project_id: str, todolist_id: str, content: str,
|
||||||
|
description: Optional[str] = None,
|
||||||
|
assignee_ids: Optional[List[str]] = None,
|
||||||
|
completion_subscriber_ids: Optional[List[str]] = None,
|
||||||
|
notify: bool = False,
|
||||||
|
due_on: Optional[str] = None,
|
||||||
|
starts_on: Optional[str] = None) -> Dict[str, Any]:
|
||||||
|
"""Create a new todo item in a todo list.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_id: Project ID
|
||||||
|
todolist_id: The todo list ID
|
||||||
|
content: The todo item's text (required)
|
||||||
|
description: HTML description of the todo
|
||||||
|
assignee_ids: List of person IDs to assign
|
||||||
|
completion_subscriber_ids: List of person IDs to notify on completion
|
||||||
|
notify: Whether to notify assignees
|
||||||
|
due_on: Due date in YYYY-MM-DD format
|
||||||
|
starts_on: Start date in YYYY-MM-DD format
|
||||||
|
"""
|
||||||
|
client = _get_basecamp_client()
|
||||||
|
if not client:
|
||||||
|
return _get_auth_error_response()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Use lambda to properly handle keyword arguments
|
||||||
|
todo = await _run_sync(
|
||||||
|
lambda: client.create_todo(
|
||||||
|
project_id, todolist_id, content,
|
||||||
|
description=description,
|
||||||
|
assignee_ids=assignee_ids,
|
||||||
|
completion_subscriber_ids=completion_subscriber_ids,
|
||||||
|
notify=notify,
|
||||||
|
due_on=due_on,
|
||||||
|
starts_on=starts_on
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"todo": todo,
|
||||||
|
"message": f"Todo '{content}' created successfully"
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error creating todo: {e}")
|
||||||
|
if "401" in str(e) and "expired" in str(e).lower():
|
||||||
|
return {
|
||||||
|
"error": "OAuth token expired",
|
||||||
|
"message": "Your Basecamp OAuth token expired during the API call. Please re-authenticate by visiting http://localhost:8000 and completing the OAuth flow again."
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"error": "Execution error",
|
||||||
|
"message": str(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def update_todo(project_id: str, todo_id: str,
|
||||||
|
content: Optional[str] = None,
|
||||||
|
description: Optional[str] = None,
|
||||||
|
assignee_ids: Optional[List[str]] = None,
|
||||||
|
completion_subscriber_ids: Optional[List[str]] = None,
|
||||||
|
notify: Optional[bool] = None,
|
||||||
|
due_on: Optional[str] = None,
|
||||||
|
starts_on: Optional[str] = None) -> Dict[str, Any]:
|
||||||
|
"""Update an existing todo item.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_id: Project ID
|
||||||
|
todo_id: The todo ID
|
||||||
|
content: The todo item's text
|
||||||
|
description: HTML description of the todo
|
||||||
|
assignee_ids: List of person IDs to assign
|
||||||
|
completion_subscriber_ids: List of person IDs to notify on completion
|
||||||
|
due_on: Due date in YYYY-MM-DD format
|
||||||
|
starts_on: Start date in YYYY-MM-DD format
|
||||||
|
"""
|
||||||
|
client = _get_basecamp_client()
|
||||||
|
if not client:
|
||||||
|
return _get_auth_error_response()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Guard against no-op updates
|
||||||
|
if all(v is None for v in [content, description, assignee_ids,
|
||||||
|
completion_subscriber_ids, notify,
|
||||||
|
due_on, starts_on]):
|
||||||
|
return {
|
||||||
|
"error": "Invalid input",
|
||||||
|
"message": "At least one field to update must be provided"
|
||||||
|
}
|
||||||
|
# Use lambda to properly handle keyword arguments
|
||||||
|
todo = await _run_sync(
|
||||||
|
lambda: client.update_todo(
|
||||||
|
project_id, todo_id,
|
||||||
|
content=content,
|
||||||
|
description=description,
|
||||||
|
assignee_ids=assignee_ids,
|
||||||
|
completion_subscriber_ids=completion_subscriber_ids,
|
||||||
|
notify=notify,
|
||||||
|
due_on=due_on,
|
||||||
|
starts_on=starts_on
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"todo": todo,
|
||||||
|
"message": "Todo updated successfully"
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
# existing exception handling…
|
||||||
|
...
|
||||||
|
logger.error(f"Error updating todo: {e}")
|
||||||
|
if "401" in str(e) and "expired" in str(e).lower():
|
||||||
|
return {
|
||||||
|
"error": "OAuth token expired",
|
||||||
|
"message": "Your Basecamp OAuth token expired during the API call. Please re-authenticate by visiting http://localhost:8000 and completing the OAuth flow again."
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"error": "Execution error",
|
||||||
|
"message": str(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def delete_todo(project_id: str, todo_id: str) -> Dict[str, Any]:
|
||||||
|
"""Delete a todo item.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_id: Project ID
|
||||||
|
todo_id: The todo ID
|
||||||
|
"""
|
||||||
|
client = _get_basecamp_client()
|
||||||
|
if not client:
|
||||||
|
return _get_auth_error_response()
|
||||||
|
|
||||||
|
try:
|
||||||
|
await _run_sync(client.delete_todo, project_id, todo_id)
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"message": "Todo deleted successfully"
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error deleting todo: {e}")
|
||||||
|
if "401" in str(e) and "expired" in str(e).lower():
|
||||||
|
return {
|
||||||
|
"error": "OAuth token expired",
|
||||||
|
"message": "Your Basecamp OAuth token expired during the API call. Please re-authenticate by visiting http://localhost:8000 and completing the OAuth flow again."
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"error": "Execution error",
|
||||||
|
"message": str(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def complete_todo(project_id: str, todo_id: str) -> Dict[str, Any]:
|
||||||
|
"""Mark a todo item as complete.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_id: Project ID
|
||||||
|
todo_id: The todo ID
|
||||||
|
"""
|
||||||
|
client = _get_basecamp_client()
|
||||||
|
if not client:
|
||||||
|
return _get_auth_error_response()
|
||||||
|
|
||||||
|
try:
|
||||||
|
completion = await _run_sync(client.complete_todo, project_id, todo_id)
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"completion": completion,
|
||||||
|
"message": "Todo marked as complete"
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error completing todo: {e}")
|
||||||
|
if "401" in str(e) and "expired" in str(e).lower():
|
||||||
|
return {
|
||||||
|
"error": "OAuth token expired",
|
||||||
|
"message": "Your Basecamp OAuth token expired during the API call. Please re-authenticate by visiting http://localhost:8000 and completing the OAuth flow again."
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"error": "Execution error",
|
||||||
|
"message": str(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def uncomplete_todo(project_id: str, todo_id: str) -> Dict[str, Any]:
|
||||||
|
"""Mark a todo item as incomplete.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_id: Project ID
|
||||||
|
todo_id: The todo ID
|
||||||
|
"""
|
||||||
|
client = _get_basecamp_client()
|
||||||
|
if not client:
|
||||||
|
return _get_auth_error_response()
|
||||||
|
|
||||||
|
try:
|
||||||
|
await _run_sync(client.uncomplete_todo, project_id, todo_id)
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"message": "Todo marked as incomplete"
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error uncompleting todo: {e}")
|
||||||
|
if "401" in str(e) and "expired" in str(e).lower():
|
||||||
|
return {
|
||||||
|
"error": "OAuth token expired",
|
||||||
|
"message": "Your Basecamp OAuth token expired during the API call. Please re-authenticate by visiting http://localhost:8000 and completing the OAuth flow again."
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"error": "Execution error",
|
||||||
|
"message": str(e)
|
||||||
|
}
|
||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
async def global_search(query: str) -> Dict[str, Any]:
|
async def global_search(query: str) -> Dict[str, Any]:
|
||||||
"""Search projects, todos and campfire messages across all projects.
|
"""Search projects, todos and campfire messages across all projects.
|
||||||
|
|||||||
@@ -88,6 +88,80 @@ class MCPServer:
|
|||||||
"required": ["project_id", "todolist_id"]
|
"required": ["project_id", "todolist_id"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "create_todo",
|
||||||
|
"description": "Create a new todo item in a todo list",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"project_id": {"type": "string", "description": "Project ID"},
|
||||||
|
"todolist_id": {"type": "string", "description": "The todo list ID"},
|
||||||
|
"content": {"type": "string", "description": "The todo item's text (required)"},
|
||||||
|
"description": {"type": "string", "description": "HTML description of the todo"},
|
||||||
|
"assignee_ids": {"type": "array", "items": {"type": "string"}, "description": "List of person IDs to assign"},
|
||||||
|
"completion_subscriber_ids": {"type": "array", "items": {"type": "string"}, "description": "List of person IDs to notify on completion"},
|
||||||
|
"notify": {"type": "boolean", "description": "Whether to notify assignees"},
|
||||||
|
"due_on": {"type": "string", "description": "Due date in YYYY-MM-DD format"},
|
||||||
|
"starts_on": {"type": "string", "description": "Start date in YYYY-MM-DD format"}
|
||||||
|
},
|
||||||
|
"required": ["project_id", "todolist_id", "content"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "update_todo",
|
||||||
|
"description": "Update an existing todo item",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"project_id": {"type": "string", "description": "Project ID"},
|
||||||
|
"todo_id": {"type": "string", "description": "The todo ID"},
|
||||||
|
"content": {"type": "string", "description": "The todo item's text"},
|
||||||
|
"description": {"type": "string", "description": "HTML description of the todo"},
|
||||||
|
"assignee_ids": {"type": "array", "items": {"type": "string"}, "description": "List of person IDs to assign"},
|
||||||
|
"completion_subscriber_ids": {"type": "array", "items": {"type": "string"}, "description": "List of person IDs to notify on completion"},
|
||||||
|
"notify": {"type": "boolean", "description": "Whether to notify assignees"},
|
||||||
|
"due_on": {"type": "string", "description": "Due date in YYYY-MM-DD format"},
|
||||||
|
"starts_on": {"type": "string", "description": "Start date in YYYY-MM-DD format"}
|
||||||
|
},
|
||||||
|
"required": ["project_id", "todo_id"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "delete_todo",
|
||||||
|
"description": "Delete a todo item",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"project_id": {"type": "string", "description": "Project ID"},
|
||||||
|
"todo_id": {"type": "string", "description": "The todo ID"}
|
||||||
|
},
|
||||||
|
"required": ["project_id", "todo_id"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "complete_todo",
|
||||||
|
"description": "Mark a todo item as complete",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"project_id": {"type": "string", "description": "Project ID"},
|
||||||
|
"todo_id": {"type": "string", "description": "The todo ID"}
|
||||||
|
},
|
||||||
|
"required": ["project_id", "todo_id"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "uncomplete_todo",
|
||||||
|
"description": "Mark a todo item as incomplete",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"project_id": {"type": "string", "description": "Project ID"},
|
||||||
|
"todo_id": {"type": "string", "description": "The todo ID"}
|
||||||
|
},
|
||||||
|
"required": ["project_id", "todo_id"]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "search_basecamp",
|
"name": "search_basecamp",
|
||||||
"description": "Search across Basecamp projects, todos, and messages",
|
"description": "Search across Basecamp projects, todos, and messages",
|
||||||
@@ -813,6 +887,91 @@ class MCPServer:
|
|||||||
"count": len(todos)
|
"count": len(todos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
elif tool_name == "create_todo":
|
||||||
|
project_id = arguments.get("project_id")
|
||||||
|
todolist_id = arguments.get("todolist_id")
|
||||||
|
content = arguments.get("content")
|
||||||
|
description = arguments.get("description")
|
||||||
|
assignee_ids = arguments.get("assignee_ids")
|
||||||
|
completion_subscriber_ids = arguments.get("completion_subscriber_ids")
|
||||||
|
notify_arg = arguments.get("notify", False)
|
||||||
|
if isinstance(notify_arg, str):
|
||||||
|
notify = notify_arg.strip().lower() in ("1", "true", "yes", "on")
|
||||||
|
else:
|
||||||
|
notify = bool(notify_arg)
|
||||||
|
due_on = arguments.get("due_on")
|
||||||
|
starts_on = arguments.get("starts_on")
|
||||||
|
|
||||||
|
todo = client.create_todo(
|
||||||
|
project_id, todolist_id, content,
|
||||||
|
description=description,
|
||||||
|
assignee_ids=assignee_ids,
|
||||||
|
completion_subscriber_ids=completion_subscriber_ids,
|
||||||
|
notify=notify,
|
||||||
|
due_on=due_on,
|
||||||
|
starts_on=starts_on
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"todo": todo,
|
||||||
|
"message": f"Todo '{content}' created successfully"
|
||||||
|
}
|
||||||
|
|
||||||
|
elif tool_name == "update_todo":
|
||||||
|
project_id = arguments.get("project_id")
|
||||||
|
todo_id = arguments.get("todo_id")
|
||||||
|
content = arguments.get("content")
|
||||||
|
description = arguments.get("description")
|
||||||
|
assignee_ids = arguments.get("assignee_ids")
|
||||||
|
completion_subscriber_ids = arguments.get("completion_subscriber_ids")
|
||||||
|
due_on = arguments.get("due_on")
|
||||||
|
starts_on = arguments.get("starts_on")
|
||||||
|
notify = arguments.get("notify")
|
||||||
|
|
||||||
|
todo = client.update_todo(
|
||||||
|
project_id, todo_id,
|
||||||
|
content=content,
|
||||||
|
description=description,
|
||||||
|
assignee_ids=assignee_ids,
|
||||||
|
completion_subscriber_ids=completion_subscriber_ids,
|
||||||
|
notify=notify,
|
||||||
|
due_on=due_on,
|
||||||
|
starts_on=starts_on
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"todo": todo,
|
||||||
|
"message": "Todo updated successfully"
|
||||||
|
}
|
||||||
|
|
||||||
|
elif tool_name == "delete_todo":
|
||||||
|
project_id = arguments.get("project_id")
|
||||||
|
todo_id = arguments.get("todo_id")
|
||||||
|
client.delete_todo(project_id, todo_id)
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"message": "Todo deleted successfully"
|
||||||
|
}
|
||||||
|
|
||||||
|
elif tool_name == "complete_todo":
|
||||||
|
project_id = arguments.get("project_id")
|
||||||
|
todo_id = arguments.get("todo_id")
|
||||||
|
completion = client.complete_todo(project_id, todo_id)
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"completion": completion,
|
||||||
|
"message": "Todo marked as complete"
|
||||||
|
}
|
||||||
|
|
||||||
|
elif tool_name == "uncomplete_todo":
|
||||||
|
project_id = arguments.get("project_id")
|
||||||
|
todo_id = arguments.get("todo_id")
|
||||||
|
client.uncomplete_todo(project_id, todo_id)
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"message": "Todo marked as incomplete"
|
||||||
|
}
|
||||||
|
|
||||||
elif tool_name == "search_basecamp":
|
elif tool_name == "search_basecamp":
|
||||||
query = arguments.get("query")
|
query = arguments.get("query")
|
||||||
project_id = arguments.get("project_id")
|
project_id = arguments.get("project_id")
|
||||||
|
|||||||
Reference in New Issue
Block a user