@withpica/mcp-server-directory 1.0.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.
- package/dist/client.d.ts +12 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +92 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +14 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/index.d.ts +32 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +168 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/resources/llms-primer.d.ts +2 -0
- package/dist/resources/llms-primer.d.ts.map +1 -0
- package/dist/resources/llms-primer.js +34 -0
- package/dist/resources/llms-primer.js.map +1 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +103 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/index.d.ts +26 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +42 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/people.d.ts +14 -0
- package/dist/tools/people.d.ts.map +1 -0
- package/dist/tools/people.js +189 -0
- package/dist/tools/people.js.map +1 -0
- package/dist/tools/recordings.d.ts +12 -0
- package/dist/tools/recordings.d.ts.map +1 -0
- package/dist/tools/recordings.js +140 -0
- package/dist/tools/recordings.js.map +1 -0
- package/dist/tools/search.d.ts +12 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +52 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/works.d.ts +15 -0
- package/dist/tools/works.d.ts.map +1 -0
- package/dist/tools/works.js +248 -0
- package/dist/tools/works.js.map +1 -0
- package/dist/utils/errors.d.ts +14 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +47 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/formatting.d.ts +10 -0
- package/dist/utils/formatting.d.ts.map +1 -0
- package/dist/utils/formatting.js +15 -0
- package/dist/utils/formatting.js.map +1 -0
- package/package.json +34 -0
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface DirectoryClientConfig {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
debug?: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare class DirectoryClient {
|
|
6
|
+
private baseUrl;
|
|
7
|
+
private debug;
|
|
8
|
+
constructor(config: DirectoryClientConfig);
|
|
9
|
+
private fetchWithTimeout;
|
|
10
|
+
request<T>(path: string, params?: Record<string, string>): Promise<T>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAU;gBAEX,MAAM,EAAE,qBAAqB;YAK3B,gBAAgB;IAmBxB,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAgF5E"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const DEFAULT_TIMEOUT_MS = 15_000;
|
|
2
|
+
const MAX_RETRIES = 2;
|
|
3
|
+
const RETRY_BASE_MS = 500;
|
|
4
|
+
function isRetryableStatus(status) {
|
|
5
|
+
return status === 429 || status === 502 || status === 503 || status === 504;
|
|
6
|
+
}
|
|
7
|
+
function sleep(ms) {
|
|
8
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
9
|
+
}
|
|
10
|
+
export class DirectoryClient {
|
|
11
|
+
baseUrl;
|
|
12
|
+
debug;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
15
|
+
this.debug = config.debug || false;
|
|
16
|
+
}
|
|
17
|
+
async fetchWithTimeout(url, init, timeoutMs) {
|
|
18
|
+
const controller = new AbortController();
|
|
19
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
20
|
+
try {
|
|
21
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
if (err.name === "AbortError") {
|
|
25
|
+
throw new Error(`Request timed out after ${timeoutMs}ms: GET ${url}`);
|
|
26
|
+
}
|
|
27
|
+
throw err;
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
clearTimeout(timer);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async request(path, params) {
|
|
34
|
+
const url = new URL(`${this.baseUrl}/api/public/directory${path}`);
|
|
35
|
+
if (params) {
|
|
36
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
37
|
+
if (value !== undefined && value !== "") {
|
|
38
|
+
url.searchParams.set(key, value);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
if (this.debug) {
|
|
43
|
+
console.error(`[Directory MCP] GET ${url.toString()} (timeout: ${DEFAULT_TIMEOUT_MS}ms)`);
|
|
44
|
+
}
|
|
45
|
+
let lastError;
|
|
46
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
47
|
+
try {
|
|
48
|
+
const response = await this.fetchWithTimeout(url.toString(), { method: "GET", headers: { Accept: "application/json" } }, DEFAULT_TIMEOUT_MS);
|
|
49
|
+
if (response.ok) {
|
|
50
|
+
const json = await response.json();
|
|
51
|
+
if (json.success === false) {
|
|
52
|
+
throw new Error(json.error || "API returned unsuccessful response");
|
|
53
|
+
}
|
|
54
|
+
return json;
|
|
55
|
+
}
|
|
56
|
+
const errorText = await response.text();
|
|
57
|
+
// Auth errors — fail fast, never retry
|
|
58
|
+
if (response.status === 401 || response.status === 403) {
|
|
59
|
+
throw new Error(`Authentication failed: ${response.status} ${errorText}`);
|
|
60
|
+
}
|
|
61
|
+
if (isRetryableStatus(response.status) && attempt < MAX_RETRIES) {
|
|
62
|
+
const retryAfter = response.headers.get("retry-after");
|
|
63
|
+
const parsed = retryAfter ? parseInt(retryAfter, 10) : NaN;
|
|
64
|
+
const delayMs = !isNaN(parsed)
|
|
65
|
+
? parsed * 1000
|
|
66
|
+
: RETRY_BASE_MS * Math.pow(2, attempt);
|
|
67
|
+
if (this.debug) {
|
|
68
|
+
console.error(`[Directory MCP] ${response.status} on attempt ${attempt + 1}, retrying in ${delayMs}ms`);
|
|
69
|
+
}
|
|
70
|
+
await sleep(delayMs);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
throw new Error(`API request failed: ${response.status} ${errorText}`);
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
lastError = err;
|
|
77
|
+
if (err.message?.includes("timed out") &&
|
|
78
|
+
attempt < MAX_RETRIES) {
|
|
79
|
+
const delayMs = RETRY_BASE_MS * Math.pow(2, attempt);
|
|
80
|
+
if (this.debug) {
|
|
81
|
+
console.error(`[Directory MCP] timeout on attempt ${attempt + 1}, retrying in ${delayMs}ms`);
|
|
82
|
+
}
|
|
83
|
+
await sleep(delayMs);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
throw lastError || new Error("Request failed after retries");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface ServerConfig {
|
|
2
|
+
directoryUrl: string;
|
|
3
|
+
serverName: string;
|
|
4
|
+
version: string;
|
|
5
|
+
debug: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function loadConfig(): ServerConfig;
|
|
8
|
+
export declare function validateConfig(config: ServerConfig): void;
|
|
9
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,UAAU,IAAI,YAAY,CAOzC;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAIzD"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function loadConfig() {
|
|
2
|
+
return {
|
|
3
|
+
directoryUrl: process.env.PICA_DIRECTORY_URL || "https://withpica.com",
|
|
4
|
+
serverName: "pica-directory-mcp-server",
|
|
5
|
+
version: "1.0.0",
|
|
6
|
+
debug: process.env.DEBUG === "true" || process.env.DEBUG === "1",
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export function validateConfig(config) {
|
|
10
|
+
if (!config.directoryUrl || !config.directoryUrl.startsWith("http")) {
|
|
11
|
+
throw new Error("Invalid PICA_DIRECTORY_URL");
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,UAAU;IACxB,OAAO;QACL,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,sBAAsB;QACtE,UAAU,EAAE,2BAA2B;QACvC,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,GAAG;KACjE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAoB;IACjD,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACpE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { loadConfig, validateConfig } from "./config.js";
|
|
3
|
+
import { DirectoryMcpServer } from "./server.js";
|
|
4
|
+
async function main() {
|
|
5
|
+
try {
|
|
6
|
+
const config = loadConfig();
|
|
7
|
+
validateConfig(config);
|
|
8
|
+
const server = new DirectoryMcpServer(config);
|
|
9
|
+
await server.start();
|
|
10
|
+
process.on("SIGINT", async () => {
|
|
11
|
+
console.error("[Directory MCP] Shutting down...");
|
|
12
|
+
await server.stop();
|
|
13
|
+
process.exit(0);
|
|
14
|
+
});
|
|
15
|
+
process.on("SIGTERM", async () => {
|
|
16
|
+
console.error("[Directory MCP] Shutting down...");
|
|
17
|
+
await server.stop();
|
|
18
|
+
process.exit(0);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
console.error("[Directory MCP] Fatal error:", error instanceof Error ? error.message : String(error));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
main();
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAC5B,cAAc,CAAC,MAAM,CAAC,CAAC;QAEvB,MAAM,MAAM,GAAG,IAAI,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAC9C,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QAErB,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;YAC9B,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;YAClD,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;YAC/B,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;YAClD,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CACX,8BAA8B,EAC9B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACvD,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Registry for Directory MCP Server
|
|
3
|
+
* Guided workflows for music discovery, sync licensing, and rights research
|
|
4
|
+
*/
|
|
5
|
+
export interface PromptDefinition {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
arguments?: Array<{
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
required?: boolean;
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
export interface PromptMessage {
|
|
15
|
+
role: "user" | "assistant";
|
|
16
|
+
content: {
|
|
17
|
+
type: string;
|
|
18
|
+
text: string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export interface PromptResult {
|
|
22
|
+
messages: PromptMessage[];
|
|
23
|
+
[key: string]: unknown;
|
|
24
|
+
}
|
|
25
|
+
export declare class PromptRegistry {
|
|
26
|
+
listPrompts(): PromptDefinition[];
|
|
27
|
+
getPrompt(name: string, args?: Record<string, any>): Promise<PromptResult>;
|
|
28
|
+
private getFindMusicPrompt;
|
|
29
|
+
private getResearchCreatorPrompt;
|
|
30
|
+
private getDirectoryAutopilotPrompt;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAAA;;;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"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Registry for Directory MCP Server
|
|
3
|
+
* Guided workflows for music discovery, sync licensing, and rights research
|
|
4
|
+
*/
|
|
5
|
+
export class PromptRegistry {
|
|
6
|
+
listPrompts() {
|
|
7
|
+
return [
|
|
8
|
+
{
|
|
9
|
+
name: "find-music",
|
|
10
|
+
description: "Find music for a sync brief, playlist, or project — search by mood, BPM, key, energy, or description",
|
|
11
|
+
arguments: [
|
|
12
|
+
{
|
|
13
|
+
name: "brief",
|
|
14
|
+
description: "What you're looking for — a mood, scene description, or audio characteristics",
|
|
15
|
+
required: false,
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: "research-creator",
|
|
21
|
+
description: "Research a songwriter, composer, or performer — see their works, identifiers, collaborators, and verification status",
|
|
22
|
+
arguments: [
|
|
23
|
+
{
|
|
24
|
+
name: "name_or_id",
|
|
25
|
+
description: "Creator name, IPI number, ISNI, or MusicBrainz ID",
|
|
26
|
+
required: false,
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "directory-autopilot",
|
|
32
|
+
description: "Not sure where to start? Describe what you need and get routed to the right workflow — sync search, rights research, or identifier lookup",
|
|
33
|
+
arguments: [],
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
async getPrompt(name, args) {
|
|
38
|
+
switch (name) {
|
|
39
|
+
case "find-music":
|
|
40
|
+
return this.getFindMusicPrompt(args?.brief);
|
|
41
|
+
case "research-creator":
|
|
42
|
+
return this.getResearchCreatorPrompt(args?.name_or_id);
|
|
43
|
+
case "directory-autopilot":
|
|
44
|
+
return this.getDirectoryAutopilotPrompt();
|
|
45
|
+
default:
|
|
46
|
+
throw new Error(`Prompt not found: ${name}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
getFindMusicPrompt(brief) {
|
|
50
|
+
const briefInstruction = brief
|
|
51
|
+
? `The user is looking for: "${brief}". Translate this into audio search parameters.`
|
|
52
|
+
: `Ask me what I'm looking for — a mood, a scene, a vibe, or specific audio characteristics (BPM, key, energy).`;
|
|
53
|
+
return {
|
|
54
|
+
messages: [
|
|
55
|
+
{
|
|
56
|
+
role: "user",
|
|
57
|
+
content: {
|
|
58
|
+
type: "text",
|
|
59
|
+
text: `Help me find music in the PICA public directory for a sync brief or project.
|
|
60
|
+
|
|
61
|
+
${briefInstruction}
|
|
62
|
+
|
|
63
|
+
Workflow:
|
|
64
|
+
1. Translate the brief into search parameters for directory_search_recordings:
|
|
65
|
+
- Mood descriptions → energy, danceability, key_mode, mood filters
|
|
66
|
+
- "Upbeat" → min_energy: 0.6, min_danceability: 0.5
|
|
67
|
+
- "Dark/moody" → max_energy: 0.4, key_mode: minor
|
|
68
|
+
- "Chill" → max_energy: 0.4, max_bpm: 100
|
|
69
|
+
- Specific requests → use BPM, key, duration filters directly
|
|
70
|
+
|
|
71
|
+
2. Run directory_search_recordings with the parameters.
|
|
72
|
+
|
|
73
|
+
3. For each promising result, use directory_lookup_work_full to get:
|
|
74
|
+
- Who wrote it (credits with IPI numbers)
|
|
75
|
+
- Whether credits are attested (verified ownership)
|
|
76
|
+
- DSP links (Spotify, Apple Music — so the user can listen)
|
|
77
|
+
- Registration score (higher = cleaner rights chain)
|
|
78
|
+
|
|
79
|
+
4. Present results as a shortlist with:
|
|
80
|
+
- Title, artist, BPM, key, energy
|
|
81
|
+
- Credits summary (who to contact for licensing)
|
|
82
|
+
- Any flags (unattested credits, low registration score, missing ISRC)
|
|
83
|
+
|
|
84
|
+
If no results match, suggest broadening the search (wider BPM range, drop key filter, etc.).
|
|
85
|
+
|
|
86
|
+
Important: This is a public directory — only works from organisations that opted in are visible. If the catalog is small, say so.`,
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
getResearchCreatorPrompt(nameOrId) {
|
|
93
|
+
const searchInstruction = nameOrId
|
|
94
|
+
? `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.`
|
|
95
|
+
: `Ask me for the creator's name, IPI number, ISNI, or MusicBrainz ID.`;
|
|
96
|
+
return {
|
|
97
|
+
messages: [
|
|
98
|
+
{
|
|
99
|
+
role: "user",
|
|
100
|
+
content: {
|
|
101
|
+
type: "text",
|
|
102
|
+
text: `Help me research a music creator in the PICA public directory.
|
|
103
|
+
|
|
104
|
+
${searchInstruction}
|
|
105
|
+
|
|
106
|
+
Once you find the person, use directory_lookup_person_full to get their complete profile:
|
|
107
|
+
- Identifiers (IPI, ISNI, MusicBrainz) — essential for rights verification
|
|
108
|
+
- All credited works with roles (writer, composer, performer, producer)
|
|
109
|
+
- Collaborator network — who they work with
|
|
110
|
+
- Verification score — how complete their profile is
|
|
111
|
+
|
|
112
|
+
Then for their most notable works (up to 5), use directory_lookup_work_full to get:
|
|
113
|
+
- Full credits and splits (are they the sole writer or one of many?)
|
|
114
|
+
- Recordings with ISRCs
|
|
115
|
+
- Audio analysis (BPM, key, energy)
|
|
116
|
+
- DSP links and registration status
|
|
117
|
+
|
|
118
|
+
Present a summary:
|
|
119
|
+
- Creator profile (name, identifiers, role patterns)
|
|
120
|
+
- Catalog overview (how many works, typical roles, common collaborators)
|
|
121
|
+
- Notable works with credit details
|
|
122
|
+
- Any gaps (missing identifiers, unattested credits, low scores)
|
|
123
|
+
|
|
124
|
+
This is useful for: rights research, due diligence before licensing, publisher evaluation, or understanding a catalog before acquisition.`,
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
getDirectoryAutopilotPrompt() {
|
|
131
|
+
return {
|
|
132
|
+
messages: [
|
|
133
|
+
{
|
|
134
|
+
role: "user",
|
|
135
|
+
content: {
|
|
136
|
+
type: "text",
|
|
137
|
+
text: `You've connected to the PICA public music directory. Help me find what I need.
|
|
138
|
+
|
|
139
|
+
First, read the llms://primer resource to understand what's available.
|
|
140
|
+
|
|
141
|
+
Then ask me what I'm looking for. Based on my answer, route to the right workflow:
|
|
142
|
+
|
|
143
|
+
If I'm looking for MUSIC FOR A PROJECT (sync brief, playlist, mood search):
|
|
144
|
+
→ 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.
|
|
145
|
+
|
|
146
|
+
If I'm looking for INFORMATION ABOUT A CREATOR (songwriter, composer, performer):
|
|
147
|
+
→ Use the research-creator workflow. Look up their profile, works, identifiers, and collaborators.
|
|
148
|
+
|
|
149
|
+
If I have a SPECIFIC IDENTIFIER to resolve (ISRC, ISWC, IPI, ISNI):
|
|
150
|
+
→ Route directly to the right lookup tool:
|
|
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
|
+
|
|
156
|
+
If I want to BROWSE what's in the directory:
|
|
157
|
+
→ Use directory_search with a broad query, or directory_list_works / directory_list_people to paginate.
|
|
158
|
+
|
|
159
|
+
Tell me which workflow you chose and why, in one sentence. Offer alternatives.
|
|
160
|
+
|
|
161
|
+
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.`,
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAyBH,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,iKAAiK;YACxL,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,2 @@
|
|
|
1
|
+
export declare const DIRECTORY_PRIMER = "# PICA Directory \u2014 Public Music Catalog Search\n\nRead-only access to published music catalog data. No authentication required.\nWorks and people are only visible if the owning organisation has opted into\nthe directory.\n\n## First Connection\n\nIf you're not sure where to start, invoke the **directory-autopilot** prompt.\nIt asks what you need and routes to the right workflow: sync search, rights\nresearch, or identifier lookup.\n\n## What You Can Do\n- Search works by title, ISWC, publisher, label\n- Search people by name, ISNI, IPI\n- Look up works by recording ISRC (directory_lookup_isrc)\n- Search recordings by audio characteristics (BPM, key, mood, energy)\n\n## What You Cannot Do\n- Create, update, or delete anything (read-only)\n- Access unpublished works or private catalog data\n- See financial data, agreements, or internal metadata\n\n## Entity Model\n- **Work**: composition with title, ISWC, credits, recordings\n- **Person**: writer/composer/performer with IPI, ISNI identifiers\n- **Recording**: audio capture with ISRC, linked to one work\n\n## Recommended Flow\n1. directory_search (broad text search across works + people)\n2. directory_lookup_work or directory_lookup_person (detailed view)\n3. directory_search_recordings (audio characteristic search for sync)\n";
|
|
2
|
+
//# sourceMappingURL=llms-primer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llms-primer.d.ts","sourceRoot":"","sources":["../../src/resources/llms-primer.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,wxCAgC5B,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const DIRECTORY_PRIMER = `# PICA Directory — Public Music Catalog Search
|
|
2
|
+
|
|
3
|
+
Read-only access to published music catalog data. No authentication required.
|
|
4
|
+
Works and people are only visible if the owning organisation has opted into
|
|
5
|
+
the directory.
|
|
6
|
+
|
|
7
|
+
## First Connection
|
|
8
|
+
|
|
9
|
+
If you're not sure where to start, invoke the **directory-autopilot** prompt.
|
|
10
|
+
It asks what you need and routes to the right workflow: sync search, rights
|
|
11
|
+
research, or identifier lookup.
|
|
12
|
+
|
|
13
|
+
## What You Can Do
|
|
14
|
+
- Search works by title, ISWC, publisher, label
|
|
15
|
+
- Search people by name, ISNI, IPI
|
|
16
|
+
- Look up works by recording ISRC (directory_lookup_isrc)
|
|
17
|
+
- Search recordings by audio characteristics (BPM, key, mood, energy)
|
|
18
|
+
|
|
19
|
+
## What You Cannot Do
|
|
20
|
+
- Create, update, or delete anything (read-only)
|
|
21
|
+
- Access unpublished works or private catalog data
|
|
22
|
+
- See financial data, agreements, or internal metadata
|
|
23
|
+
|
|
24
|
+
## Entity Model
|
|
25
|
+
- **Work**: composition with title, ISWC, credits, recordings
|
|
26
|
+
- **Person**: writer/composer/performer with IPI, ISNI identifiers
|
|
27
|
+
- **Recording**: audio capture with ISRC, linked to one work
|
|
28
|
+
|
|
29
|
+
## Recommended Flow
|
|
30
|
+
1. directory_search (broad text search across works + people)
|
|
31
|
+
2. directory_lookup_work or directory_lookup_person (detailed view)
|
|
32
|
+
3. directory_search_recordings (audio characteristic search for sync)
|
|
33
|
+
`;
|
|
34
|
+
//# sourceMappingURL=llms-primer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llms-primer.js","sourceRoot":"","sources":["../../src/resources/llms-primer.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgC/B,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ServerConfig } from "./config.js";
|
|
2
|
+
export declare class DirectoryMcpServer {
|
|
3
|
+
private server;
|
|
4
|
+
private client;
|
|
5
|
+
private toolRegistry;
|
|
6
|
+
private promptRegistry;
|
|
7
|
+
private config;
|
|
8
|
+
constructor(config: ServerConfig);
|
|
9
|
+
private setupHandlers;
|
|
10
|
+
start(): Promise<void>;
|
|
11
|
+
stop(): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAM3C,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,MAAM,CAAe;gBAEjB,MAAM,EAAE,YAAY;IA2BhC,OAAO,CAAC,aAAa;IAkEf,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAUtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAI5B"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import { DirectoryClient } from "./client.js";
|
|
5
|
+
import { ToolRegistry } from "./tools/index.js";
|
|
6
|
+
import { PromptRegistry } from "./prompts/index.js";
|
|
7
|
+
import { logError } from "./utils/errors.js";
|
|
8
|
+
import { DIRECTORY_PRIMER } from "./resources/llms-primer.js";
|
|
9
|
+
export class DirectoryMcpServer {
|
|
10
|
+
server;
|
|
11
|
+
client;
|
|
12
|
+
toolRegistry;
|
|
13
|
+
promptRegistry;
|
|
14
|
+
config;
|
|
15
|
+
constructor(config) {
|
|
16
|
+
this.config = config;
|
|
17
|
+
this.client = new DirectoryClient({
|
|
18
|
+
baseUrl: config.directoryUrl,
|
|
19
|
+
debug: config.debug,
|
|
20
|
+
});
|
|
21
|
+
this.server = new Server({
|
|
22
|
+
name: config.serverName,
|
|
23
|
+
version: config.version,
|
|
24
|
+
}, {
|
|
25
|
+
capabilities: {
|
|
26
|
+
tools: {},
|
|
27
|
+
resources: {},
|
|
28
|
+
prompts: {},
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
this.toolRegistry = new ToolRegistry(this.client);
|
|
32
|
+
this.promptRegistry = new PromptRegistry();
|
|
33
|
+
this.setupHandlers();
|
|
34
|
+
}
|
|
35
|
+
setupHandlers() {
|
|
36
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
37
|
+
if (this.config.debug) {
|
|
38
|
+
console.error("[Directory MCP] Listing tools");
|
|
39
|
+
}
|
|
40
|
+
return { tools: this.toolRegistry.listTools() };
|
|
41
|
+
});
|
|
42
|
+
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
43
|
+
return {
|
|
44
|
+
resources: [
|
|
45
|
+
{
|
|
46
|
+
uri: "llms://primer",
|
|
47
|
+
name: "PICA Domain Primer",
|
|
48
|
+
description: "Plain-language description of PICA's domain model, entity relationships, and recommended agent workflows. Read this first.",
|
|
49
|
+
mimeType: "text/markdown",
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
55
|
+
const { uri } = request.params;
|
|
56
|
+
if (uri === "llms://primer") {
|
|
57
|
+
return {
|
|
58
|
+
contents: [
|
|
59
|
+
{
|
|
60
|
+
uri: "llms://primer",
|
|
61
|
+
mimeType: "text/markdown",
|
|
62
|
+
text: DIRECTORY_PRIMER,
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
throw new Error(`Resource not found: ${uri}`);
|
|
68
|
+
});
|
|
69
|
+
this.server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
70
|
+
return { prompts: this.promptRegistry.listPrompts() };
|
|
71
|
+
});
|
|
72
|
+
this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
73
|
+
const { name, arguments: args } = request.params;
|
|
74
|
+
return await this.promptRegistry.getPrompt(name, args);
|
|
75
|
+
});
|
|
76
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
77
|
+
const { name, arguments: args } = request.params;
|
|
78
|
+
if (this.config.debug) {
|
|
79
|
+
console.error(`[Directory MCP] Executing tool: ${name}`, args);
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
return await this.toolRegistry.executeTool(name, args || {});
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
logError(`Tool execution: ${name}`, error);
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
async start() {
|
|
91
|
+
const transport = new StdioServerTransport();
|
|
92
|
+
await this.server.connect(transport);
|
|
93
|
+
console.error("[Directory MCP] PICA Directory MCP Server started");
|
|
94
|
+
console.error(`[Directory MCP] Version: ${this.config.version}`);
|
|
95
|
+
console.error(`[Directory MCP] API URL: ${this.config.directoryUrl}`);
|
|
96
|
+
console.error("[Directory MCP] Ready to accept connections");
|
|
97
|
+
}
|
|
98
|
+
async stop() {
|
|
99
|
+
await this.server.close();
|
|
100
|
+
console.error("[Directory MCP] Server stopped");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { DirectoryClient } from "../client.js";
|
|
2
|
+
export interface ToolDefinition {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: string;
|
|
7
|
+
properties: Record<string, any>;
|
|
8
|
+
required?: string[];
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export interface ToolResult {
|
|
12
|
+
content: Array<{
|
|
13
|
+
type: string;
|
|
14
|
+
text: string;
|
|
15
|
+
}>;
|
|
16
|
+
structuredContent?: Record<string, unknown>;
|
|
17
|
+
isError?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export type ToolExecutor = (args: Record<string, any>) => Promise<any>;
|
|
20
|
+
export declare class ToolRegistry {
|
|
21
|
+
private tools;
|
|
22
|
+
constructor(client: DirectoryClient);
|
|
23
|
+
listTools(): ToolDefinition[];
|
|
24
|
+
executeTool(name: string, args: Record<string, any>): Promise<any>;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAO/C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAChC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;AAEvE,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAGX;gBAEU,MAAM,EAAE,eAAe;IAiBnC,SAAS,IAAI,cAAc,EAAE;IAIvB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;CAgBzE"}
|