UNPKG

@withpica/mcp-server

Version:

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

126 lines • 7.52 kB
// Copyright (c) 2025-2026 Withpica Ltd. All rights reserved. import { formatSuccess } from "@withpica/mcp-utils"; export class FilesTools { pica; constructor(pica) { this.pica = pica; } getTools() { return [ { definition: { name: "pica_file_deliver", scope: "write:files", audiences: ["stdio", "http"], // Tier per ADR-230: `write` — this CREATES a revocable, expiring, // recipient-scoped delivery link (an insert), not a deletion. It // therefore does NOT warrant the `destructive:*` scope and IS // reachable on the OAuth connector (claude.ai / ChatGPT) under // `write:files` — agents need to "send files through chat". // // BUT the confirmation friction is deliberate and kept: on an IP // platform, "send the master to john@band.com" is typo-catastrophic // (the link is revocable, but a download that already happened can't // be un-sent). `previewMode: "two_step_token"` forces the same // confirmation-token round-trip the destructive tier would — without // the destructive:* scope or the 7-day freshness gate. The first // call returns a preview that surfaces recipient_email for the agent // to verify; the second call echoes the token to execute. tier: "write", previewMode: "two_step_token", vernacular_kind: "specialist", vernacular_reason: "Specialist outbound-sharing context; not yet covered by the Creator Question Atlas — pending telemetry-driven addition per ADR-226 Phase 4 substrate writes. Sister of pica_notify_user.", description: "Use when the user asks: 'send the master to john@band.com', " + "'give the supervisor the demo', 'share this track with my manager', " + "'email the stems to the studio'. " + "Generate a secure, time-limited delivery link for a file PICA holds. " + "Each delivery is bound to a specific recipient email — that recipient is " + "the accountability party on the audit trail, and the link can be revoked " + "via pica_file_revoke_delivery if it leaks. " + "Returns { id, recipient_email, access_token, expires_at } — the `id` is " + "the deliveryId for later revocation; share the access link (built from " + "the access_token by the workspace) with the recipient. " + "Default expiry is 48 hours; max 168 hours (1 week).", workflows: "infrastructure", inputSchema: { type: "object", properties: { file_id: { type: "string", description: "UUID of the file to deliver. Get this from pica_audio_query or " + "any inspect tool that surfaces audio file ids.", }, recipient_email: { type: "string", description: "Email address of the recipient — recorded on the delivery for the " + "audit trail. Confirm spelling with the user before calling; " + "deliveries are revocable but the email stays on the record.", }, expires_in_hours: { type: "number", description: "Hours until the link expires. Default 48. Maximum 168 (one week). " + "Shorter expiries are better for one-off shares; longer is reasonable " + "for ongoing collaborator access during a session.", }, }, required: ["file_id", "recipient_email"], }, }, executor: this.deliver.bind(this), }, { definition: { name: "pica_file_revoke_delivery", scope: "write:files", audiences: ["stdio", "http"], // Tier per ADR-230: `write` — kills access in place, the // delivery record persists, fully reversible by re-issuing a // new delivery. No new external data egress. tier: "write", vernacular_kind: "specialist", vernacular_reason: "Specialist outbound-sharing context; not yet covered by the Creator Question Atlas — pending telemetry-driven addition per ADR-226 Phase 4 substrate writes. Sister of pica_notify_user.", description: "Use when the user asks: 'cancel that link I sent to john', " + "'revoke the delivery from yesterday', 'kill the access to the master', " + "'they shouldn't have access anymore'. " + "Revoke a previously-issued delivery link so the recipient can no longer " + "use it — even if it hasn't expired yet. The delivery record stays on the " + "audit trail for accountability; only the access is killed.", workflows: "infrastructure", inputSchema: { type: "object", properties: { delivery_id: { type: "string", description: "UUID of the delivery to revoke — the `id` returned by " + "pica_file_deliver when the link was originally created.", }, }, required: ["delivery_id"], }, }, executor: this.revoke.bind(this), }, ]; } async deliver(args) { const result = await this.pica.files.deliver({ fileId: args.file_id, recipientEmail: args.recipient_email, expiresIn: args.expires_in_hours, }); return formatSuccess(`Delivery link created for ${result.recipient_email} (expires ${result.expires_at}). ` + `Share this token-bearing URL with the recipient; revoke via pica_file_revoke_delivery if needed using id ${result.id}.`, { delivery_id: result.id, file_id: result.file_id, recipient_email: result.recipient_email, access_token: result.access_token, expires_at: result.expires_at, revoked: result.revoked, }); } async revoke(args) { await this.pica.files.revokeDelivery(args.delivery_id); return formatSuccess(`Delivery ${args.delivery_id} revoked. The recipient can no longer use the link.`, { delivery_id: args.delivery_id, revoked: true }); } } //# sourceMappingURL=files.js.map