Skip to main content
Glama
phkus
by phkus
archived-tools.ts14.2 kB
/** * ARCHIVED TOOLS - Removed from main MCP server * * These tools were removed as part of the November 2025 reorganization to simplify * the server for a clear authorship workflow where AI can only add content (not modify/delete). * * This file is kept for future reference in case these features are needed again. * * Removed tools: * - deleteText: Delete blocks by ID * - getCollectionItems: Browse and read collection items with filtering * - createCollectionItems: Add new items to collections * - updateCollectionItems: Update existing collection items */ import { z } from "zod"; /** * TOOL: deleteText * Delete a page or heading and all its content * * Original location: lines 297-368 in src/index.ts */ export const deleteTextToolDefinition = { name: "deleteText", schema: { document: z .string() .describe("Name of the document to delete from (e.g., 'MCP test')."), id: z .string() .describe("ID of the page or heading to delete. WARNING: Deletes entire section including nested content."), }, async handler({ document, id }: { document: string; id: string }, context: { documents: Record<string, string> }) { try { // Get document URL const documentUrl = context.documents[document]; if (!documentUrl) { const available = Object.keys(context.documents).join(", "); return { content: [ { type: "text", text: `Document '${document}' not found. Available documents: ${available}`, }, ], isError: true, }; } const response = await fetch(`${documentUrl}/blocks`, { method: "DELETE", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ blockIds: [id] }), }); if (!response.ok) { const errorText = await response.text(); return { content: [ { type: "text", text: `Failed to delete block: Craft API error (${response.status}): ${errorText}`, }, ], isError: true, }; } const responseData = (await response.json()) as any; // Handle new API format: other endpoints return response.items instead of response const deletedIds = responseData.items || responseData; const deletedCount = Array.isArray(deletedIds) ? deletedIds.length : 1; return { content: [ { type: "text", text: `Successfully deleted block ${id}. Deleted ${deletedCount} block(s).`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to delete block: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } }, }; /** * TOOL: getCollectionItems * Browse and read collection items with filtering * * Original location: lines 555-692 in src/index.ts */ export const getCollectionItemsToolDefinition = { name: "getCollectionItems", schema: { document: z .string() .describe("Name of the document containing the collection (e.g., 'MCP test')."), collectionName: z .string() .describe("Name of the collection (case-insensitive, e.g., 'Sources', 'drafts', 'notes'). Use readDocument first to discover available collections."), filter: z .record(z.any()) .optional() .describe("Filter items by property values (e.g., {from_year: '1971', box_nr: 45}). Only items matching all filter criteria are returned."), maxDepth: z .number() .optional() .default(0) .describe("Content depth: 0 = properties + word count (fast browsing), -1 = full nested content (for reading items). Default 0."), useMarkdown: z .boolean() .optional() .default(false) .describe("If true, returns flat contentMarkdown field instead of nested blocks. Useful for collections with short text content."), }, async handler( { document, collectionName, filter, maxDepth, useMarkdown }: { document: string; collectionName: string; filter?: Record<string, any>; maxDepth?: number; useMarkdown?: boolean }, context: { documents: Record<string, string> } ) { try { // Get document URL const documentUrl = context.documents[document]; if (!documentUrl) { const available = Object.keys(context.documents).join(", "); return { content: [ { type: "text", text: `Document '${document}' not found. Available documents: ${available}`, }, ], isError: true, }; } // Normalize collection name to lowercase (Craft API requires lowercase) const normalizedCollectionName = collectionName.toLowerCase(); // When maxDepth=0 (browsing), fetch content for word count but will hide it const shouldShowWordCount = maxDepth === 0; const apiMaxDepth = shouldShowWordCount ? -1 : maxDepth; const apiUseMarkdown = shouldShowWordCount ? true : useMarkdown; const params = new URLSearchParams(); if (apiMaxDepth !== undefined) params.set("maxDepth", apiMaxDepth.toString()); const headers: Record<string, string> = { Accept: apiUseMarkdown ? "application/json; content=markdown" : "application/json", }; const response = await fetch( `${documentUrl}/collections/${normalizedCollectionName}/items?${params.toString()}`, { method: "GET", headers: headers, }, ); if (!response.ok) { const errorText = await response.text(); return { content: [ { type: "text", text: `Failed to get collection items: Craft API error (${response.status}): ${errorText}. Make sure the collection '${collectionName}' exists in the current document.`, }, ], isError: true, }; } const responseData = (await response.json()) as any; let items = responseData.items || responseData; // Apply filtering if filter parameter is provided if (filter && Object.keys(filter).length > 0) { items = items.filter((item: any) => { // Check if all filter criteria match return Object.entries(filter).every(([key, value]) => { const itemValue = item.properties?.[key]; // Convert both to strings for comparison to handle different types return String(itemValue) === String(value); }); }); } // If maxDepth=0 (browsing mode), show word count instead of content if (shouldShowWordCount) { items = items.map((item: any) => { const content = item.contentMarkdown || ""; const wordCount = content.trim().length > 0 ? content.trim().split(/\s+/).length : 0; // Remove content fields and add word count const { content: _, contentMarkdown: __, ...itemWithoutContent } = item; return { ...itemWithoutContent, wordCount }; }); } const formatted = JSON.stringify(items, null, 2); const filterNote = filter && Object.keys(filter).length > 0 ? ` (filtered by ${Object.entries(filter).map(([k, v]) => `${k}=${v}`).join(', ')})` : ''; return { content: [ { type: "text", text: `Found ${items.length} item(s) in collection '${collectionName}'${filterNote}:\n\n${formatted}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to get collection items: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } }, }; /** * TOOL: createCollectionItems * Add new items to a collection * * Original location: lines 694-794 in src/index.ts */ export const createCollectionItemsToolDefinition = { name: "createCollectionItems", schema: { document: z .string() .describe("Name of the document containing the collection (e.g., 'MCP test')."), collectionName: z .string() .describe("Name of the collection to add items to (e.g., 'drafts', 'notes', 'tasks')."), items: z .array( z.object({ title: z.string().describe("Title of the item"), properties: z .record(z.any()) .optional() .describe( "Properties object matching the collection schema (e.g., {status: 'todo', priority: 'high'}). Schema depends on the collection.", ), }), ) .describe("Array of items to create in the collection."), allowNewSelectOptions: z .boolean() .optional() .default(false) .describe("If true, allows creating new select options if they don't exist in the schema."), }, async handler( { document, collectionName, items, allowNewSelectOptions }: { document: string; collectionName: string; items: Array<{title: string; properties?: Record<string, any>}>; allowNewSelectOptions?: boolean }, context: { documents: Record<string, string> } ) { try { // Get document URL const documentUrl = context.documents[document]; if (!documentUrl) { const available = Object.keys(context.documents).join(", "); return { content: [ { type: "text", text: `Document '${document}' not found. Available documents: ${available}`, }, ], isError: true, }; } // Normalize collection name to lowercase (Craft API requires lowercase) const normalizedCollectionName = collectionName.toLowerCase(); const requestBody: any = { items }; if (allowNewSelectOptions) { requestBody.allowNewSelectOptions = true; } const response = await fetch( `${documentUrl}/collections/${normalizedCollectionName}/items`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(requestBody), }, ); if (!response.ok) { const errorText = await response.text(); return { content: [ { type: "text", text: `Failed to create collection items: Craft API error (${response.status}): ${errorText}. Check that properties match the collection schema and that the collection '${collectionName}' exists.`, }, ], isError: true, }; } const responseData = (await response.json()) as any; const createdItems = responseData.successful || responseData.items || responseData; const formatted = JSON.stringify(createdItems, null, 2); return { content: [ { type: "text", text: `Successfully created ${createdItems.length} item(s) in collection '${collectionName}':\n\n${formatted}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to create collection items: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } }, }; /** * TOOL: updateCollectionItems * Update existing items in a collection * * Original location: lines 796-897 in src/index.ts */ export const updateCollectionItemsToolDefinition = { name: "updateCollectionItems", schema: { document: z .string() .describe("Name of the document containing the collection (e.g., 'MCP test')."), collectionName: z .string() .describe("Name of the collection to update items in (e.g., 'drafts', 'notes', 'tasks')."), itemsToUpdate: z .array( z.object({ id: z.string().describe("ID of the item to update"), title: z.string().optional().describe("New title for the item"), properties: z .record(z.any()) .optional() .describe( "Properties to update (e.g., {status: 'done'}). Only specified properties are updated.", ), }), ) .describe("Array of items to update in the collection."), allowNewSelectOptions: z .boolean() .optional() .default(false) .describe("If true, allows creating new select options if they don't exist in the schema."), }, async handler( { document, collectionName, itemsToUpdate, allowNewSelectOptions }: { document: string; collectionName: string; itemsToUpdate: Array<{id: string; title?: string; properties?: Record<string, any>}>; allowNewSelectOptions?: boolean }, context: { documents: Record<string, string> } ) { try { // Get document URL const documentUrl = context.documents[document]; if (!documentUrl) { const available = Object.keys(context.documents).join(", "); return { content: [ { type: "text", text: `Document '${document}' not found. Available documents: ${available}`, }, ], isError: true, }; } // Normalize collection name to lowercase (Craft API requires lowercase) const normalizedCollectionName = collectionName.toLowerCase(); const requestBody: any = { itemsToUpdate }; if (allowNewSelectOptions) { requestBody.allowNewSelectOptions = true; } const response = await fetch( `${documentUrl}/collections/${normalizedCollectionName}/items`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(requestBody), }, ); if (!response.ok) { const errorText = await response.text(); return { content: [ { type: "text", text: `Failed to update collection items: Craft API error (${response.status}): ${errorText}. Check that item IDs exist and properties match the collection schema.`, }, ], isError: true, }; } const responseData = (await response.json()) as any; const updatedItems = responseData.successful || responseData.items || responseData; const formatted = JSON.stringify(updatedItems, null, 2); return { content: [ { type: "text", text: `Successfully updated ${updatedItems.length} item(s) in collection '${collectionName}':\n\n${formatted}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to update collection items: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } }, }; /** * USAGE NOTES * * To restore any of these tools to the main server: * 1. Copy the tool definition from this file * 2. Convert it back to this.server.tool() format in src/index.ts init() method * 3. Update CLAUDE.md documentation to reflect the restored tool * * Example for restoring deleteText: * * this.server.tool( * "deleteText", * deleteTextToolDefinition.schema, * async (params) => deleteTextToolDefinition.handler(params, { documents: this.documents }) * ); */

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/phkus/craft-mcp'

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