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