UNPKG

@withpica/mcp-server

Version:

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

60 lines • 3.06 kB
// Copyright (c) 2025-2026 Withpica Ltd. All rights reserved. /** * What a song or recording edit in a CLIENT's catalogue came back as * (ADR-333 PR 1.3). * * PATCH /api/admin/works/:id and /recordings/:id, named for a client * catalogue, answer one of two envelopes (clientCataloguePatch in each route, * lib/services/relationship-proposals.ts changeThroughRelationship): * - a proposal, 202 `{ applied: false, proposal_reference, expires_at, * message }`: nothing has changed; the client's owners decide it; * - a direct change (an administrator), `{ applied: true, result }`: the * updated record is `result`. * In the caller's own catalogue the answer is the record itself. * * The MCP callers of those two routes (updateWork, updateRecording, * pica_enrichment_clear) read the answer here, so a proposal is not reported * as "updated" and a direct change's record is read from `result` (D2 Gate 2, * holdout run 38435148161: pica_works_update answered "Work updated * successfully" for a representative's proposal). A new caller that skips * this fails tools/__tests__/client-catalogue-replies.test.ts ("every caller * of works.update / recordings.update reads the change outcome"). */ import { currentCatalogue } from "@withpica/mcp-sdk"; import { formatSuccess } from "@withpica/mcp-utils"; export function readChangeOutcome(answer) { if (answer && typeof answer === "object" && "applied" in answer) { const a = answer; if (a.applied === false) { // A proposal with no reference cannot be followed up: say so rather // than report either outcome. if (typeof a.proposal_reference !== "string" || !a.proposal_reference) throw new Error("the change was not applied, and no proposal reference came back"); return { kind: "proposed", reference: a.proposal_reference, expiresAt: typeof a.expires_at === "string" ? a.expires_at : null, }; } if (a.applied === true && "result" in a) return { kind: "applied", record: a.result }; } // In a client's catalogue the route always answers one of the two // envelopes. Anything else means the envelope changed: refuse to call it // applied, or a proposal would be reported as "updated" again. if (currentCatalogue() !== undefined) throw new Error("the change's outcome in this client's catalogue could not be read: neither applied nor proposed came back"); return { kind: "applied", record: answer }; } /** The answer for a change sent to the client as a proposal. */ export function formatProposedChange(entity, id, fields, outcome) { return formatSuccess(`Proposed to the client: nothing changes until one of the catalogue's owners approves it`, { id, entity, applied: false, proposed_fields: fields, proposal_reference: outcome.reference, expires_at: outcome.expiresAt, }); } //# sourceMappingURL=relationship-change.js.map