UNPKG

@withpica/mcp-server

Version:

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

130 lines • 6.45 kB
// Copyright (c) 2025-2026 Withpica Ltd. All rights reserved. import { formatStructuredList, formatSuccess } from "@withpica/mcp-utils"; export class PublishersTools { pica; constructor(pica) { this.pica = pica; } getTools() { return [ { definition: { name: "pica_publishers_query", scope: "read:catalog", audiences: ["stdio", "http", "public"], tier: "read", description: "Find publishers by name or IPI. Use before setting publisher on credits. " + "→ then: pica_credits_update (link publisher to a credit)", 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: { query: { type: "string", description: "Search by publisher name or IPI", }, limit: { type: "number", minimum: 1, maximum: 200, description: "Max results (default: 50)", }, offset: { type: "number", minimum: 0, description: "Skip this many results — page with offset while has_more is true.", }, }, }, }, executor: this.queryPublishers.bind(this), }, { definition: { name: "pica_publishers_create", scope: "write:catalog", audiences: ["stdio", "http", "public"], tier: "write", description: "Create (or fetch existing) publisher in the catalog-wide " + "`global_publishers` table. Idempotent by ipi_number — if a " + "publisher with the same IPI already exists, returns the existing " + "row. Check `pica_publishers_query` first to avoid duplicates and " + "to resolve parent_publisher_id.", 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: { name: { type: "string", description: "Publisher name." }, ipi_number: { type: "string", description: "Publisher IPI number (9-11 digits; normalised to 11 with " + "leading zero-padding). Required.", }, legal_name: { type: "string", description: "Legal entity name (e.g. 'Example Publishing Ltd.') — optional.", }, country: { type: "string", description: "ISO country code (e.g. 'GB', 'US').", }, isni: { type: "string", description: "ISNI identifier (16-character alphanumeric) if the publisher has one.", }, publisher_type: { type: "string", description: "Category label (e.g. 'major', 'indie', 'admin', 'self_published'). Freeform — no backend CHECK.", }, wikidata_id: { type: "string", description: "Wikidata Q-number (e.g. 'Q123456').", }, parent_publisher_id: { type: "string", description: "UUID of parent publisher for subsidiary/admin relationships. FK → global_publishers.id. Use `pica_publishers_query` to find the parent's ID before passing it here; the route returns FK_NOT_FOUND if the UUID does not exist.", }, founded_date: { type: "string", description: "Founding date (YYYY-MM-DD).", }, headquarters: { type: "string", description: "Freeform location (e.g. 'London, UK').", }, }, required: ["name", "ipi_number"], }, }, executor: this.createPublisher.bind(this), }, ]; } async queryPublishers(args) { // listPage: an honest has_more and offset. The total is null — the // route does not count the platform-wide registry — never the page // length (row-cap T3). const limit = args.limit || 50; const offset = args.offset || 0; const page = await this.pica.publishers.listPage({ query: args.query, limit, offset, }); return formatStructuredList(page.data, "publisher", { total: page.total, has_more: page.hasMore, limit, offset, }); } async createPublisher(args) { const result = await this.pica.publishers.create(args); return formatSuccess("Publisher created", result); } } //# sourceMappingURL=publishers.js.map