Skip to main content
Glama

collaboration

Query collaboration data in OfficeRnD including events, tickets, and posts with filtering options. List entities with pagination or retrieve specific items by ID.

Instructions

Query collaboration data in OfficeRnD.

action=list: List entities with optional filters and pagination (max 50 per page). action=get: Get a single entity by ID.

Entity-specific filters when listing:

  • events: location, startAfter, startBefore (ISO dates)

  • tickets: status, member, location

  • posts: (pagination only)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actionYesAction to perform
entityYesEntity type to query
idNoEntity ID (required for action=get)
statusNoFilter by status (tickets only)
memberNoFilter by member ID (tickets only)
locationNoFilter by location ID (events, tickets)
startAfterNoEvents starting on/after this ISO date
startBeforeNoEvents starting before this ISO date
cursorNextNoCursor token for next page of results
limitNoResults per page (max 50, default 50)

Implementation Reference

  • The handler function logic for the collaboration tool, which executes list or get actions based on the provided entity and filters.
        async ({ action, entity, id, status, member, location, startAfter, startBefore, cursorNext, limit }) => {
          try {
            const cfg = ENTITIES[entity];
    
            if (action === "get") {
              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 "events":
                if (location) params["location"] = location;
                if (startAfter) params["start[$gte]"] = startAfter;
                if (startBefore) params["start[$lt]"] = startBefore;
                break;
              case "tickets":
                if (status) params["status"] = status;
                if (member) params["member"] = member;
                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,
            };
          }
        }
      );
    }
  • The input schema definition using Zod for the collaboration tool.
    inputSchema: {
      action: z.enum(["list", "get"]).describe("Action to perform"),
      entity: z
        .enum(["events", "tickets", "posts"])
        .describe("Entity type to query"),
      id: z
        .string()
        .optional()
        .describe("Entity ID (required for action=get)"),
      status: z
        .string()
        .optional()
        .describe("Filter by status (tickets only)"),
      member: z
        .string()
        .optional()
        .describe("Filter by member ID (tickets only)"),
      location: z
        .string()
        .optional()
        .describe("Filter by location ID (events, tickets)"),
      startAfter: z
        .string()
        .optional()
        .describe("Events starting on/after this ISO date"),
      startBefore: z
        .string()
        .optional()
        .describe("Events starting before this ISO date"),
      cursorNext: z
        .string()
        .optional()
        .describe("Cursor token for next page of results"),
      limit: z
        .string()
        .optional()
        .describe("Results per page (max 50, default 50)"),
    },
  • Tool registration function for the collaboration tool.
    export function registerCollaborationTool(server: McpServer): void {
      server.registerTool(
        "collaboration",
        {
          title: "Collaboration",
          description: `Query collaboration data in OfficeRnD.
    
    action=list: List entities with optional filters and pagination (max 50 per page).
    action=get: Get a single entity by ID.
    
    Entity-specific filters when listing:
    - events: location, startAfter, startBefore (ISO dates)
    - tickets: status, member, location
    - posts: (pagination only)`,
          inputSchema: {
            action: z.enum(["list", "get"]).describe("Action to perform"),
            entity: z
              .enum(["events", "tickets", "posts"])
              .describe("Entity type to query"),
            id: z
              .string()
              .optional()
              .describe("Entity ID (required for action=get)"),
            status: z
              .string()
              .optional()
              .describe("Filter by status (tickets only)"),
            member: z
              .string()
              .optional()
              .describe("Filter by member ID (tickets only)"),
            location: z
              .string()
              .optional()
              .describe("Filter by location ID (events, tickets)"),
            startAfter: z
              .string()
              .optional()
              .describe("Events starting on/after this ISO date"),
            startBefore: z
              .string()
              .optional()
              .describe("Events starting before this ISO date"),
            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, status, member, location, startAfter, startBefore, cursorNext, limit }) => {
          try {
            const cfg = ENTITIES[entity];
    
            if (action === "get") {
              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 "events":
                if (location) params["location"] = location;
                if (startAfter) params["start[$gte]"] = startAfter;
                if (startBefore) params["start[$lt]"] = startBefore;
                break;
              case "tickets":
                if (status) params["status"] = status;
                if (member) params["member"] = member;
                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,
            };
          }
        }
      );
    }
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