list_schedules
Retrieve monitoring schedules for all five dimensions including status, interval in days, next and last run timestamps. Use to check upcoming monitoring runs or verify schedule configuration.
Instructions
Get monitoring schedules for all 5 dimensions. Returns enabled/disabled status, interval in days, next run timestamp, and last run timestamp per dimension. Dimension names use marketing names (tech-trust, content, positioning, pricing, ai-visibility). Use this to check when the next monitoring run is due or verify scheduling configuration. Read-only. Returns JSON array.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| projectId | Yes | Project ID (from list_projects) |
Implementation Reference
- src/tools.ts:20-26 (helper)ToolDef interface defines the shape of each tool: name, description, parameters (Zod schema), path (URL builder), and optional queryParams. This is the type used for all tool definitions including list_schedules.
export interface ToolDef { name: string; description: string; parameters: z.ZodObject<any>; path: (args: Record<string, any>) => string; queryParams?: string[]; } - src/tools.ts:307-315 (schema)Schema definition for the list_schedules tool. Defines the tool's name, description, Zod-validated parameters (projectId as 24-char hex string), and path builder that maps to GET /v1/projects/{projectId}/schedules.
{ name: "list_schedules", description: "Get monitoring schedules for all 5 dimensions. Returns enabled/disabled status, interval in days, next run timestamp, and last run timestamp per dimension. Dimension names use marketing names (tech-trust, content, positioning, pricing, ai-visibility). Use this to check when the next monitoring run is due or verify scheduling configuration. Read-only. Returns JSON array.", parameters: z.object({ projectId: objectId("Project ID (from list_projects)"), }), path: (a) => `/v1/projects/${a.projectId}/schedules`, }, - src/index.ts:16-25 (registration)Registration loop: list_schedules is registered with the MCP server via server.tool(...) by iterating the tools array. The handler is a generic async function that calls apiGet with the tool's path and optional query params.
for (const tool of tools) { server.tool(tool.name, tool.description, tool.parameters.shape, async (args: Record<string, any>) => { const path = tool.path(args); const query: Record<string, any> = {}; for (const key of tool.queryParams ?? []) { if (args[key] !== undefined) query[key] = args[key]; } return apiGet(path, Object.keys(query).length ? query : undefined); }); } - src/api-client.ts:3-58 (handler)apiGet is the actual HTTP execution handler. It constructs the URL from the base (https://api.competlab.com) + path (e.g., /v1/projects/{id}/schedules), adds query parameters, sets the CL-API-Key header, fetches the data, and returns the response text as MCP content.
export async function apiGet( path: string, query?: Record<string, string | number>, ): Promise<{ content: Array<{ type: "text"; text: string }>; isError?: true }> { const apiKey = process.env.COMPETLAB_API_KEY; if (!apiKey) { return { content: [ { type: "text", text: JSON.stringify({ error: "api_key_missing", message: "COMPETLAB_API_KEY environment variable is not set", }), }, ], isError: true, }; } const url = new URL(`${API_BASE}${path}`); if (query) { for (const [k, v] of Object.entries(query)) { if (v !== undefined) url.searchParams.set(k, String(v)); } } try { const res = await fetch(url, { headers: { "CL-API-Key": apiKey }, }); const body = await res.text(); if (!res.ok) { return { content: [{ type: "text", text: body }], isError: true }; } return { content: [{ type: "text", text: body }] }; } catch (err) { return { content: [ { type: "text", text: JSON.stringify({ error: "api_unreachable", message: err instanceof Error ? err.message : "Failed to reach CompetLab API", status: 503, }), }, ], isError: true, }; } }