@withpica/mcp-server
Version:
MCP Server for withPICA — enables AI assistants to interact with your withPICA music catalog
115 lines • 5.63 kB
JavaScript
// 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