@withpica/mcp-server-directory 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +43 -26
  2. package/dist/prompts/index.d.ts +5 -6
  3. package/dist/prompts/index.d.ts.map +1 -1
  4. package/dist/prompts/index.js +92 -135
  5. package/dist/prompts/index.js.map +1 -1
  6. package/dist/prompts/public-question-atlas.d.ts +121 -0
  7. package/dist/prompts/public-question-atlas.d.ts.map +1 -0
  8. package/dist/prompts/public-question-atlas.js +404 -0
  9. package/dist/prompts/public-question-atlas.js.map +1 -0
  10. package/dist/tools/chain.d.ts +12 -0
  11. package/dist/tools/chain.d.ts.map +1 -0
  12. package/dist/tools/chain.js +109 -0
  13. package/dist/tools/chain.js.map +1 -0
  14. package/dist/tools/index.d.ts +9 -0
  15. package/dist/tools/index.d.ts.map +1 -1
  16. package/dist/tools/index.js +2 -0
  17. package/dist/tools/index.js.map +1 -1
  18. package/dist/tools/people.d.ts +0 -1
  19. package/dist/tools/people.d.ts.map +1 -1
  20. package/dist/tools/people.js +23 -36
  21. package/dist/tools/people.js.map +1 -1
  22. package/dist/tools/recordings.d.ts.map +1 -1
  23. package/dist/tools/recordings.js +7 -3
  24. package/dist/tools/recordings.js.map +1 -1
  25. package/dist/tools/search.d.ts.map +1 -1
  26. package/dist/tools/search.js +7 -4
  27. package/dist/tools/search.js.map +1 -1
  28. package/dist/tools/works.d.ts +0 -1
  29. package/dist/tools/works.d.ts.map +1 -1
  30. package/dist/tools/works.js +41 -42
  31. package/dist/tools/works.js.map +1 -1
  32. package/package.json +3 -2
  33. package/src/__tests__/prompts/index.test.ts +47 -64
  34. package/src/__tests__/prompts/prompt-eval-harness.test.ts +135 -104
  35. package/src/__tests__/tools/chain.test.ts +122 -0
  36. package/src/__tests__/tools/composability-chains.test.ts +4 -2
  37. package/src/__tests__/tools/people.test.ts +9 -3
  38. package/src/__tests__/tools/works.test.ts +32 -3
  39. package/src/prompts/index.ts +97 -141
  40. package/src/prompts/public-question-atlas.ts +540 -0
  41. package/src/tools/chain.ts +118 -0
  42. package/src/tools/index.ts +12 -0
  43. package/src/tools/people.ts +22 -41
  44. package/src/tools/recordings.ts +7 -3
  45. package/src/tools/search.ts +7 -4
  46. package/src/tools/works.ts +39 -46
package/CHANGELOG.md CHANGED
@@ -1,39 +1,56 @@
1
1
  # Changelog
2
2
 
3
- All notable changes to `@withpica/mcp-server-directory` will be documented in this file.
3
+ All notable changes to `@withpica/mcp-server-directory` are documented here.
4
4
 
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- > **Rule of the road:** every version bump to this package MUST land with a
9
- > matching entry here in the same commit. See the project's "npm publish
10
- > discipline" memory entry for the enforcement rationale.
5
+ The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to semantic versioning where the major number is incremented
7
+ for breaking tool-surface changes.
11
8
 
12
9
  ## [Unreleased]
13
10
 
14
- ## [1.1.0] 2026-04-13
11
+ ## [1.1.0] - 2026-04-21
15
12
 
