UNPKG

@withpica/mcp-server

Version:

MCP Server for withPICA — enables AI assistants to interact with your withPICA music catalog

115 lines • 5.63 kB
// Copyright (c) 2025-2026 Withpica Ltd. All rights reserved. import { formatSuccess } from "@withpica/mcp-utils"; import { typedError } from "./error-envelope.js"; export class DirectoryTools { pica; constructor(pica) { this.pica = pica; } getTools() { return [ { definition: { name: "pica_directory_settings", scope: "admin", audiences: ["stdio", "http", "public"], tier: "read", description: "Get or update your account's directory visibility settings. " + "Controls whether your catalogue appears in the PICA public directory " + "and what information is shown (audio previews, splits, publishers, etc.).", workflows: "infrastructure", vernacular_kind: "specialist", vernacular_reason: "Specialist context; not yet covered by the Creator Question Atlas — pending telemetry-driven addition per ADR-226 Phase 4 substrate writes.", inputSchema: { type: "object", properties: { action: { type: "string", enum: ["get", "update"], description: "Action to perform. 'get' returns current settings. 'update' changes settings.", }, opted_in: { type: "boolean", description: "Make catalogue discoverable in the PICA directory. " + "When true, sync supervisors and AI agents can find your recordings.", }, show_audio_preview: { type: "boolean", description: "Allow audio previews in directory listings. " + "When true, visitors can listen to your tracks.", }, show_splits: { type: "boolean", description: "Show credit split percentages in directory.", }, show_publishers: { type: "boolean", description: "Show publisher information in directory.", }, show_agreements: { type: "boolean", description: "Show agreement details in directory.", }, show_stems: { type: "boolean", description: "Show stems/instrumentals in directory.", }, contact_enabled: { type: "boolean", description: "Allow licensing enquiries from the directory. On by default; " + "set false to switch enquiries off for every listed work.", }, }, required: ["action"], }, }, executor: this.directorySettings.bind(this), }, ]; } async directorySettings(args) { if (args.action === "get") { const result = await this.pica.directory.getSettings(); const s = result.settings; const status = s.opted_in ? "discoverable" : "private"; const summary = [ `Directory status: ${status}`, `Eligible works: ${result.eligible_work_count}`, s.show_audio_preview ? "Audio preview: on" : "Audio preview: off", s.contact_enabled ? "Enquiries: on" : "Enquiries: off", s.show_splits ? "Splits: visible" : "Splits: hidden", s.show_publishers ? "Publishers: visible" : "Publishers: hidden", ].join("\n"); return { content: [{ type: "text", text: summary }], structuredContent: result, }; } // Update const updates = {}; const boolFields = [ "opted_in", "show_audio_preview", "show_splits", "show_publishers", "show_agreements", "show_stems", "contact_enabled", ]; for (const field of boolFields) { if (args[field] !== undefined) updates[field] = Boolean(args[field]); } if (Object.keys(updates).length === 0) { // typedError, not formatAsText({error}): the latter has no `isError`, so // the dispatcher and the client read a refusal as a SUCCESS whose payload // happens to contain the word "error", and mcp_audit_log.error_code is // NULL. See ./error-envelope.ts. return typedError("VALIDATION_ERROR", "No settings to update. Provide at least one setting field."); } const result = await this.pica.directory.updateSettings(updates); const status = result.opted_in ? "discoverable" : "private"; return formatSuccess(`Directory settings updated. Your catalogue is now ${status}.`, result); } } //# sourceMappingURL=directory.js.map