import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { api } from "../api/client.js";
import {
formatResponse,
validateDeleteOperation,
createDeleteSafetyError,
validateBoardAccess,
validateBoardWideOperation,
createBoardFocusError,
isBoardFocusEnabled,
getFocusedBoardId,
} from "../utils/index.js";
import { BoardTypeSchema } from "../types/index.js";
export function registerBoardTools(server: McpServer) {
// Only register list_boards if not in board focus mode
if (!isBoardFocusEnabled()) {
server.tool("list_boards", "List all boards", {}, async () => {
// Double-check board-wide operation access
const accessCheck = validateBoardWideOperation();
if (!accessCheck.allowed) {
return formatResponse(createBoardFocusError(accessCheck));
}
const response = await api.get("/projects/list-of-boards");
return formatResponse(response.data);
});
}
// Get board details - always available but with board access validation
server.tool(
"get_board",
"Get details of a specific board",
{
board_id: z.number().int().positive().describe("Board ID"),
},
async (args) => {
const { board_id } = args;
// Validate board access
const accessCheck = validateBoardAccess(board_id);
if (!accessCheck.allowed) {
return formatResponse(createBoardFocusError(accessCheck));
}
const response = await api.get(`/projects/${board_id}`);
return formatResponse(response.data);
}
);
// Only register create_board if not in board focus mode
if (!isBoardFocusEnabled()) {
server.tool(
"create_board",
"Create a new board",
{
title: z.string().min(1).describe("Board title"),
description: z.string().optional().describe("Board description"),
type: BoardTypeSchema.default("to-do").describe("Board type"),
},
async (args) => {
// Double-check board-wide operation access
const accessCheck = validateBoardWideOperation();
if (!accessCheck.allowed) {
return formatResponse(createBoardFocusError(accessCheck));
}
const { title, description, type } = args;
const boardData: any = {
title,
type,
};
if (description) {
boardData.description = description;
}
const response = await api.post("/projects", { board: boardData });
return formatResponse(response.data);
}
);
}
// Create a new stage - always available but with board access validation
server.tool(
"create_stage",
"Create a new stage in a board",
{
board_id: z.number().int().positive().describe("Board ID"),
title: z.string().min(1).describe("Stage title"),
position: z.number().optional().describe("Stage position (optional)"),
},
async (args) => {
const { board_id, title, position } = args;
// Validate board access
const accessCheck = validateBoardAccess(board_id);
if (!accessCheck.allowed) {
return formatResponse(createBoardFocusError(accessCheck));
}
const stageData: any = {
title,
};
if (position !== undefined) {
stageData.position = position;
}
const response = await api.post(
`/projects/${board_id}/stage-create`,
stageData
);
return formatResponse(response.data);
}
);
// Delete a board - conditional registration and validation
if (!isBoardFocusEnabled()) {
server.tool(
"delete_board",
"Delete a board and all its data",
{
board_id: z.number().int().positive().describe("Board ID"),
confirm_delete: z
.union([z.boolean(), z.string()])
.optional()
.describe(
"Confirmation required: set to true, 'yes', or 'confirm' to proceed"
),
},
async (args) => {
const { board_id, confirm_delete } = args;
// Validate delete operation safety
const safetyCheck = validateDeleteOperation("board", confirm_delete);
if (!safetyCheck.allowed) {
return formatResponse(createDeleteSafetyError(safetyCheck));
}
// Validate board access
const accessCheck = validateBoardAccess(board_id);
if (!accessCheck.allowed) {
return formatResponse(createBoardFocusError(accessCheck));
}
const response = await api.delete(`/projects/${board_id}`);
return formatResponse(response.data);
}
);
}
}