Skip to main content
Glama
Im-Hal-9K

Capacities-MCP-Plus

capacities_read_object_content

Read-only

Retrieve full content from Capacities knowledge objects using object IDs or search terms to access stored information.

Instructions

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.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
objectIdYesThe UUID of the object to retrieve. You can get this from 'Copy object reference' in Capacities.
spaceIdYesThe UUID of the space containing the object
titleNoOptional: The title or partial title of the object to search for. This improves search results.

Implementation Reference

  • The execute function implementing the tool logic: attempts undocumented endpoints for full object content, falls back to search API for snippets and highlights.
    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)}`,
    		);
    	}
  • Zod schema defining the input parameters for the tool: objectId (required UUID), spaceId (required UUID), title (optional string).
    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.",
    		),
    }),
  • src/server.ts:29-29 (registration)
    Registration of the readObjectContentTool to the FastMCP server instance.
    server.addTool(readObjectContentTool);
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=true, indicating a safe read operation with potential for unknown endpoints. The description adds valuable context beyond this: it discloses the fallback behavior to search API aggregation and mentions undocumented endpoints, which helps the agent understand reliability and performance implications. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and includes two additional sentences that add context without unnecessary detail. It's appropriately sized, though the second sentence could be slightly more concise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read operation with annotations covering safety and open-world hints, and no output schema, the description provides adequate context on behavior (fallback mechanism) but lacks details on return values or error handling. It's complete enough for basic use but has gaps in output expectations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema fully documents all parameters. The description adds minimal semantics by noting that the title parameter 'improves search results,' but this is redundant with the schema's description. Baseline 3 is appropriate as the schema carries the burden.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb ('Retrieve') and resource ('full content of a Capacities object by its ID'), making the purpose specific. However, it doesn't explicitly distinguish this tool from sibling tools like 'capacities_search', which might also retrieve content, though the focus on a specific object ID provides some implicit differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage by mentioning that it 'tries undocumented endpoints first, then falls back to search API aggregation,' which suggests a fallback mechanism but doesn't explicitly state when to use this tool versus alternatives like 'capacities_search'. No clear exclusions or prerequisites are provided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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