@withpica/mcp-server
Version:
MCP Server for withPICA — enables AI assistants to interact with your withPICA music catalog
135 lines • 7.51 kB
JavaScript
// Copyright (c) 2025-2026 Withpica Ltd. All rights reserved.
import { formatSuccess } from "@withpica/mcp-utils";
export class StatementsTools {
pica;
constructor(pica) {
this.pica = pica;
}
getTools() {
return [
{
definition: {
name: "pica_statements_pending",
scope: "read:finances",
audiences: ["stdio", "http", "public"],
tier: "read",
description: "List uploaded royalty/streaming statement documents the user hasn't imported yet. For each, read it with pica_documents_inspect, extract the line items, and import with pica_statement_ingest_document. Returns lean summaries (id, title, parsing_status) — no financial figures. Statements can't be emailed into PICA: if the user has a statement that isn't listed, ask them to upload it (the result's forwarding field says the same). Statements already imported are not listed here — use pica_statements_query for those.",
workflows: "infrastructure",
vernacular_kind: "specialist",
vernacular_reason: "Specialist discovery for the statement-ingestion flow, outside the Creator Question Atlas.",
annotations: {
title: "pending statements",
readOnlyHint: true,
idempotentHint: true,
},
inputSchema: {
type: "object",
properties: {
parsed_status: {
type: "string",
enum: ["pending", "completed", "all"],
description: "filter by parse state",
},
limit: {
type: "number",
description: "max rows (default 25, max 50)",
},
offset: { type: "number", description: "pagination offset" },
},
},
},
executor: this.listPending.bind(this),
},
{
definition: {
name: "pica_statement_ingest_document",
scope: "write:finances",
audiences: ["stdio", "http", "public"],
tier: "write",
// Delegated agents (OAuth/grant) propose; the org owner approves
// in-view/email; PICA replays via human-approval-executor (ADR-250).
approvalMode: "human",
description: "When the user has uploaded a royalty/streaming statement document (PDF, image, or xlsx — NOT csv; csv goes through pica_import_analyze / pica_import_execute instead, a deterministic row-by-row importer with no AI extraction step), read it with pica_documents_inspect, extract the line items, then call this to import them. Money is fallible: extract fewer rows confidently over many rows wrongly, set a per-row confidence, and never guess a figure. Returns a summary; the import only lands after the owner approves. Find pending statements with pica_statements_pending.",
workflows: "infrastructure",
vernacular_kind: "specialist",
vernacular_reason: "Financial write behind human approval; invoked by exact name in a specialist statement-ingestion flow, outside the Creator Question Atlas.",
annotations: { title: "ingest statement document" },
inputSchema: {
type: "object",
properties: {
document_id: {
type: "string",
description: "the uploaded statement document id",
},
source: {
type: "string",
description: "the society/distributor the statement is from, e.g. 'PRS', 'DistroKid'",
},
statement_period: {
type: "string",
description: "e.g. 'Q4 2025' (optional)",
},
rows: {
type: "array",
description: "one entry per statement line you read",
items: {
type: "object",
properties: {
work_title: { type: "string" },
amount: { type: "number" },
currency: { type: "string" },
payment_date: {
type: "string",
description: "ISO date YYYY-MM-DD",
},
stream_quantity: {
type: "number",
description: "plays/streams; omit for society statements",
},
territory: { type: "string" },
revenue_type: { type: "string" },
isrc: { type: "string" },
iswc: { type: "string" },
ipi: { type: "string" },
tunecode: { type: "string" },
writer_name: { type: "string" },
confidence: {
type: "number",
description: "0-1, your confidence in this line",
},
},
required: [
"work_title",
"amount",
"payment_date",
"confidence",
],
},
},
},
required: ["document_id", "source", "rows"],
},
},
executor: this.ingestDocument.bind(this),
},
];
}
async listPending(args) {
const result = await this.pica.statements.listPending({
limit: args.limit,
offset: args.offset,
parsed_status: args.parsed_status,
});
return formatSuccess("Pending statements", result);
}
async ingestDocument(args) {
const result = await this.pica.statements.ingestDocument({
document_id: args.document_id,
source: args.source,
statement_period: args.statement_period,
rows: args.rows,
});
return formatSuccess("Statement rows ingested", result);
}
}
//# sourceMappingURL=statements.js.map