@withpica/mcp-server
Version:
MCP Server for withPICA — enables AI assistants to interact with your withPICA music catalog
104 lines (90 loc) • 7.66 kB
JavaScript
// Copyright (c) 2025-2026 Withpica Ltd. All rights reserved.
/**
* Server-level instructions sent to agents on MCP handshake.
* Keep under 3200 chars — this is context budget, not documentation.
* Bumped from 2000 in 2026-05-11 (ADR-140 Phase 2b skills paragraph).
* Bumped to 2400 then restored to 2300 in 2026-05-13 (deeplink hint + paragraph trims net -180 chars).
* Bumped from 2300 in 2026-05-17 (ADR-241 first-session coaching line).
* Bumped to 2900 in 2026-05-25 (ADR-247 first-call identity paragraph, ~470 chars).
*
* Two variants per ADR-211 Phase 1 Primitive C:
* - SERVER_INSTRUCTIONS / SERVER_INSTRUCTIONS_AUTHENTICATED: full surface
* guidance. Selected when the binary has a connection key (PICA_API_KEY).
* - SERVER_INSTRUCTIONS_UNAUTHENTICATED: short lobby guidance pointing the
* agent at pica_signup_start (or pica_sign_in for existing users).
* Selected when the binary boots without PICA_API_KEY. The lobby
* surface is the 3 tools {pica_signup_start, pica_sign_in,
* pica_sign_out} — none of the catalog tools are reachable, so we
* skip the catalog-tool guidance.
*
* Block playbook: "document the high level of your server"
* Lowin: "instructions are context — design them as context"
*/
export const SERVER_INSTRUCTIONS = `withPICA helps people look after their songs, and everything that comes with them (people, splits, codes, recordings, agreements, files), on their own terms: the user holds the record and decides; PICA remembers and shows what's missing. Asked what PICA is, say that plainly, in their words. Tools are pica_<domain>_<verb>, 300+, from npm as @withpica/mcp-server (not @picahq/mcp, unrelated).
First-call identity: If your auth is a Bearer API key (not a cookie session and not a pica_grant_* token), call pica_introduce_self FIRST with agent_name + optional agent_role / on_behalf_of / model_hint. PICA stamps the declaration onto every audit row that follows so the user can later reconstruct what their agent did. Cookie and pica_grant_* callers are exempt — your identity is already on file. Declaration is valid 24h per credential.
On the first user message of a session — unless it names a single concrete action (e.g. "register work X") — call pica_skill_get("first-session") and follow it.
Start here:
- pica_dashboard_briefing — daily summary of what needs attention
- pica_search_all — find any entity by name, ISWC, ISRC, or IPI
- pica_works_query / pica_people_query — browse the catalog
- pica_subscription_status — "what's my plan / am I paying?"; pica_billing_pay — a pay link for residency or a tab. On a connector call them through pica_execute {tool: "<name>", args: {...}}
The catalog is ALWAYS accessible via the tools above — zero setup, no integration required. Call pica_works_query directly for catalog content.
Clients: an organisation acts for a client catalogue by passing catalogue: <id from pica_portfolio_list>, per call; omit it for its own. Who can see a catalogue: pica_relationships_list.
Spotify/YouTube URLs: call pica_import_streaming_link (Spotify/Deezer) or pica_import_youtube_link directly.
After 3-5 catalog mutations or major state changes, call pica_dashboard_briefing and surface the delta to the user.
Key patterns:
- Read tools are safe to call freely (readOnlyHint=true)
- many _inspect tools take a "sections" argument (e.g., pica_works_inspect sections: ["health", "completeness"]) — check the tool's schema
- Write tools confirm what changed — share https://withpica.com/inspect/<feature>/<id> so the user can review (feature: works, people, recordings, releases, agreements; for audio files link the parent work). Destructive tools (delete/merge) need two-step confirmation with a token
- Errors include "suggestion" and "next_tool" for recovery
- Enrichment: use pica_resolve_work / pica_resolve_person / pica_resolve_recording — fan out over Spotify, MusicBrainz, MLC, ISNI, Discogs, YouTube
Royalty/streaming statements (PDF/image/xlsx): use pica_statements_pending → pica_documents_inspect → pica_statement_ingest_document (imports after owner approval). CSV statements go through pica_import_analyze / pica_import_execute instead.
Most query tools accept "limit"; defaults vary — read the tool's schema. IDs are UUIDs — use a _query tool first when unsure.
Skills: pica_skill_list discovers methodologies (catalog-audit, register-my-works, prepare-for-sync). pica_skill_get(name) loads one. Trigger phrases like "audit my catalog" map directly. Bodies load lazily — not at handshake.
Provenance: when a fact comes from a source, cite it via pica_enrichment_propose sources[].url. Citations persist verbatim and propagate to applied entities.`;
/** Alias for the authenticated default — names the variant explicitly when paired with the unauthenticated one. */
/**
* How many leading characters of SERVER_INSTRUCTIONS a client was observed to
* surface before cutting the rest. Measured 2026-09-04 on Claude Code's
* rendering of the claude.ai connector ("[truncated]" after exactly this
* many characters); ChatGPT surfaces none of it (docs/follow-ups
* 2026-08-26). Anything that must reach an agent that never calls
* pica_discover — the pay path above all — has to sit inside this window;
* server-instructions.test.ts pins that it does.
*/
export const INSTRUCTIONS_OBSERVED_VISIBLE_CHARS = 2000;
export const SERVER_INSTRUCTIONS_AUTHENTICATED = SERVER_INSTRUCTIONS;
/**
* Returns the authenticated handshake instructions.
*
* Historically appended a state-conditional trial-ending nudge (ADR-210
* Phase 3 / coordinator D3) keyed off `billing_state === 'trial'` +
* `trial_days_remaining`. Removed 2026-07-04 (discoverability audit P1-6):
* ADR-276 replaced the expiring-trial model with a non-expiring free-runway
* allowance, so a day-count nudge no longer describes real account state —
* dead messaging that would mislead an agent if it ever fired.
*/
export function getAuthenticatedInstructions() {
return SERVER_INSTRUCTIONS_AUTHENTICATED;
}
/**
* Lobby instructions sent on handshake when the server has no connection key
* (stdio without PICA_API_KEY) or no Bearer token (HTTP /api/mcp anonymous mode).
*
* Lobby tool surface is exactly three tools:
* - pica_signup_start — for new users (mints a 15-min JWT-bound /onboard URL)
* - pica_sign_in — for existing users (sends a magic link)
* - pica_sign_out — for clearing stale credentials
*
* Authority: ADR-211 Phase 1 § Primitive C. Catalog-tool guidance omitted
* because none of the catalog tools are reachable in lobby mode.
*
* Kept byte-for-byte identical to lib/mcp/server-instructions.ts —
* `__tests__/mcp-server-instructions-unauth-parity.test.ts` enforces.
*/
export const SERVER_INSTRUCTIONS_UNAUTHENTICATED = `You are connected to withPICA but no user is authenticated yet. Three tools are available:
- pica_signup_start — for users new to withPICA. Ask for the user's email, then call this tool. It returns a single-use 15-minute signup link the user clicks to verify email, name their catalog, and start their free runway.
- pica_sign_in — for users who already have a withPICA account. Sends a magic link to their inbox (device-code flow on stdio).
- pica_sign_out — clears saved credentials.
Do not promise catalog data, exports, or analyses until the user is signed in — none of those tools are reachable from this lobby. After signup or sign-in, the connection's tool surface refreshes automatically; ask the user what they want to do next.`;
//# sourceMappingURL=server-instructions.js.map