Skip to main content
Glama
bbernstein

LacyLights MCP Server

by bbernstein

get_channel_map

Retrieve the DMX channel usage map for a specified project, identifying which channels are active. Optionally, filter results by universe for detailed analysis of channel allocations within the LacyLights system.

Instructions

Get the DMX channel usage map for a project

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectIdYesProject ID to analyze
universeNoSpecific universe to analyze (if not provided, shows all)

Implementation Reference

  • Main handler function for get_channel_map tool. Fetches project fixtures, groups by universe, computes channel usage map showing which fixtures occupy which DMX channels, identifies free channels, and provides usage summary.
    async getChannelMap(args: z.infer<typeof GetChannelMapSchema>) {
      const { projectId, universe } = GetChannelMapSchema.parse(args);
    
      try {
        const project = await this.graphqlClient.getProject(projectId);
        if (!project) {
          throw new Error(`Project with ID ${projectId} not found`);
        }
    
        let fixtures = project.fixtures;
        if (universe) {
          fixtures = fixtures.filter((f) => f.universe === universe);
        }
    
        // Group fixtures by universe
        const universeMap = fixtures.reduce(
          (acc, fixture) => {
            if (!acc[fixture.universe]) {
              acc[fixture.universe] = {
                universe: fixture.universe,
                fixtures: [],
                channelUsage: new Array(512).fill(null),
              };
            }
    
            const channelCount = fixture.channelCount;
            const endChannel = fixture.startChannel + channelCount - 1;
    
            // Mark channels as used
            for (let i = fixture.startChannel; i <= endChannel; i++) {
              if (i <= 512) {
                const channelIndex = i - fixture.startChannel;
                let channelType = "UNKNOWN";
                
                // Use mode-specific channels if available
                if (fixture.channels && fixture.channels.length > channelIndex) {
                  channelType = fixture.channels[channelIndex].type;
                }
                
                acc[fixture.universe].channelUsage[i - 1] = {
                  fixtureId: fixture.id,
                  fixtureName: fixture.name,
                  channelType: channelType,
                };
              }
            }
    
            acc[fixture.universe].fixtures.push({
              id: fixture.id,
              name: fixture.name,
              type: fixture.type,
              manufacturer: fixture.manufacturer,
              model: fixture.model,
              startChannel: fixture.startChannel,
              endChannel,
              channelCount,
            });
    
            return acc;
          },
          {} as Record<number, any>,
        );
    
        // Sort fixtures within each universe by start channel
        Object.values(universeMap).forEach((universeData: any) => {
          universeData.fixtures.sort(
            (a: any, b: any) => a.startChannel - b.startChannel,
          );
        });
    
        // Calculate available channels for each universe
        Object.values(universeMap).forEach((universeData: any) => {
          const usedChannels = universeData.channelUsage.filter(
            (ch: any) => ch !== null,
          ).length;
          universeData.availableChannels = 512 - usedChannels;
          universeData.nextAvailableChannel =
            this.findNextAvailableChannelInArray(universeData.channelUsage);
        });
    
        return {
          projectId,
          totalUniverses: Object.keys(universeMap).length,
          universes: Object.values(universeMap),
          summary: {
            totalFixtures: fixtures.length,
            totalChannelsUsed: Object.values(universeMap).reduce(
              (sum: number, u: any) => sum + (512 - u.availableChannels),
              0,
            ),
            totalChannelsAvailable: Object.values(universeMap).reduce(
              (sum: number, u: any) => sum + u.availableChannels,
              0,
            ),
          },
        };
      } catch (error) {
        throw new Error(`Failed to get channel map: ${error}`);
      }
    }
  • Zod input schema defining parameters: projectId (required string), universe (optional number). Used for validation in the handler.
    const GetChannelMapSchema = z.object({
      projectId: z.string().describe("Project ID to analyze"),
      universe: z
        .number()
        .optional()
        .describe("Specific universe to analyze (if not provided, shows all)"),
    });
  • src/index.ts:397-413 (registration)
    Tool registration in listTools response, including name, description, and inputSchema matching the Zod schema.
    name: "get_channel_map",
    description: "Get the DMX channel usage map for a project",
    inputSchema: {
      type: "object",
      properties: {
        projectId: {
          type: "string",
          description: "Project ID to analyze",
        },
        universe: {
          type: "number",
          description:
            "Specific universe to analyze (if not provided, shows all)",
        },
      },
      required: ["projectId"],
    },
  • src/index.ts:1954-1966 (registration)
    Dispatch handler in CallToolRequestSchema switch statement that routes calls to fixtureTools.getChannelMap.
    case "get_channel_map":
      return {
        content: [
          {
            type: "text",
            text: JSON.stringify(
              await this.fixtureTools.getChannelMap(args as any),
              null,
              2,
            ),
          },
        ],
      };

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/bbernstein/lacylights-mcp'

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