Skip to main content
Glama
doc.tools.ts15.3 kB
import { Tool } from "@modelcontextprotocol/sdk/types.js"; import { SearchDocsParams, ClickUpDoc, CreateDocParams, GetDocPagesParams, ClickUpDocPage, CreateDocPageParams, GetDocPageContentParams, EditDocPageContentParams, } from "../types.js"; import { ClickUpService } from "../services/clickup.service.js"; import { logger } from "../logger.js"; // Common descriptions const teamIdDescription = "The ID of the Workspace (Team) to operate on."; const archivedDescription = "Whether to include archived items (true or false)."; // Tool Definitions export const searchDocsTool: Tool = { name: "clickup_search_docs", description: "Searches for Docs within a Workspace (Team).", inputSchema: { type: "object", properties: { team_id: { type: "string", description: teamIdDescription }, query: { type: "string", description: "Search string for Doc name/content.", }, include_archived: { type: "boolean", description: archivedDescription }, }, required: ["team_id"], }, outputSchema: { type: "object", properties: { docs: { type: "array", items: { type: "object", properties: { id: { type: "string" }, name: { type: "string" } } } } }, description: "An object containing an array of doc objects in the 'docs' property.", }, }; export const createDocTool: Tool = { name: "clickup_create_doc", description: "Creates a new Doc within a Workspace.", inputSchema: { type: "object", properties: { workspace_id: { type: "string", description: "The ID of the Workspace (Team ID) where the Doc will be created. This corresponds to the team_id from get_teams.", }, name: { type: "string", description: "Name of the new Doc." }, parent: { type: "object", description: "Optional: The parent of the new Doc (e.g., another Doc, Space, Folder, List).", properties: { id: { type: "string", description: "ID of the parent resource.", }, type: { type: "number", description: "Numeric type of the parent: 4 for Space, 5 for Folder, 6 for List, 7 for Everything (Workspace/Team level), 12 for Workspace (synonymous with 7 in this context often). If creating at workspace root, parent might not be needed or use type 7 or 12 with workspace ID.", }, }, required: ["id", "type"], }, visibility: { type: "string", enum: ["PUBLIC", "PRIVATE", "PERSONAL", "HIDDEN"], description: "Optional: Visibility of the Doc. Must be one of: PUBLIC, PRIVATE, PERSONAL, HIDDEN.", }, create_page: { type: "boolean", description: "Optional: Whether to automatically create an initial page within the new Doc. Defaults to true.", }, }, required: ["workspace_id", "name"], }, outputSchema: { type: "object", properties: { doc: { type: "object", properties: { id: { type: "string" }, name: { type: "string" } } } }, description: "An object containing the created doc object in the 'doc' property.", }, }; export const getDocPagesTool: Tool = { name: "clickup_get_doc_pages", description: "Retrieves the list of pages within a specific Doc.", inputSchema: { type: "object", properties: { workspace_id: { type: "string", description: "The ID of the Workspace (Team ID) where the Doc resides.", }, doc_id: { type: "string", description: "The ID of the Doc." }, }, required: ["workspace_id", "doc_id"], }, outputSchema: { type: "object", properties: { pages: { type: "array", items: { type: "object", properties: { id: { type: "string" }, name: { type: "string" } } } } }, description: "An object containing an array of page objects in the 'pages' property.", }, }; export const createDocPageTool: Tool = { name: "clickup_create_doc_page", description: "Creates a new page within a specific Doc.", inputSchema: { type: "object", properties: { workspace_id: { type: "string", description: "The ID of the Workspace (Team ID) where the Doc resides.", }, doc_id: { type: "string", description: "The ID of the Doc to add the page to.", }, name: { type: "string", description: "The name (title) of the new page.", }, content: { type: "string", description: "Markdown content for the new page (optional).", }, orderindex: { type: "number", description: "Position of the page in the Doc structure (optional). Note: Not used in v3 create page API.", }, parent_page_id: { type: "string", description: "Optional: The ID of the parent page to nest this page under.", }, sub_title: { type: "string", description: "Optional: The subtitle of the new page.", }, content_format: { type: "string", description: "Optional: The format of the page content (e.g., 'text/md', 'text/plain'). Defaults to 'text/md'.", }, }, required: ["workspace_id", "doc_id", "name"], }, outputSchema: { type: "object", properties: { page: { type: "object", properties: { id: { type: "string" }, name: { type: "string" } } } }, description: "An object containing the created page object in the 'page' property.", }, }; export const getDocPageContentTool: Tool = { name: "clickup_get_doc_page_content", description: "Retrieves the content (Markdown) of a specific Doc page.", inputSchema: { type: "object", properties: { workspace_id: { type: "string", description: "The ID of the Workspace (Team ID) where the Doc resides.", }, doc_id: { type: "string", description: "The ID of the Doc containing the page.", }, page_id: { type: "string", description: "The ID of the page." }, content_format: { type: "string", description: "Optional: The format to return the page content in (e.g., 'text/md', 'text/plain'). Defaults to 'text/md'.", }, }, required: ["workspace_id", "doc_id", "page_id"], }, outputSchema: { type: "object", properties: { content: { type: "string" }, page: { type: "object", properties: { id: { type: "string" }, name: { type: "string" } } } }, description: "An object containing the page content and metadata.", }, }; export const editDocPageContentTool: Tool = { name: "clickup_edit_doc_page_content", description: "Updates the content and/or title of a specific Doc page.", inputSchema: { type: "object", properties: { workspace_id: { type: "string", description: "The ID of the Workspace (Team ID) where the Doc resides.", }, doc_id: { type: "string", description: "The ID of the Doc containing the page.", }, page_id: { type: "string", description: "The ID of the page to update." }, content: { type: "string", description: "The new Markdown content for the page.", }, title: { type: "string", description: "The new title for the page (optional, maps to API 'name').", }, sub_title: { type: "string", description: "Optional: The new subtitle for the page.", }, content_edit_mode: { type: "string", enum: ["replace", "append", "prepend"], description: "Optional: Strategy for updating content (default: replace).", }, content_format: { type: "string", description: "Optional: Format of the page content (e.g., 'text/md', default: text/md).", }, }, required: ["workspace_id", "doc_id", "page_id", "content"], }, outputSchema: { type: "object", properties: { page: { type: "object", properties: { id: { type: "string" }, name: { type: "string" } } }, success: { type: "boolean" } }, description: "An object containing the updated page object and success status.", }, }; // Handler Functions export async function handleSearchDocs( clickUpService: ClickUpService, args: Record<string, unknown>, ) { const params = args as unknown as SearchDocsParams; if (!params.team_id || typeof params.team_id !== "string") { throw new Error("Team ID is required."); } logger.info( `Handling tool call: ${searchDocsTool.name} for team ${params.team_id}`, ); try { const docs = await clickUpService.docService.searchDocs(params); return { content: [ { type: "text", text: JSON.stringify(docs, null, 2), }, ], structuredContent: { docs }, }; } catch (error) { logger.error(`Error in ${searchDocsTool.name}:`, error); throw error instanceof Error ? error : new Error("Failed to search docs"); } } export async function handleCreateDoc( clickUpService: ClickUpService, args: Record<string, unknown>, ) { const params = args as unknown as CreateDocParams; if (!params.workspace_id || typeof params.workspace_id !== "string") { throw new Error("Workspace ID is required to create a doc."); } if (!params.name || typeof params.name !== "string") { throw new Error("Doc name is required."); } logger.info( `Handling tool call: ${createDocTool.name} for workspace ${params.workspace_id} with name ${params.name}`, ); try { const newDoc = await clickUpService.docService.createDoc(params); return { content: [ { type: "text", text: JSON.stringify(newDoc, null, 2), }, ], structuredContent: { doc: newDoc }, }; } catch (error) { logger.error(`Error in ${createDocTool.name}:`, error); throw error instanceof Error ? error : new Error("Failed to create doc"); } } export async function handleGetDocPages( clickUpService: ClickUpService, args: Record<string, unknown>, ) { const params = args as unknown as GetDocPagesParams; if (!params.doc_id || typeof params.doc_id !== "string") { throw new Error("Doc ID is required."); } logger.info( `Handling tool call: ${getDocPagesTool.name} for doc ${params.doc_id}`, ); try { const pages = await clickUpService.docService.getDocPages(params); return { content: [ { type: "text", text: JSON.stringify(pages, null, 2), }, ], structuredContent: { pages }, }; } catch (error) { logger.error(`Error in ${getDocPagesTool.name}:`, error); throw error instanceof Error ? error : new Error("Failed to get doc pages"); } } export async function handleCreateDocPage( clickUpService: ClickUpService, args: Record<string, unknown>, ) { const params = args as unknown as CreateDocPageParams; if (!params.workspace_id || typeof params.workspace_id !== "string") { throw new Error("Workspace ID is required for createDocPage tool."); } if (!params.doc_id || typeof params.doc_id !== "string") { throw new Error("Doc ID is required."); } if (!params.name || typeof params.name !== "string") { throw new Error("Page name (title) is required."); } logger.info( `Handling tool call: ${createDocPageTool.name} for doc ${params.doc_id} in workspace ${params.workspace_id}`, ); try { const newPage = await clickUpService.docService.createDocPage(params); return { content: [ { type: "text", text: JSON.stringify(newPage, null, 2), }, ], structuredContent: { page: newPage }, }; } catch (error) { logger.error(`Error in ${createDocPageTool.name}:`, error); throw error instanceof Error ? error : new Error("Failed to create doc page"); } } export async function handleGetDocPageContent( clickUpService: ClickUpService, args: Record<string, unknown>, ) { const params = args as unknown as GetDocPageContentParams; if (!params.workspace_id || typeof params.workspace_id !== "string") { throw new Error("Workspace ID is required for getDocPageContent tool."); } if (!params.doc_id || typeof params.doc_id !== "string") { throw new Error("Doc ID is required for getDocPageContent tool."); } if (!params.page_id || typeof params.page_id !== "string") { throw new Error("Page ID is required."); } logger.info( `Handling tool call: ${getDocPageContentTool.name} for page ${params.page_id} in doc ${params.doc_id}, workspace ${params.workspace_id}`, ); try { const pageContent = await clickUpService.docService.getDocPageContent(params); return { content: [ { type: "text", text: typeof pageContent === "string" ? pageContent : JSON.stringify(pageContent, null, 2), }, ], structuredContent: { content: typeof pageContent === "string" ? pageContent : pageContent, page: { id: params.page_id, name: "Page Content" } }, }; } catch (error) { logger.error(`Error in ${getDocPageContentTool.name}:`, error); throw error instanceof Error ? error : new Error("Failed to get doc page content"); } } export async function handleEditDocPageContent( clickUpService: ClickUpService, args: Record<string, unknown>, ) { const params = args as unknown as EditDocPageContentParams; if (!params.workspace_id || typeof params.workspace_id !== "string") { throw new Error("Workspace ID is required for editDocPageContent tool."); } if (!params.doc_id || typeof params.doc_id !== "string") { throw new Error("Doc ID is required for editDocPageContent tool."); } if (!params.page_id || typeof params.page_id !== "string") { throw new Error("Page ID is required."); } if (params.content === undefined) { throw new Error("Content is required to edit a doc page."); } logger.info( `Handling tool call: ${editDocPageContentTool.name} for page ${params.page_id} in doc ${params.doc_id}, workspace ${params.workspace_id}`, ); try { await clickUpService.docService.editDocPageContent(params); return { content: [ { type: "text", text: `Successfully edited page ${params.page_id}.`, }, ], structuredContent: { page: { id: params.page_id, name: params.title || "Updated Page" }, success: true }, }; } catch (error) { logger.error(`Error in ${editDocPageContentTool.name}:`, error); throw error instanceof Error ? error : new Error("Failed to edit doc page content"); } } export const docTools = [ searchDocsTool, createDocTool, getDocPagesTool, createDocPageTool, getDocPageContentTool, editDocPageContentTool, ];

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Nazruden/clickup-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server