Skip to main content
Glama
readObjectContent.ts5.47 kB
import { z } from "zod"; import { API_BASE_URL, getApiKey } from "../api.js"; export const readObjectContentTool = { annotations: { openWorldHint: true, readOnlyHint: true, title: "Read Object Content", }, description: "Retrieve the full content of a Capacities object by its ID. Optionally provide a title or search term to improve results. This tries undocumented endpoints first, then falls back to search API aggregation.", execute: async (args: { objectId: string; spaceId: string; title?: string; }) => { const apiKey = getApiKey(); // Try potential undocumented endpoints first const potentialEndpoints = [ `/object/${args.objectId}`, `/objects/${args.objectId}`, `/content/${args.objectId}`, `/space/${args.spaceId}/object/${args.objectId}`, ]; for (const endpoint of potentialEndpoints) { try { const response = await fetch(`${API_BASE_URL}${endpoint}`, { headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", }, }); if (response.ok) { const data = await response.json(); return JSON.stringify( { note: `Successfully retrieved from undocumented endpoint: ${endpoint}`, object: data, }, null, 2, ); } } catch (error) { // Continue to next endpoint } } // Fallback to search API approach try { // Search using title if provided, otherwise use a wildcard search const searchTerm = args.title || "*"; const requestBody = { searchTerm: searchTerm, spaceIds: [args.spaceId], mode: "fullText" as const, }; const searchResponse = await fetch(`${API_BASE_URL}/search`, { method: "POST", headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", }, body: JSON.stringify(requestBody), }); if (!searchResponse.ok) { throw new Error( `Search API error: ${searchResponse.status} ${searchResponse.statusText}`, ); } const data = (await searchResponse.json()) as { results?: Array<{ id?: string; title?: string; highlights?: Array<{ snippets?: string[]; context?: { field?: string; [key: string]: unknown }; score?: number; [key: string]: unknown; }>; snippet?: string; [key: string]: unknown; }>; }; if (!data || !data.results || data.results.length === 0) { return JSON.stringify( { error: "Object not found", message: `No results found. Try providing the 'title' parameter to search for the object.`, searchTerm: searchTerm, }, null, 2, ); } // Find the exact match by ID const exactMatch = data.results.find( (result) => result.id === args.objectId, ); if (!exactMatch) { return JSON.stringify( { error: "Object not found by ID", message: `Found ${data.results.length} results but none matched object ID ${args.objectId}. Try searching by title first.`, availableResults: data.results.map((r) => ({ id: r.id, title: r.title, })), }, null, 2, ); } // Aggregate content from highlights and snippets const aggregatedContent: string[] = []; // Try to extract snippet if (exactMatch.snippet && typeof exactMatch.snippet === "string") { aggregatedContent.push(exactMatch.snippet); } // Extract from highlights array - each highlight has a snippets array if (exactMatch.highlights && Array.isArray(exactMatch.highlights)) { for (const highlight of exactMatch.highlights) { // The highlight object has a "snippets" array containing the actual text if (highlight.snippets && Array.isArray(highlight.snippets)) { for (const snippet of highlight.snippets) { if (typeof snippet === "string" && snippet.trim()) { aggregatedContent.push(snippet); } } } } } // Also try other common content fields on the result object const otherContentFields = [ "content", "text", "body", "description", "mdText", ]; for (const field of otherContentFields) { const value = exactMatch[field]; if (value && typeof value === "string" && value.trim()) { aggregatedContent.push(`[${field}]: ${value}`); } } return JSON.stringify( { note: "Content retrieved via search API. This may be incomplete - search only returns snippets/highlights.", object: { id: exactMatch.id, title: exactMatch.title, aggregatedContent: aggregatedContent.length > 0 ? aggregatedContent.join("\n\n---\n\n") : "No content snippets available", snippetCount: aggregatedContent.length, highlights: exactMatch.highlights, rawResult: exactMatch, }, }, null, 2, ); } catch (error) { throw new Error( `Failed to read object content: ${error instanceof Error ? error.message : String(error)}`, ); } }, name: "capacities_read_object_content", parameters: z.object({ objectId: z .string() .uuid() .describe( "The UUID of the object to retrieve. You can get this from 'Copy object reference' in Capacities.", ), spaceId: z .string() .uuid() .describe("The UUID of the space containing the object"), title: z .string() .optional() .describe( "Optional: The title or partial title of the object to search for. This improves search results.", ), }), };

Implementation Reference

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/Im-Hal-9K/Capacities-MCP-Plus'

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