Skip to main content
Glama

get-filterable-attributes

Identify which attributes can filter PI Dashboard charts or categories by analyzing a sample entity type.

Instructions

Get the list of attributes that can be used for filtering by examining a sample entity

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
entityTypeYesType of entity to examine (chart or category)

Implementation Reference

  • Handler function that executes the tool logic: fetches sample entities for the given type ('chart' or 'category'), analyzes the first entity's properties to determine filterable attributes, their types, suitable operators, and generates usage examples.
    }, async ({ entityType }) => {
        try {
            if (!apiUrlSet || !authToken) {
                return {
                    isError: true,
                    content: [{
                            type: "text",
                            text: "Please set API URL and authenticate before using this tool."
                        }]
                };
            }
            let endpoint = "";
            // Get a sample entity
            if (entityType === "chart") {
                endpoint = "/charts";
            }
            else if (entityType === "category") {
                endpoint = "/categories";
            }
            // Get all entities (since pagination may not be supported)
            const listResponse = await authenticatedRequest(endpoint, "GET");
            if (listResponse &&
                typeof listResponse === 'object' &&
                'content' in listResponse &&
                Array.isArray(listResponse.content) &&
                listResponse.content.length > 0) {
                // Just use the first entity as our sample
                const sampleEntity = listResponse.content[0];
                // Extract the attributes from the sample entity
                const attributes = Object.keys(sampleEntity).map(key => {
                    const value = sampleEntity[key];
                    const type = typeof value;
                    // Determine which operators are suitable based on the value type
                    let availableOperators = [];
                    if (type === "string") {
                        // Prioritize 'like' for string fields since it's case-insensitive
                        availableOperators = ["like", "nlike", "eq", "ne"];
                    }
                    else if (type === "number") {
                        availableOperators = ["eq", "ne", "gt", "lt", "ge", "le"];
                    }
                    else if (type === "boolean") {
                        availableOperators = ["eq", "ne"];
                    }
                    return {
                        name: key,
                        type: type,
                        example: value !== null && value !== undefined ? String(value).substring(0, 30) : "null", // Show a sample value (truncated)
                        operators: availableOperators
                    };
                });
                // Find a string field for the example if possible
                const stringField = attributes.find(attr => attr.type === "string" && attr.example && attr.example !== "null");
                let exampleFilter = "";
                if (stringField) {
                    exampleFilter = `${stringField.name}(like)=${stringField.example}`;
                }
                else if (attributes.length > 0) {
                    const firstAttr = attributes[0];
                    exampleFilter = `${firstAttr.name}(${firstAttr.operators[0]})=${firstAttr.example}`;
                }
                let exampleMultipleFilter = "";
                if (attributes.length > 1) {
                    const secondAttr = attributes[1];
                    exampleMultipleFilter = `${exampleFilter}&${secondAttr.name}(${secondAttr.operators[0]})=${secondAttr.example}`;
                }
                return {
                    content: [{
                            type: "text",
                            text: `Filterable attributes for ${entityType}:\n${JSON.stringify(attributes, null, 2)}\n\n` +
                                `Example filter usage: '${exampleFilter}'\n\n` +
                                `Example with multiple filters: '${exampleMultipleFilter || "Not enough attributes for multiple filter example"}'\n\n` +
                                `Note: For text fields, the 'like' operator is recommended as it performs case-insensitive substring matching.`
                        }]
                };
            }
            else {
                return {
                    content: [{
                            type: "text",
                            text: `No ${entityType} entities found to analyze. Please ensure there is at least one ${entityType} in the system.`
                        }]
                };
            }
        }
        catch (error) {
            return {
                isError: true,
                content: [{ type: "text", text: `Error fetching ${entityType} attributes: ${getErrorMessage(error)}` }]
            };
        }
  • Input schema for the tool: requires 'entityType' as either 'chart' or 'category'.
    entityType: z.enum(["chart", "category"]).describe("Type of entity to examine (chart or category)")
  • build/index.js:166-259 (registration)
    Registration of the get-filterable-attributes tool using server.tool(), including description, input schema, and inline handler function.
    server.tool("get-filterable-attributes", "Get the list of attributes that can be used for filtering by examining a sample entity", {
        entityType: z.enum(["chart", "category"]).describe("Type of entity to examine (chart or category)")
    }, async ({ entityType }) => {
        try {
            if (!apiUrlSet || !authToken) {
                return {
                    isError: true,
                    content: [{
                            type: "text",
                            text: "Please set API URL and authenticate before using this tool."
                        }]
                };
            }
            let endpoint = "";
            // Get a sample entity
            if (entityType === "chart") {
                endpoint = "/charts";
            }
            else if (entityType === "category") {
                endpoint = "/categories";
            }
            // Get all entities (since pagination may not be supported)
            const listResponse = await authenticatedRequest(endpoint, "GET");
            if (listResponse &&
                typeof listResponse === 'object' &&
                'content' in listResponse &&
                Array.isArray(listResponse.content) &&
                listResponse.content.length > 0) {
                // Just use the first entity as our sample
                const sampleEntity = listResponse.content[0];
                // Extract the attributes from the sample entity
                const attributes = Object.keys(sampleEntity).map(key => {
                    const value = sampleEntity[key];
                    const type = typeof value;
                    // Determine which operators are suitable based on the value type
                    let availableOperators = [];
                    if (type === "string") {
                        // Prioritize 'like' for string fields since it's case-insensitive
                        availableOperators = ["like", "nlike", "eq", "ne"];
                    }
                    else if (type === "number") {
                        availableOperators = ["eq", "ne", "gt", "lt", "ge", "le"];
                    }
                    else if (type === "boolean") {
                        availableOperators = ["eq", "ne"];
                    }
                    return {
                        name: key,
                        type: type,
                        example: value !== null && value !== undefined ? String(value).substring(0, 30) : "null", // Show a sample value (truncated)
                        operators: availableOperators
                    };
                });
                // Find a string field for the example if possible
                const stringField = attributes.find(attr => attr.type === "string" && attr.example && attr.example !== "null");
                let exampleFilter = "";
                if (stringField) {
                    exampleFilter = `${stringField.name}(like)=${stringField.example}`;
                }
                else if (attributes.length > 0) {
                    const firstAttr = attributes[0];
                    exampleFilter = `${firstAttr.name}(${firstAttr.operators[0]})=${firstAttr.example}`;
                }
                let exampleMultipleFilter = "";
                if (attributes.length > 1) {
                    const secondAttr = attributes[1];
                    exampleMultipleFilter = `${exampleFilter}&${secondAttr.name}(${secondAttr.operators[0]})=${secondAttr.example}`;
                }
                return {
                    content: [{
                            type: "text",
                            text: `Filterable attributes for ${entityType}:\n${JSON.stringify(attributes, null, 2)}\n\n` +
                                `Example filter usage: '${exampleFilter}'\n\n` +
                                `Example with multiple filters: '${exampleMultipleFilter || "Not enough attributes for multiple filter example"}'\n\n` +
                                `Note: For text fields, the 'like' operator is recommended as it performs case-insensitive substring matching.`
                        }]
                };
            }
            else {
                return {
                    content: [{
                            type: "text",
                            text: `No ${entityType} entities found to analyze. Please ensure there is at least one ${entityType} in the system.`
                        }]
                };
            }
        }
        catch (error) {
            return {
                isError: true,
                content: [{ type: "text", text: `Error fetching ${entityType} attributes: ${getErrorMessage(error)}` }]
            };
        }
    });
  • Reference to get-filterable-attributes in the input schema description of list-categories tool.
    filter: z.string().optional().describe("Filter criteria in the format 'fieldName(operator)=value'. Multiple filters can be combined with & (e.g., 'description(like)=dashboard&orgId(eq)=1'). Available operators: eq, ne, gt, lt, ge, le, like, nlike. Use get-filterable-attributes tool to see available fields."),
  • Reference to get-filterable-attributes in the input schema description of list-charts tool.
    filter: z.string().optional().describe("Filter criteria in the format 'fieldName(operator)=value'. Multiple filters can be combined with & (e.g., 'description(like)=revenue&categoryId(eq)=5'). Available operators: eq, ne, gt, lt, ge, le, like, nlike. Use get-filterable-attributes tool to see available fields."),
Behavior2/5

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

No annotations are provided, so the description carries the full burden. It describes the action ('Get the list of attributes') but lacks behavioral details such as whether this is a read-only operation, what permissions are required, how the sample entity is selected, or what format the output takes. The description is functional but misses key operational context.

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 a single, clear sentence that efficiently conveys the tool's purpose without unnecessary words. It's front-loaded with the main action and resource. However, it could be slightly more structured by explicitly mentioning the parameter or output, though this isn't required for high conciseness.

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?

Given the tool has one parameter with full schema coverage and no output schema, the description provides a basic functional overview but lacks depth. It doesn't explain the return values or behavioral aspects, which is a gap since there are no annotations to compensate. For a tool that likely returns structured data about filterable attributes, more context on output would be helpful.

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%, with the single parameter 'entityType' fully documented in the schema (including enum values and description). The description doesn't add any parameter-specific information beyond what's in the schema, so it meets the baseline of 3 where the schema handles the heavy lifting.

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 ('Get') and resource ('list of attributes that can be used for filtering'), and specifies the method ('by examining a sample entity'). However, it doesn't explicitly differentiate from sibling tools like 'get-category' or 'get-chart' which might also retrieve entity information but for different purposes.

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 context ('by examining a sample entity') but doesn't explicitly state when to use this tool versus alternatives. For example, it doesn't clarify if this is for discovering filterable fields before using filtering tools or if it's a prerequisite for certain operations. No exclusions or specific alternatives are mentioned.

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/mingzilla/pi-api-mcp-server'

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