Skip to main content
Glama

Settings

settings

Retrieve and manage OfficeRnD organization settings including locations, resource types, business hours, and custom properties through list or get actions.

Instructions

Query organization settings and configuration in OfficeRnD.

action=list: List configuration entities. action=get: Get a single location by ID (locations only).

Entity-specific filters when listing:

  • locations: name

  • resource_types: (pagination only)

  • business_hours: location

  • custom_properties: (pagination only)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actionYesAction to perform
entityYesEntity type to query
idNoLocation ID (required for action=get, locations only)
nameNoFilter by exact name (locations)
locationNoFilter by location ID (business_hours)
cursorNextNoCursor token for next page of results
limitNoResults per page (max 50, default 50)

Implementation Reference

  • The main handler function for the "settings" tool, which processes 'list' and 'get' actions for various entities.
      async ({ action, entity, id, name, location, cursorNext, limit }) => {
        try {
          const cfg = ENTITIES[entity];
    
          if (action === "get") {
            if (!cfg.getPath) {
              return {
                content: [{ type: "text" as const, text: `Entity "${entity}" does not support get by ID.` }],
                isError: true,
              };
            }
            if (!id) {
              return {
                content: [{ type: "text" as const, text: "id is required for action=get." }],
                isError: true,
              };
            }
            const item = await apiGet<Record<string, unknown>>(`${cfg.getPath}/${id}`);
            return { content: [{ type: "text" as const, text: cfg.formatter(item) }] };
          }
    
          // list
          const params: Record<string, string> = {};
          if (cursorNext) params["$cursorNext"] = cursorNext;
          if (limit) params["$limit"] = limit;
    
          switch (entity) {
            case "locations":
              if (name) params["name"] = name;
              break;
            case "business_hours":
              if (location) params["location"] = location;
              break;
          }
    
          const data = await apiGet<PaginatedResponse<Record<string, unknown>>>(cfg.listPath, params);
    
          if (data.results.length === 0) {
            return { content: [{ type: "text" as const, text: `No ${cfg.label} found.` }] };
          }
    
          const text = data.results.map(cfg.formatter).join("\n---\n");
          let result = `Found ${data.results.length} ${cfg.label} (range ${data.rangeStart}-${data.rangeEnd}):\n\n${text}`;
          if (data.cursorNext) {
            result += `\n\n[More results available — use cursorNext: "${data.cursorNext}"]`;
          }
    
          return { content: [{ type: "text" as const, text: result }] };
        } catch (error) {
          return {
            content: [
              {
                type: "text" as const,
                text: `Error querying ${entity}: ${error instanceof Error ? error.message : String(error)}`,
              },
            ],
            isError: true,
          };
        }
      }
    );
  • Input schema definition for the "settings" tool using Zod.
    inputSchema: {
      action: z.enum(["list", "get"]).describe("Action to perform"),
      entity: z
        .enum(["locations", "resource_types", "business_hours", "custom_properties"])
        .describe("Entity type to query"),
      id: z
        .string()
        .optional()
        .describe("Location ID (required for action=get, locations only)"),
      name: z
        .string()
        .optional()
        .describe("Filter by exact name (locations)"),
      location: z
        .string()
        .optional()
        .describe("Filter by location ID (business_hours)"),
      cursorNext: z
        .string()
        .optional()
        .describe("Cursor token for next page of results"),
      limit: z
        .string()
        .optional()
        .describe("Results per page (max 50, default 50)"),
    },
  • Registration function for the "settings" tool on the McpServer.
    export function registerSettingsTool(server: McpServer): void {
      server.registerTool(
        "settings",
        {
          title: "Settings",
          description: `Query organization settings and configuration in OfficeRnD.
    
    action=list: List configuration entities.
    action=get: Get a single location by ID (locations only).
    
    Entity-specific filters when listing:
    - locations: name
    - resource_types: (pagination only)
    - business_hours: location
    - custom_properties: (pagination only)`,
          inputSchema: {
            action: z.enum(["list", "get"]).describe("Action to perform"),
            entity: z
              .enum(["locations", "resource_types", "business_hours", "custom_properties"])
              .describe("Entity type to query"),
            id: z
              .string()
              .optional()
              .describe("Location ID (required for action=get, locations only)"),
            name: z
              .string()
              .optional()
              .describe("Filter by exact name (locations)"),
            location: z
              .string()
              .optional()
              .describe("Filter by location ID (business_hours)"),
            cursorNext: z
              .string()
              .optional()
              .describe("Cursor token for next page of results"),
            limit: z
              .string()
              .optional()
              .describe("Results per page (max 50, default 50)"),
          },
        },
        async ({ action, entity, id, name, location, cursorNext, limit }) => {
          try {
            const cfg = ENTITIES[entity];
    
            if (action === "get") {
              if (!cfg.getPath) {
                return {
                  content: [{ type: "text" as const, text: `Entity "${entity}" does not support get by ID.` }],
                  isError: true,
                };
              }
              if (!id) {
                return {
                  content: [{ type: "text" as const, text: "id is required for action=get." }],
                  isError: true,
                };
              }
              const item = await apiGet<Record<string, unknown>>(`${cfg.getPath}/${id}`);
              return { content: [{ type: "text" as const, text: cfg.formatter(item) }] };
            }
    
            // list
            const params: Record<string, string> = {};
            if (cursorNext) params["$cursorNext"] = cursorNext;
            if (limit) params["$limit"] = limit;
    
            switch (entity) {
              case "locations":
                if (name) params["name"] = name;
                break;
              case "business_hours":
                if (location) params["location"] = location;
                break;
            }
    
            const data = await apiGet<PaginatedResponse<Record<string, unknown>>>(cfg.listPath, params);
    
            if (data.results.length === 0) {
              return { content: [{ type: "text" as const, text: `No ${cfg.label} found.` }] };
            }
    
            const text = data.results.map(cfg.formatter).join("\n---\n");
            let result = `Found ${data.results.length} ${cfg.label} (range ${data.rangeStart}-${data.rangeEnd}):\n\n${text}`;
            if (data.cursorNext) {
              result += `\n\n[More results available — use cursorNext: "${data.cursorNext}"]`;
            }
    
            return { content: [{ type: "text" as const, text: result }] };
          } catch (error) {
            return {
              content: [
                {
                  type: "text" as const,
                  text: `Error querying ${entity}: ${error instanceof Error ? error.message : String(error)}`,
                },
              ],
              isError: true,
            };
          }
        }
      );
    }
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. While 'Query' implies read-only behavior, the description doesn't explicitly confirm safety (crucial for a 'settings' tool), disclose pagination behavior beyond parameter existence, or describe return formats/error cases.

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?

Well-structured with clear section headers (action descriptions, entity-specific filters). Information is front-loaded with the general purpose statement followed by specific operational details. No redundant sentences, though the formatting with line breaks is slightly verbose.

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 lack of output schema, the description should explain return values but doesn't. It adequately covers the 7-parameter complexity through the entity-filter mappings, but misses behavioral context (rate limits, auth requirements) that would complete the picture for a configuration tool.

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

Parameters4/5

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

With 100% schema coverage, the baseline is 3. The description adds value by mapping specific filter parameters to their applicable entities (e.g., 'locations: name', 'business_hours: location'), clarifying constraints that the schema lists separately. It also emphasizes the 'locations only' restriction for the get action.

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 tool 'Query organization settings and configuration in OfficeRnD,' specifying the verb (query), resource (settings/configuration), and domain. It distinguishes from siblings (billing, collaboration, etc.) by focusing on configuration entities, though it doesn't explicitly contrast with them.

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

Usage Guidelines4/5

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

Provides clear internal usage context by documenting when to use action=list versus action=get, explicitly noting that get is restricted to locations only, and mapping entity-specific filters. However, it lacks external comparison—no guidance on when to use this tool versus siblings like 'space' or 'community'.

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/MrBoor/officernd-mcp'

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