16
- ### Changed
13
+ Shipped as minor rather than major despite the `*_full` tool removal:
14
+ the removed names had near-zero external adoption (they shipped recently
15
+ and weren't advertised externally), and staying on the 1.x line keeps
16
+ `^1.0.0` consumers on the upgrade path rather than stranding them on
17
+ the broken cascade. Clients that cached the `*_full` names will see a
18
+ tool-not-found error and need to refresh their tool list.
17
19
 
18
- - **ADR-171: Prompts replaced with workflow-level skills.**
19
- 3 prompts → 2 skills, each with decision trees, domain knowledge,
20
- and the shared preamble (tone, discovery principle, read-only note).
20
+ ### Breaking
21
21
 
22
- New skills: `discover-music`, `research-creator`.
22
+ - **Removed `directory_lookup_person_full` and `directory_lookup_work_full`.**
23
+ Both tools hit the same upstream endpoints as their non-`_full` counterparts
24
+ with only a formatting difference — there was no capability delta. The
25
+ `_full` variants are now the canonical names (`directory_lookup_person`
26
+ and `directory_lookup_work`); the thin variants have been deleted. Clients
27
+ that cached the `_full` names need to update their tool list; the
28
+ replacements return a superset of the prior data, so no output is lost.
23
29
 
24
- Retired prompts: `find-music`, `directory-autopilot`.
25
- `find-music` → `discover-music` (adds equal discovery principle,
26
- reference track search, similarity exploration).
27
- `directory-autopilot` routing folded into `research-creator`
28
- (identifier resolution, browsing, creator lookup all in one skill).
29
- `research-creator` gains collaborator network, similarity search,
30
- rights landscape, and identifier routing from the old autopilot.
30
+ ### Added
31
31
 
32
- ## [1.0.0]2026-04-06
32
+ - **`directory_chain` tool** one-call rights-chain lookup. Accepts a
33
+ free-text query, a direct ISWC/ISRC `identifier`, or audio-only filters
34
+ (BPM / key / energy / mood). Returns the already-public `ChainResult`
35
+ shape: work + writers + publishers (names + roles only, no IPIs or
36
+ splits) + linked recording + audio characteristics. Wraps the existing
37
+ public `/api/public/directory/chain` endpoint — no new backing API work.
38
+ - `directory_list_people` now accepts `letter` (A–Z, `#`) for alphabetical
39
+ browsing. The backend has supported this for months; only the MCP tool
40
+ was missing the parameter.
41
+ - `directory_list_works` now accepts `letter`, `sort` (`title` | `recent`),
42
+ and `isrc` — all previously backend-only.
33
43
 
34
- ### Added
44
+ ### Changed
35
45
 
36
- - Initial release of the PICA Public Directory MCP Server
37
- - 12 read-only tools for searching works, recordings, people, and identifiers
38
- - 3 prompts: `find-music`, `research-creator`, `directory-autopilot`
39
- - Deterministic eval harness for prompt routing validation
46
+ - **`directory_lookup_person` now matches its description.** Previously the
47
+ tool advertised ISNI / IPI / MusicBrainz ID support but the backing query
48
+ only matched `global_creator_id` — any non-UUID identifier silently 404'd.
49
+ The query now cascades through `global_creator_id` `isni` →
50
+ `cae_ipi_number` → `musicbrainz_id`, first hit wins.
51
+ - `directory_search` description rewritten to drop the false "ranked" claim.
52
+ The backing endpoint is a fan-out (`listWorks` + `listPeople`,
53
+ half-limit each), not cross-type ranking. Callers should prefer typed
54
+ list tools when they know the entity type.
55
+ - `directory_lookup_isrc` description rewritten to frame it honestly as a
56
+ pinned filter preset on `list_works` rather than a distinct lookup.
@@ -1,8 +1,6 @@
1
1
  /**
2
- * Skill Registry for Directory MCP Server
3
- * Workflow-level skills for music discovery and creator research.
4
- * Deployed as upgraded prompts; will convert to MCP skills format
5
- * when the spec extension ships (ADR-171).
2
+ * Prompt Registry for Directory MCP Server
3
+ * Guided workflows for music discovery, sync licensing, and rights research
6
4
  */
7
5
  export interface PromptDefinition {
8
6
  name: string;
@@ -27,7 +25,8 @@ export interface PromptResult {
27
25
  export declare class PromptRegistry {
28
26
  listPrompts(): PromptDefinition[];
29
27
  getPrompt(name: string, args?: Record<string, any>): Promise<PromptResult>;
30
- private getDiscoverMusicSkill;
31
- private getResearchCreatorSkill;
28
+ private getFindMusicPrompt;
29
+ private getResearchCreatorPrompt;
30
+ private getDirectoryAutopilotPrompt;
32
31
  }
33
32
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAkBD,qBAAa,cAAc;IACzB,WAAW,IAAI,gBAAgB,EAAE;IA8B3B,SAAS,CACb,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACzB,OAAO,CAAC,YAAY,CAAC;IAWxB,OAAO,CAAC,qBAAqB;IAiF7B,OAAO,CAAC,uBAAuB;CA2EhC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,qBAAa,cAAc;IACzB,WAAW,IAAI,gBAAgB,EAAE;IAoC3B,SAAS,CACb,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACzB,OAAO,CAAC,YAAY,CAAC;IAaxB,OAAO,CAAC,kBAAkB;IA6C1B,OAAO,CAAC,wBAAwB;IAwChC,OAAO,CAAC,2BAA2B;CAqCpC"}
@@ -1,25 +1,10 @@
1
1
  // Copyright (c) 2024-2026 Withpica Ltd. All rights reserved.
2
- const SHARED_PREAMBLE = `You are guiding a music seeker through the PICA public directory — a discovery layer over verified music catalogs.
3
-
4
- Tone: knowledgeable friend. You know what's available and how to find it. Straightforward, never salesy.
5
-
6
- Discovery principle: every creator's work has equal discoverability. Catalog quality determines visibility, not fame or follower count. Results are sorted by musical fit, not popularity. An unknown songwriter with analysed audio ranks the same as a major artist.
7
-
8
- Before starting this workflow:
9
- 1. Read the llms://primer resource to understand what's available in the directory
10
- 2. This is a read-only public directory — you can search and look up, but you can't create or modify anything
11
- 3. Only works from organisations that opted into the directory are visible
12
-
13
- After completing this workflow:
14
- - Summarise what you found in one short paragraph
15
- - Suggest the natural next step
16
- - If they say no, that's fine. Don't ask twice.`;
17
2
  export class PromptRegistry {
18
3
  listPrompts() {
19
4
  return [
20
5
  {
21
- name: "discover-music",
22
- description: "Find music for a sync brief, playlist, or project — search by mood, BPM, key, energy, or description. Equal discovery: results sorted by musical fit, not popularity",
6
+ name: "find-music",
7
+ description: "Find music for a sync brief, playlist, or project — search by mood, BPM, key, energy, or description",
23
8
  arguments: [
24
9
  {
25
10
  name: "brief",
@@ -30,7 +15,7 @@ export class PromptRegistry {
30
15
  },
31
16
  {
32
17
  name: "research-creator",
33
- description: "Research a songwriter, composer, or performer — full catalog, identifiers, collaborator network, rights landscape, and similarity search",
18
+ description: "Research a songwriter, composer, or performer — see their works, identifiers, collaborators, and verification status",
34
19
  arguments: [
35
20
  {
36
21
  name: "name_or_id",
@@ -39,166 +24,138 @@ export class PromptRegistry {
39
24
  },
40
25
  ],
41
26
  },
27
+ {
28
+ name: "directory-autopilot",
29
+ description: "Not sure where to start? Describe what you need and get routed to the right workflow — sync search, rights research, or identifier lookup",
30
+ arguments: [],
31
+ },
42
32
  ];
43
33
  }
44
34
  async getPrompt(name, args) {
45
35
  switch (name) {
46
- case "discover-music":
47
- return this.getDiscoverMusicSkill(args?.brief);
36
+ case "find-music":
37
+ return this.getFindMusicPrompt(args?.brief);
48
38
  case "research-creator":
49
- return this.getResearchCreatorSkill(args?.name_or_id);
39
+ return this.getResearchCreatorPrompt(args?.name_or_id);
40
+ case "directory-autopilot":
41
+ return this.getDirectoryAutopilotPrompt();
50
42
  default:
51
43
  throw new Error(`Prompt not found: ${name}`);
52
44
  }
53
45
  }
54
- getDiscoverMusicSkill(brief) {
46
+ getFindMusicPrompt(brief) {
55
47
  const briefInstruction = brief
56
48
  ? `The user is looking for: "${brief}". Translate this into audio search parameters.`
57
- : `Ask what they're looking for — a mood, a scene, a vibe, or specific audio characteristics (BPM, key, energy).`;
49
+ : `Ask me what I'm looking for — a mood, a scene, a vibe, or specific audio characteristics (BPM, key, energy).`;
58
50
  return {
59
51
  messages: [
60
52
  {
61
53
  role: "user",
62
54
  content: {
63
55
  type: "text",
64
- text: `${SHARED_PREAMBLE}
56
+ text: `Help me find music in the PICA public directory for a sync brief or project.
65
57
 
66
- --- SKILL: discover-music ---
58
+ ${briefInstruction}
67
59
 
68
- Help find music by what it sounds like, not who made it. Equal discovery — every well-catalogued work has the same chance.
60
+ Workflow:
61
+ 1. Translate the brief into search parameters for directory_search_recordings:
62
+ - Mood descriptions → energy, danceability, key_mode, mood filters
63
+ - "Upbeat" → min_energy: 0.6, min_danceability: 0.5
64
+ - "Dark/moody" → max_energy: 0.4, key_mode: minor
65
+ - "Chill" → max_energy: 0.4, max_bpm: 100
66
+ - Specific requests → use BPM, key, duration filters directly
69
67
 
70
- ${briefInstruction}
68
+ 2. Run directory_search_recordings with the parameters.
69
+
70
+ 3. For each promising result, use directory_lookup_work to get:
71
+ - Who wrote it (credits with IPI numbers)
72
+ - Whether credits are attested (verified ownership)
73
+ - DSP links (Spotify, Apple Music — so the user can listen)
74
+ - Registration score (higher = cleaner rights chain)
71
75
 
72
- Sync brief / mood-based search:
73
- Extract parameters from natural language:
74
- mood, BPM range, key, energy, instrumentation, vocal/instrumental, duration constraints
75
- Translate mood descriptions to search parameters for directory_search_recordings:
76
- - "Upbeat" → min_energy: 0.6, min_danceability: 0.5
77
- - "Dark/moody" → max_energy: 0.4, key_mode: minor
78
- - "Chill" → max_energy: 0.4, max_bpm: 100
79
- - Specific requests → use BPM, key, duration filters directly
80
- → Run directory_search_recordings with the parameters
81
- → Present results by musical fit, not popularity:
82
- "here are [N] tracks that match. sorted by how closely they fit your brief, not by who made them."
83
- → Per result: title, creator, BPM, key, mood tags, duration.
84
- No follower counts. No stream numbers.
85
-
86
- For each promising result, use directory_lookup_work_full to get:
87
- - Who wrote it (credits with IPI numbers)
88
- - Whether credits are attested (verified ownership)
89
- - DSP links (Spotify, Apple Music — so the user can listen)
90
- - Registration score (higher = cleaner rights chain)
91
-
92
- Present as a shortlist with:
93
- - Title, artist, BPM, key, energy
94
- - Credits summary (who to contact for licensing)
95
- - Any flags (unattested credits, low registration score, missing ISRC)
96
-
97
- Reference track search:
98
- → "got a reference track? tell me what you like about it."
99
- → Parse what they value: tempo, mood, instrumentation, vocal style
100
- → Search by those parameters
101
-
102
- Similarity exploration:
103
- → "want to find music similar to [track] by someone you've never heard of?"
104
- → Search by the sound, not the name — this is where the discovery principle lives
105
-
106
- If they like one:
107
- → "want to hear more from this creator, or find similar tracks?"
108
- → Similar → search with same parameters
109
- → More from creator → pivot to research-creator skill
110
-
111
- Rights check:
112
- → For any track: "want to check the rights situation?"
113
- → Show ownership, publisher, contact path via directory_lookup_work_full
114
- → If enquiry → guide through submission
76
+ 4. Present results as a shortlist with:
77
+ - Title, artist, BPM, key, energy
78
+ - Credits summary (who to contact for licensing)
79
+ - Any flags (unattested credits, low registration score, missing ISRC)
115
80
 
116
81
  If no results match, suggest broadening the search (wider BPM range, drop key filter, etc.).
117
82
 
118
- If the catalog is small, say so: "the directory currently has [N] works it's growing. here's what matches from what's available."
83
+ Important: This is a public directory only works from organisations that opted in are visible. If the catalog is small, say so.`,
84
+ },
85
+ },
86
+ ],
87
+ };
88
+ }
89
+ getResearchCreatorPrompt(nameOrId) {
90
+ const searchInstruction = nameOrId
91
+ ? `Look up: "${nameOrId}". Try directory_lookup_person first (it accepts name, IPI, ISNI, or MusicBrainz ID). If that doesn't match, use directory_list_people with a text search.`
92
+ : `Ask me for the creator's name, IPI number, ISNI, or MusicBrainz ID.`;
93
+ return {
94
+ messages: [
95
+ {
96
+ role: "user",
97
+ content: {
98
+ type: "text",
99
+ text: `Help me research a music creator in the PICA public directory.
119
100
 
120
- Domain knowledge:
121
- - Results sorted by audio-parameter match, not streams or followers
122
- - Reference track searching works by extracting musical qualities, not artist similarity
123
- - Rights information is always available — the directory doesn't hide who owns what
124
- - Sync supervisors think in briefs (mood + tempo + energy + duration), not artist names
125
- - Similarity search by audio surfaces genuinely similar music the seeker might never have found
101
+ ${searchInstruction}
126
102
 
127
- Tools: directory_search_recordings, directory_search, directory_lookup_work, directory_lookup_work_full, directory_lookup_person, directory_lookup_person_full`,
103
+ Once you find the person, use directory_lookup_person to get their complete profile:
104
+ - Identifiers (IPI, ISNI, MusicBrainz) — essential for rights verification
105
+ - All credited works with roles (writer, composer, performer, producer)
106
+ - Collaborator network — who they work with
107
+ - Verification score — how complete their profile is
108
+
109
+ Then for their most notable works (up to 5), use directory_lookup_work to get:
110
+ - Full credits and splits (are they the sole writer or one of many?)
111
+ - Recordings with ISRCs
112
+ - Audio analysis (BPM, key, energy)
113
+ - DSP links and registration status
114
+
115
+ Present a summary:
116
+ - Creator profile (name, identifiers, role patterns)
117
+ - Catalog overview (how many works, typical roles, common collaborators)
118
+ - Notable works with credit details
119
+ - Any gaps (missing identifiers, unattested credits, low scores)
120
+
121
+ This is useful for: rights research, due diligence before licensing, publisher evaluation, or understanding a catalog before acquisition.`,
128
122
  },
129
123
  },
130
124
  ],
131
125
  };
132
126
  }
133
- getResearchCreatorSkill(nameOrId) {
134
- const searchInstruction = nameOrId
135
- ? `Look up: "${nameOrId}". Try directory_lookup_person_full first (it accepts name, IPI, ISNI, or MusicBrainz ID). If that doesn't match, use directory_list_people with a text search.`
136
- : `Ask for the creator's name, IPI number, ISNI, or MusicBrainz ID.`;
127
+ getDirectoryAutopilotPrompt() {
137
128
  return {
138
129
  messages: [
139
130
  {
140
131
  role: "user",
141
132
  content: {
142
133
  type: "text",
143
- text: `${SHARED_PREAMBLE}
134
+ text: `You've connected to the PICA public music directory. Help me find what I need.
144
135
 
145
- --- SKILL: research-creator ---
136
+ First, read the llms://primer resource to understand what's available.
146
137
 
147
- Deep-dive on a specific creator. Full catalog, identifiers, collaborator network, rights landscape.
138
+ Then ask me what I'm looking for. Based on my answer, route to the right workflow:
148
139
 
149
- Also handles routing that was previously in directory-autopilot:
150
- - If the user has a specific identifier to resolve (ISRC, ISWC, IPI, ISNI):
151
- → ISRC (e.g. USABC1234567) → directory_lookup_isrc → then directory_lookup_work_full
152
- → ISWC (e.g. T-123.456.789-0) → directory_lookup_work_full
153
- → IPI or ISNI → directory_lookup_person_full
154
- → MusicBrainz ID → directory_lookup_person_full
155
- - If the user wants to browse → use directory_search with a broad query, or directory_list_works / directory_list_people
140
+ If I'm looking for MUSIC FOR A PROJECT (sync brief, playlist, mood search):
141
+ Use the find-music workflow. Translate my description into audio search parameters and search recordings by BPM, key, energy, mood. Then look up full details on promising matches.
156
142
 
157
- "who do you want to learn about?"
143
+ If I'm looking for INFORMATION ABOUT A CREATOR (songwriter, composer, performer):
144
+ → Use the research-creator workflow. Look up their profile, works, identifiers, and collaborators.
158
145
 
159
- ${searchInstruction}
146
+ If I have a SPECIFIC IDENTIFIER to resolve (ISRC, ISWC, IPI, ISNI):
147
+ → Route directly to the right lookup tool:
148
+ - ISRC (e.g. USABC1234567) → directory_lookup_isrc → then directory_lookup_work
149
+ - ISWC (e.g. T-123.456.789-0) → directory_lookup_work
150
+ - IPI or ISNI → directory_lookup_person
151
+ - MusicBrainz ID → directory_lookup_person
152
+
153
+ If I want to BROWSE what's in the directory:
154
+ → Use directory_search with a broad query, or directory_list_works / directory_list_people to paginate.
155
+
156
+ Tell me which workflow you chose and why, in one sentence. Offer alternatives.
160
157
 
161
- Lookup by name, IPI, ISNI, or ISRC:
162
- → Find the person using directory_lookup_person_full
163
- → If multiple matches: present with distinguishing works/roles
164
-
165
- Creator profile:
166
- → Full catalog: all works, roles, co-writers
167
- → Identifiers: IPI, ISNI, MusicBrainz, IPN
168
- → Collaborator network: "frequently works with [names]"
169
- → Genre/mood footprint: based on analysed audio across catalog
170
-
171
- For their most notable works (up to 5), use directory_lookup_work_full to get:
172
- - Full credits and splits (are they the sole writer or one of many?)
173
- - Recordings with ISRCs
174
- - Audio analysis (BPM, key, energy)
175
- - DSP links and registration status
176
-
177
- Cross-reference:
178
- → "want to verify their identifiers against ISNI or MusicBrainz?"
179
- → Flag discrepancies
180
-
181
- Similarity exploration:
182
- → "want to find other creators with a similar sound?"
183
- → Use directory_search_recordings by audio characteristics of their catalog
184
- → Equal discovery: results by sound, not fame
185
-
186
- Rights landscape:
187
- → "want to know who controls their catalog?"
188
- → Publishers, agreements, licensing paths
189
-
190
- After research:
191
- → Summary: creator profile, catalog overview, notable works, gaps
192
- → "want to submit a licensing enquiry, or explore more creators?"
193
-
194
- Domain knowledge:
195
- - Creator research often starts from one work and expands via collaborator network — adjacent talent discovery
196
- - Identifier verification across sources catches discrepancies that matter for rights
197
- - Similarity search by audio surfaces genuinely similar music through non-traditional channels
198
- - The collaborator network is how you discover creators no algorithm would surface
199
- - This is useful for: rights research, due diligence before licensing, publisher evaluation, or catalog acquisition
200
-
201
- Tools: directory_lookup_person_full, directory_lookup_work_full, directory_search_recordings, directory_search, directory_lookup_isrc, directory_list_works, directory_list_people`,
158
+ Important: This is a read-only public directory. I can search and look up, but I can't create or modify anything. Only works from organisations that opted into the directory are visible.`,
202
159
  },
203
160
  },
204
161
  ],
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAgC7D,MAAM,eAAe,GAAG;;;;;;;;;;;;;;gDAcwB,CAAC;AAEjD,MAAM,OAAO,cAAc;IACzB,WAAW;QACT,OAAO;YACL;gBACE,IAAI,EAAE,gBAAgB;gBACtB,WAAW,EACT,sKAAsK;gBACxK,SAAS,EAAE;oBACT;wBACE,IAAI,EAAE,OAAO;wBACb,WAAW,EACT,+EAA+E;wBACjF,QAAQ,EAAE,KAAK;qBAChB;iBACF;aACF;YACD;gBACE,IAAI,EAAE,kBAAkB;gBACxB,WAAW,EACT,0IAA0I;gBAC5I,SAAS,EAAE;oBACT;wBACE,IAAI,EAAE,YAAY;wBAClB,WAAW,EAAE,mDAAmD;wBAChE,QAAQ,EAAE,KAAK;qBAChB;iBACF;aACF;SACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,SAAS,CACb,IAAY,EACZ,IAA0B;QAE1B,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,gBAAgB;gBACnB,OAAO,IAAI,CAAC,qBAAqB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACjD,KAAK,kBAAkB;gBACrB,OAAO,IAAI,CAAC,uBAAuB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YACxD;gBACE,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAEO,qBAAqB,CAAC,KAAc;QAC1C,MAAM,gBAAgB,GAAG,KAAK;YAC5B,CAAC,CAAC,6BAA6B,KAAK,iDAAiD;YACrF,CAAC,CAAC,+GAA+G,CAAC;QAEpH,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE;wBACP,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,GAAG,eAAe;;;;;;EAMlC,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+JAyD6I;qBACpJ;iBACF;aACF;SACF,CAAC;IACJ,CAAC;IAEO,uBAAuB,CAAC,QAAiB;QAC/C,MAAM,iBAAiB,GAAG,QAAQ;YAChC,CAAC,CAAC,aAAa,QAAQ,iKAAiK;YACxL,CAAC,CAAC,kEAAkE,CAAC;QAEvE,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE;wBACP,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,GAAG,eAAe;;;;;;;;;;;;;;;;EAgBlC,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mLA0CgK;qBACxK;iBACF;aACF;SACF,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAAA,6DAA6D;AA8B7D,MAAM,OAAO,cAAc;IACzB,WAAW;QACT,OAAO;YACL;gBACE,IAAI,EAAE,YAAY;gBAClB,WAAW,EACT,sGAAsG;gBACxG,SAAS,EAAE;oBACT;wBACE,IAAI,EAAE,OAAO;wBACb,WAAW,EACT,+EAA+E;wBACjF,QAAQ,EAAE,KAAK;qBAChB;iBACF;aACF;YACD;gBACE,IAAI,EAAE,kBAAkB;gBACxB,WAAW,EACT,sHAAsH;gBACxH,SAAS,EAAE;oBACT;wBACE,IAAI,EAAE,YAAY;wBAClB,WAAW,EAAE,mDAAmD;wBAChE,QAAQ,EAAE,KAAK;qBAChB;iBACF;aACF;YACD;gBACE,IAAI,EAAE,qBAAqB;gBAC3B,WAAW,EACT,2IAA2I;gBAC7I,SAAS,EAAE,EAAE;aACd;SACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,SAAS,CACb,IAAY,EACZ,IAA0B;QAE1B,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,YAAY;gBACf,OAAO,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC9C,KAAK,kBAAkB;gBACrB,OAAO,IAAI,CAAC,wBAAwB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YACzD,KAAK,qBAAqB;gBACxB,OAAO,IAAI,CAAC,2BAA2B,EAAE,CAAC;YAC5C;gBACE,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAEO,kBAAkB,CAAC,KAAc;QACvC,MAAM,gBAAgB,GAAG,KAAK;YAC5B,CAAC,CAAC,6BAA6B,KAAK,iDAAiD;YACrF,CAAC,CAAC,8GAA8G,CAAC;QAEnH,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE;wBACP,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE;;EAEhB,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;kIAyBgH;qBACvH;iBACF;aACF;SACF,CAAC;IACJ,CAAC;IAEO,wBAAwB,CAAC,QAAiB;QAChD,MAAM,iBAAiB,GAAG,QAAQ;YAChC,CAAC,CAAC,aAAa,QAAQ,4JAA4J;YACnL,CAAC,CAAC,qEAAqE,CAAC;QAE1E,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE;wBACP,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE;;EAEhB,iBAAiB;;;;;;;;;;;;;;;;;;;;0IAoBuH;qBAC/H;iBACF;aACF;SACF,CAAC;IACJ,CAAC;IAEO,2BAA2B;QACjC,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE;wBACP,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;2LAwByK;qBAChL;iBACF;aACF;SACF,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Public Question Atlas — ADR-229 Decision 1.
3
+ *
4
+ * Source-of-truth registry mapping natural public-discovery questions to
5
+ * the canonical directory-MCP tool resolution. Sister of:
6
+ * - `mcp-server/src/prompts/creator-question-atlas.ts` (ADR-226, customer)
7
+ * - `team-mcp-server/src/prompts/operator-question-atlas.ts` (ADR-228, operator)
8
+ *
9
+ * Read by:
10
+ *
11
+ * - lint Rule 11F (extended in ADR-229) — validates every `directory_*`
12
+ * tool's `Use when the user asks` block cites questions resolving
13
+ * here, rejects creator/operator atlas cross-pollination, asserts
14
+ * mutual exclusivity of `clean_empty_state` and `fallback_when_empty`,
15
+ * and asserts `disambiguation` shape integrity
16
+ * - `scripts/intent-resolution-eval.ts --surface=directory` (ADR-229 PR-3)
17
+ * - the Phase 4 description rewrites — `Use when the user asks` blocks
18
+ * pull question + synonym strings from here
19
+ *
20
+ * The `AtlasEntry` type is inline-duplicated rather than imported from a
21
+ * shared package, mirroring ADR-228's choice (Open Question 3 default —
22
+ * extract to `packages/mcp-atlas-types/` only if a fourth MCP surface
23
+ * lands or the type drift becomes painful).
24
+ *
25
+ * Two shape extensions vs the creator and operator atlases (per ADR-229
26
+ * Decision 4):
27
+ *
28
+ * 1. `clean_empty_state?: { message; suggest_query_shape }` — public-
29
+ * surface analog of `fallback_when_empty`. The directory has no
30
+ * internal action to nudge toward (the empty state IS the final
31
+ * answer for the anonymous user); this field carries the prescribed
32
+ * empty-state copy plus a query-shape hint for the calling LLM.
33
+ *
34
+ * 2. `disambiguation?: { ambiguous_terms[]; resolver_tool; resolver_intent }` —
35
+ * first-class concern on the public surface (creator/operator MCPs
36
+ * have a calling-context that narrows the search; the public
37
+ * directory hits "Bowie", "Sade", "Madonna", "Lover Boy" constantly
38
+ * and must declare an explicit resolver step).
39
+ *
40
+ * `clean_empty_state` and `fallback_when_empty` are mutually exclusive on
41
+ * a single entry — Rule 11F enforces this at lint time.
42
+ *
43
+ * The public atlas omits `natural_domain` (creator-side binds to
44
+ * `discovery.ts` CATEGORIES; the directory MCP has no equivalent
45
+ * taxonomy — the discovery surface is search and lookup, not category-
46
+ * faceted browse). It also omits `available_when` (the operator atlas's
47
+ * forward-compat hook for unshipped sections; the directory has no
48
+ * deferred-section concept).
49
+ */
50
+ export interface AtlasFallback {
51
+ message: string;
52
+ next_tool: string;
53
+ }
54
+ export interface AtlasCleanEmptyState {
55
+ /**
56
+ * Atlas-prescribed copy for the empty-state response. The calling LLM
57
+ * may render in its own voice; the suggested-query-shape hint is the
58
+ * load-bearing part.
59
+ */
60
+ message: string;
61
+ /**
62
+ * Free-text hint for how to refine the query, interpreted by the LLM
63
+ * as guidance (not rendered verbatim). Example:
64
+ * `"title + writer | title + year | ISWC if known"`.
65
+ */
66
+ suggest_query_shape: string;
67
+ }
68
+ export interface AtlasDisambiguation {
69
+ /**
70
+ * Names known to be ambiguous in the music-metadata domain (multiple
71
+ * persons, artist projects, or works with the same string). v1 ships
72
+ * a static list; v2 (deferred per ADR-229 § Risks #3) could resolve
73
+ * dynamically against the index's name-collision frequency.
74
+ */
75
+ ambiguous_terms: string[];
76
+ /**
77
+ * The directory tool the agent should call FIRST to surface candidate
78
+ * entities for the user to disambiguate before committing to the
79
+ * lookup tool in `resolves_to`.
80
+ */
81
+ resolver_tool: string;
82
+ /**
83
+ * Free-text guidance for the LLM on how to run the resolver step.
84
+ * Example: `"Call directory_lookup_person first to surface candidates;
85
+ * ask which one before calling directory_list_works."`
86
+ */
87
+ resolver_intent: string;
88
+ }
89
+ export type AtlasResolution = {
90
+ kind: "tool";
91
+ name: string;
92
+ default_args?: Record<string, unknown>;
93
+ } | {
94
+ kind: "prompt";
95
+ name: string;
96
+ };
97
+ export interface AtlasEntry {
98
+ question: string;
99
+ synonyms: string[];
100
+ resolves_to: AtlasResolution;
101
+ /** Mutually exclusive with `clean_empty_state` (lint-enforced). */
102
+ fallback_when_empty?: AtlasFallback;
103
+ /** ADR-229 Decision 4 — public-surface empty-state contract. */
104
+ clean_empty_state?: AtlasCleanEmptyState;
105
+ /** ADR-229 Decision 4 — public-surface name-collision contract. */
106
+ disambiguation?: AtlasDisambiguation;
107
+ }
108
+ /**
109
+ * Names known-ambiguous in the music-metadata domain — multiple persons
110
+ * sharing a stage name, or artist project names that collide with
111
+ * person names. Seed list per ADR-229 § Open Q2 (case-insensitive — the
112
+ * lint and the resolver normalise on lowercase).
113
+ *
114
+ * Grow this list as Phase 5 eval data surfaces real collisions the
115
+ * static seed misses. Do not prune without eval evidence — the cost of
116
+ * missing a real collision (wrong-tool routing on a public-facing
117
+ * surface) is higher than the cost of an extra resolver call.
118
+ */
119
+ export declare const AMBIGUOUS_NAMES: string[];
120
+ export declare const PUBLIC_ATLAS: AtlasEntry[];
121
+ //# sourceMappingURL=public-question-atlas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public-question-atlas.d.ts","sourceRoot":"","sources":["../../src/prompts/public-question-atlas.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErC,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,EAAE,eAAe,CAAC;IAC7B,mEAAmE;IACnE,mBAAmB,CAAC,EAAE,aAAa,CAAC;IACpC,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,oBAAoB,CAAC;IACzC,mEAAmE;IACnE,cAAc,CAAC,EAAE,mBAAmB,CAAC;CACtC;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,EAWnC,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,UAAU,EAqZpC,CAAC"}