@withpica/mcp-server-directory 1.3.0 → 1.4.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/CHANGELOG.md +28 -0
- package/dist/client.d.ts +12 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +93 -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 +15 -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 +28 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/changelog.d.ts +16 -0
- package/dist/lib/changelog.d.ts.map +1 -0
- package/dist/lib/changelog.generated.d.ts +4 -0
- package/dist/lib/changelog.generated.d.ts.map +1 -0
- package/dist/lib/changelog.generated.js +6 -0
- package/dist/lib/changelog.generated.js.map +1 -0
- package/dist/lib/changelog.js +84 -0
- package/dist/lib/changelog.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 +165 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/public-question-atlas.d.ts +121 -0
- package/dist/prompts/public-question-atlas.d.ts.map +1 -0
- package/dist/prompts/public-question-atlas.js +434 -0
- package/dist/prompts/public-question-atlas.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 +35 -0
- package/dist/resources/llms-primer.js.map +1 -0
- package/dist/server.d.ts +33 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +223 -0
- package/dist/server.js.map +1 -0
- package/dist/skills/index.d.ts +32 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +50 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/skills.generated.d.ts +18 -0
- package/dist/skills/skills.generated.d.ts.map +1 -0
- package/dist/skills/skills.generated.js +14 -0
- package/dist/skills/skills.generated.js.map +1 -0
- package/dist/tools/__tests__/release-notes.test.d.ts +2 -0
- package/dist/tools/__tests__/release-notes.test.d.ts.map +1 -0
- package/dist/tools/__tests__/release-notes.test.js +49 -0
- package/dist/tools/__tests__/release-notes.test.js.map +1 -0
- package/dist/tools/chain.d.ts +12 -0
- package/dist/tools/chain.d.ts.map +1 -0
- package/dist/tools/chain.js +109 -0
- package/dist/tools/chain.js.map +1 -0
- package/dist/tools/index.d.ts +36 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +49 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/people.d.ts +13 -0
- package/dist/tools/people.d.ts.map +1 -0
- package/dist/tools/people.js +177 -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 +145 -0
- package/dist/tools/recordings.js.map +1 -0
- package/dist/tools/release-notes.d.ts +22 -0
- package/dist/tools/release-notes.d.ts.map +1 -0
- package/dist/tools/release-notes.js +102 -0
- package/dist/tools/release-notes.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 +56 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/skills.d.ts +19 -0
- package/dist/tools/skills.d.ts.map +1 -0
- package/dist/tools/skills.js +127 -0
- package/dist/tools/skills.js.map +1 -0
- package/dist/tools/works.d.ts +14 -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 +48 -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 +16 -0
- package/dist/utils/formatting.js.map +1 -0
- package/package.json +4 -3
- package/scripts/build-changelog.ts +25 -0
- package/src/lib/changelog.ts +119 -0
- package/src/prompts/public-question-atlas.ts +19 -10
- package/src/server.ts +19 -0
- package/src/tools/__tests__/release-notes.test.ts +62 -0
- package/src/tools/index.ts +2 -0
- package/src/tools/release-notes.ts +148 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
// Copyright (c) 2024-2026 Withpica Ltd. All rights reserved.
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { DirectoryClient } from "./client.js";
|
|
6
|
+
import { ToolRegistry } from "./tools/index.js";
|
|
7
|
+
import { PromptRegistry } from "./prompts/index.js";
|
|
8
|
+
import { logError } from "./utils/errors.js";
|
|
9
|
+
import { DIRECTORY_PRIMER } from "./resources/llms-primer.js";
|
|
10
|
+
import { CHANGELOG_MD } from "./lib/changelog.generated.js";
|
|
11
|
+
import { SkillsRegistry } from "./skills/index.js";
|
|
12
|
+
export class DirectoryMcpServer {
|
|
13
|
+
server;
|
|
14
|
+
client;
|
|
15
|
+
toolRegistry;
|
|
16
|
+
promptRegistry;
|
|
17
|
+
skillsRegistry;
|
|
18
|
+
config;
|
|
19
|
+
// Logged once after the MCP `initialize` handshake completes so each
|
|
20
|
+
// session prints a single client-attribution breadcrumb to stderr
|
|
21
|
+
// (Railway logs / Sentry breadcrumbs). Directory MCP has no DB audit
|
|
22
|
+
// pipeline today; this is provenance-only.
|
|
23
|
+
clientAttributionLogged = false;
|
|
24
|
+
constructor(config) {
|
|
25
|
+
this.config = config;
|
|
26
|
+
this.client = new DirectoryClient({
|
|
27
|
+
baseUrl: config.directoryUrl,
|
|
28
|
+
debug: config.debug,
|
|
29
|
+
});
|
|
30
|
+
this.server = new Server({
|
|
31
|
+
name: config.serverName,
|
|
32
|
+
version: config.version,
|
|
33
|
+
}, {
|
|
34
|
+
capabilities: {
|
|
35
|
+
tools: {},
|
|
36
|
+
resources: {},
|
|
37
|
+
prompts: {},
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
this.toolRegistry = new ToolRegistry(this.client);
|
|
41
|
+
this.promptRegistry = new PromptRegistry();
|
|
42
|
+
this.skillsRegistry = new SkillsRegistry();
|
|
43
|
+
this.setupHandlers();
|
|
44
|
+
}
|
|
45
|
+
setupHandlers() {
|
|
46
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
47
|
+
if (this.config.debug) {
|
|
48
|
+
console.error("[Directory MCP] Listing tools");
|
|
49
|
+
}
|
|
50
|
+
return { tools: this.toolRegistry.listTools() };
|
|
51
|
+
});
|
|
52
|
+
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
53
|
+
const resources = [
|
|
54
|
+
{
|
|
55
|
+
uri: "llms://primer",
|
|
56
|
+
name: "PICA Domain Primer",
|
|
57
|
+
description: "Plain-language description of PICA's domain model, entity relationships, and recommended agent workflows. Read this first.",
|
|
58
|
+
mimeType: "text/markdown",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
uri: "skill://withpica/index.json",
|
|
62
|
+
name: "PICA Directory Skills Index",
|
|
63
|
+
description: "Enumeration of downloadable directory skill methodologies (SEP-2640 bridge). Each entry maps a kebab-case name to its skill:// URI, description, and trigger phrases.",
|
|
64
|
+
mimeType: "application/json",
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
uri: "release-notes://withpica/mcp-server-directory/latest",
|
|
68
|
+
name: "Release Notes — @withpica/mcp-server-directory",
|
|
69
|
+
description: "Full CHANGELOG.md for the PICA directory MCP server. For just the last few releases, agents can call directory_release_notes.",
|
|
70
|
+
mimeType: "text/markdown",
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
for (const summary of this.skillsRegistry.listSkills()) {
|
|
74
|
+
resources.push({
|
|
75
|
+
uri: `skill://withpica/${summary.name}/SKILL.md`,
|
|
76
|
+
name: `Skill — ${summary.name}`,
|
|
77
|
+
description: summary.description,
|
|
78
|
+
mimeType: "text/markdown",
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return { resources };
|
|
82
|
+
});
|
|
83
|
+
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
84
|
+
const { uri } = request.params;
|
|
85
|
+
if (uri === "llms://primer") {
|
|
86
|
+
return {
|
|
87
|
+
contents: [
|
|
88
|
+
{
|
|
89
|
+
uri: "llms://primer",
|
|
90
|
+
mimeType: "text/markdown",
|
|
91
|
+
text: DIRECTORY_PRIMER,
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (uri === "release-notes://withpica/mcp-server-directory/latest") {
|
|
97
|
+
return {
|
|
98
|
+
contents: [
|
|
99
|
+
{
|
|
100
|
+
uri,
|
|
101
|
+
mimeType: "text/markdown",
|
|
102
|
+
text: CHANGELOG_MD,
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
if (uri.startsWith("skill://withpica/")) {
|
|
108
|
+
return this.readSkillResource(uri);
|
|
109
|
+
}
|
|
110
|
+
throw new Error(`Resource not found: ${uri}`);
|
|
111
|
+
});
|
|
112
|
+
this.server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
113
|
+
return { prompts: this.promptRegistry.listPrompts() };
|
|
114
|
+
});
|
|
115
|
+
this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
116
|
+
const { name, arguments: args } = request.params;
|
|
117
|
+
return await this.promptRegistry.getPrompt(name, args);
|
|
118
|
+
});
|
|
119
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
120
|
+
const { name, arguments: args } = request.params;
|
|
121
|
+
this.logClientAttributionOnce();
|
|
122
|
+
if (this.config.debug) {
|
|
123
|
+
console.error(`[Directory MCP] Executing tool: ${name}`, args);
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
return await this.toolRegistry.executeTool(name, args || {});
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
logError(`Tool execution: ${name}`, error);
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Emit a single stderr line per session naming the client that handshook
|
|
136
|
+
* with us — sourced from `clientInfo` on the MCP `initialize` request.
|
|
137
|
+
* Self-declared, NOT authenticated; treat as provenance metadata only.
|
|
138
|
+
*
|
|
139
|
+
* Directory MCP is unauthenticated and writes no audit rows, so this
|
|
140
|
+
* stderr breadcrumb is the only attribution surface today. When/if a
|
|
141
|
+
* directory audit pipeline lands, fold these values into McpAuditEntry
|
|
142
|
+
* (the wire shape already carries optional client_name + client_version).
|
|
143
|
+
*/
|
|
144
|
+
logClientAttributionOnce() {
|
|
145
|
+
if (this.clientAttributionLogged)
|
|
146
|
+
return;
|
|
147
|
+
const info = this.server.getClientVersion?.();
|
|
148
|
+
if (!info)
|
|
149
|
+
return;
|
|
150
|
+
this.clientAttributionLogged = true;
|
|
151
|
+
console.error(`[Directory MCP] client: ${info.name ?? "unknown"} v${info.version ?? "unknown"}`);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Resolve a skill:// URI. ADR-140 Phase 2b — SEP-2640 bridge pattern.
|
|
155
|
+
* Two URI shapes:
|
|
156
|
+
* - skill://withpica/index.json
|
|
157
|
+
* - skill://withpica/<name>/SKILL.md
|
|
158
|
+
*/
|
|
159
|
+
readSkillResource(uri) {
|
|
160
|
+
if (uri === "skill://withpica/index.json") {
|
|
161
|
+
const index = this.skillsRegistry.listSkills().map((s) => ({
|
|
162
|
+
name: s.name,
|
|
163
|
+
uri: `skill://withpica/${s.name}/SKILL.md`,
|
|
164
|
+
description: s.description,
|
|
165
|
+
triggers: s.triggers,
|
|
166
|
+
audience: s.audience,
|
|
167
|
+
}));
|
|
168
|
+
return {
|
|
169
|
+
contents: [
|
|
170
|
+
{
|
|
171
|
+
uri,
|
|
172
|
+
mimeType: "application/json",
|
|
173
|
+
text: JSON.stringify({ skills: index }, null, 2),
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const match = uri.match(/^skill:\/\/withpica\/([a-z0-9-]+)\/SKILL\.md$/);
|
|
179
|
+
if (!match) {
|
|
180
|
+
throw new Error(`Malformed skill URI: ${uri}`);
|
|
181
|
+
}
|
|
182
|
+
const name = match[1];
|
|
183
|
+
if (!this.skillsRegistry.has(name)) {
|
|
184
|
+
throw new Error(`Skill not found: ${name}`);
|
|
185
|
+
}
|
|
186
|
+
const skill = this.skillsRegistry.getSkill(name);
|
|
187
|
+
const frontmatter = [
|
|
188
|
+
"---",
|
|
189
|
+
`name: ${skill.name}`,
|
|
190
|
+
`description: ${skill.description}`,
|
|
191
|
+
"triggers:",
|
|
192
|
+
...skill.triggers.map((t) => ` - ${t}`),
|
|
193
|
+
`audience: ${skill.audience}`,
|
|
194
|
+
"tools_required:",
|
|
195
|
+
...skill.tools_required.map((t) => ` - ${t}`),
|
|
196
|
+
`output: ${skill.output}`,
|
|
197
|
+
"---",
|
|
198
|
+
"",
|
|
199
|
+
].join("\n");
|
|
200
|
+
return {
|
|
201
|
+
contents: [
|
|
202
|
+
{
|
|
203
|
+
uri,
|
|
204
|
+
mimeType: "text/markdown",
|
|
205
|
+
text: frontmatter + skill.body,
|
|
206
|
+
},
|
|
207
|
+
],
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
async start() {
|
|
211
|
+
const transport = new StdioServerTransport();
|
|
212
|
+
await this.server.connect(transport);
|
|
213
|
+
console.error("[Directory MCP] PICA Directory MCP Server started");
|
|
214
|
+
console.error(`[Directory MCP] Version: ${this.config.version}`);
|
|
215
|
+
console.error(`[Directory MCP] API URL: ${this.config.directoryUrl}`);
|
|
216
|
+
console.error("[Directory MCP] Ready to accept connections");
|
|
217
|
+
}
|
|
218
|
+
async stop() {
|
|
219
|
+
await this.server.close();
|
|
220
|
+
console.error("[Directory MCP] Server stopped");
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
//# 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,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills Registry — directory MCP, ADR-140 Phase 2b
|
|
3
|
+
*
|
|
4
|
+
* Sister of mcp-server/src/skills/index.ts. Same shape, scoped to the public
|
|
5
|
+
* directory MCP. Body bytes are generated at build time by
|
|
6
|
+
* `scripts/build-skills.ts` and inlined into `skills.generated.ts`.
|
|
7
|
+
*
|
|
8
|
+
* Public/anonymous surface — every skill body must clear the IP-protection
|
|
9
|
+
* lint (scripts/lint-mcp-tools.ts Rule 14) before publishing. Directory MCP
|
|
10
|
+
* skills MUST NOT quote from trade-secret directories listed in
|
|
11
|
+
* `.claude/rules/ip-protection.md`.
|
|
12
|
+
*/
|
|
13
|
+
import { SKILLS, SKILL_NAMES, type Skill } from "./skills.generated.js";
|
|
14
|
+
export interface SkillSummary {
|
|
15
|
+
name: string;
|
|
16
|
+
description: string;
|
|
17
|
+
triggers: string[];
|
|
18
|
+
audience: string;
|
|
19
|
+
}
|
|
20
|
+
export declare class SkillsRegistry {
|
|
21
|
+
listNames(): ReadonlyArray<string>;
|
|
22
|
+
listSkills(): SkillSummary[];
|
|
23
|
+
getSkill(name: string): Skill;
|
|
24
|
+
has(name: string): boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare class SkillNotFoundError extends Error {
|
|
27
|
+
readonly skillName: string;
|
|
28
|
+
constructor(skillName: string);
|
|
29
|
+
}
|
|
30
|
+
export { SKILLS, SKILL_NAMES };
|
|
31
|
+
export type { Skill };
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/skills/index.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAExE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,cAAc;IACzB,SAAS,IAAI,aAAa,CAAC,MAAM,CAAC;IAIlC,UAAU,IAAI,YAAY,EAAE;IAY5B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK;IAQ7B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAG3B;AAED,qBAAa,kBAAmB,SAAQ,KAAK;aACf,SAAS,EAAE,MAAM;gBAAjB,SAAS,EAAE,MAAM;CAI9C;AAED,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AAC/B,YAAY,EAAE,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Copyright (c) 2024-2026 Withpica Ltd. All rights reserved.
|
|
2
|
+
/**
|
|
3
|
+
* Skills Registry — directory MCP, ADR-140 Phase 2b
|
|
4
|
+
*
|
|
5
|
+
* Sister of mcp-server/src/skills/index.ts. Same shape, scoped to the public
|
|
6
|
+
* directory MCP. Body bytes are generated at build time by
|
|
7
|
+
* `scripts/build-skills.ts` and inlined into `skills.generated.ts`.
|
|
8
|
+
*
|
|
9
|
+
* Public/anonymous surface — every skill body must clear the IP-protection
|
|
10
|
+
* lint (scripts/lint-mcp-tools.ts Rule 14) before publishing. Directory MCP
|
|
11
|
+
* skills MUST NOT quote from trade-secret directories listed in
|
|
12
|
+
* `.claude/rules/ip-protection.md`.
|
|
13
|
+
*/
|
|
14
|
+
import { SKILLS, SKILL_NAMES } from "./skills.generated.js";
|
|
15
|
+
export class SkillsRegistry {
|
|
16
|
+
listNames() {
|
|
17
|
+
return SKILL_NAMES;
|
|
18
|
+
}
|
|
19
|
+
listSkills() {
|
|
20
|
+
return SKILL_NAMES.map((name) => {
|
|
21
|
+
const skill = SKILLS[name];
|
|
22
|
+
return {
|
|
23
|
+
name: skill.name,
|
|
24
|
+
description: skill.description,
|
|
25
|
+
triggers: skill.triggers,
|
|
26
|
+
audience: skill.audience,
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
getSkill(name) {
|
|
31
|
+
const skill = SKILLS[name];
|
|
32
|
+
if (!skill) {
|
|
33
|
+
throw new SkillNotFoundError(name);
|
|
34
|
+
}
|
|
35
|
+
return skill;
|
|
36
|
+
}
|
|
37
|
+
has(name) {
|
|
38
|
+
return name in SKILLS;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export class SkillNotFoundError extends Error {
|
|
42
|
+
skillName;
|
|
43
|
+
constructor(skillName) {
|
|
44
|
+
super(`Skill not found: ${skillName}`);
|
|
45
|
+
this.skillName = skillName;
|
|
46
|
+
this.name = "SkillNotFoundError";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export { SKILLS, SKILL_NAMES };
|
|
50
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/skills/index.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,MAAM,EAAE,WAAW,EAAc,MAAM,uBAAuB,CAAC;AASxE,MAAM,OAAO,cAAc;IACzB,SAAS;QACP,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,UAAU;QACR,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;YAC3B,OAAO;gBACL,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;aACzB,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED,QAAQ,CAAC,IAAY;QACnB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,IAAI,MAAM,CAAC;IACxB,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IACf;IAA5B,YAA4B,SAAiB;QAC3C,KAAK,CAAC,oBAAoB,SAAS,EAAE,CAAC,CAAC;QADb,cAAS,GAAT,SAAS,CAAQ;QAE3C,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAED,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GENERATED FILE — DO NOT EDIT BY HAND.
|
|
3
|
+
*
|
|
4
|
+
* Regenerated by `scripts/build-skills.ts` from `src/skills/<name>/SKILL.md`.
|
|
5
|
+
* Runs in `prebuild`. See ADR-140 Phase 2b.
|
|
6
|
+
*/
|
|
7
|
+
export interface Skill {
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
triggers: string[];
|
|
11
|
+
audience: string;
|
|
12
|
+
tools_required: string[];
|
|
13
|
+
output: string;
|
|
14
|
+
body: string;
|
|
15
|
+
}
|
|
16
|
+
export declare const SKILLS: Record<string, Skill>;
|
|
17
|
+
export declare const SKILL_NAMES: ReadonlyArray<string>;
|
|
18
|
+
//# sourceMappingURL=skills.generated.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.generated.d.ts","sourceRoot":"","sources":["../../src/skills/skills.generated.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAUxC,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC,MAAM,CAAiC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Copyright (c) 2024-2026 Withpica Ltd. All rights reserved.
|
|
2
|
+
export const SKILLS = {
|
|
3
|
+
"find-music-for-sync-brief": {
|
|
4
|
+
name: "find-music-for-sync-brief",
|
|
5
|
+
description: "Find music in the PICA public directory for a sync brief — translate a mood/vibe/scene description into audio search parameters, run the search, and return a rights-aware shortlist with credit details for licensing.",
|
|
6
|
+
triggers: ["find music for a sync brief", "find me a track for a film scene", "music for this brief", "find an uplifting indie folk track", "I need music that sounds like"],
|
|
7
|
+
audience: "sync supervisor / music library / ad agency / film & TV music team",
|
|
8
|
+
tools_required: ["directory_search_recordings", "directory_lookup_work", "directory_lookup_person"],
|
|
9
|
+
output: "A rights-aware shortlist — each result with title, artist, audio characteristics (BPM, key, energy), credits summary for licensing contact, and any flags (unattested credits, low registration score, missing ISRC).",
|
|
10
|
+
body: "# find-music-for-sync-brief\n\nHelp the user find music in PICA's public directory for a sync brief. Translate their description (mood, vibe, scene, era, vocal style) into search parameters, run the search, and return a shortlist that includes the information they need to license — not just the track.\n\nThis is a public skill — any AI agent connected to the directory MCP can use it. The directory only contains works from organisations that have opted in.\n\n## Step 1 — Translate the brief\n\nMost sync briefs are described in natural language. Translate before searching:\n\n| User says | Search parameters |\n|---|---|\n| upbeat / uplifting / driving | `min_energy: 0.6`, `min_danceability: 0.5` |\n| dark / moody / brooding | `max_energy: 0.4`, `key_mode: minor` |\n| chill / ambient / background | `max_energy: 0.4`, `max_bpm: 100` |\n| epic / cinematic | `min_energy: 0.7`, often longer durations |\n| specific BPM (\"around 120bpm\") | `min_bpm: 115`, `max_bpm: 125` |\n| acoustic / sparse | typically lower `danceability` and `energy` |\n| vocal / instrumental | filter on `has_vocals` if available |\n\nIf the user gives an artist or song reference (\"something like X\"), look up that reference first via `directory_lookup_work` or `directory_search_recordings` by title — then mimic its audio profile in the new search.\n\n## Step 2 — Search\n\nCall `directory_search_recordings` with the parameters from step 1. Default limit is fine for an initial scan.\n\nIf the brief is vague, do two searches with slightly different parameters and compare. If too many results, narrow on BPM or key. If too few, widen the BPM range first, then drop key_mode.\n\n## Step 3 — Lookup full details\n\nFor the top 5-10 promising results, call `directory_lookup_work` to get:\n\n- **Who wrote it** — credits with IPI numbers (essential for the licensing contact path)\n- **Whether credits are attested** — an unattested credit means the ownership claim hasn't been verified; flag this\n- **DSP links** (Spotify, Apple Music) — the user wants to listen before shortlisting\n- **Registration score** — higher score = cleaner rights chain = easier to license\n\nFor high-value matches where the user wants to know more about the creator, call `directory_lookup_person` with the IPI to see the writer's broader catalog and collaborator network.\n\n## Step 4 — Present the shortlist\n\nPresent each shortlisted track with:\n\n- **Title, artist** — what the user listens for\n- **Audio profile** — BPM, key, energy (one line, the supervisor's quick filter)\n- **Credits summary** — writers with IPI, publisher if known (this is the licensing path)\n- **DSP links** — so the user can listen\n- **Flags** — unattested credits, low registration score, missing ISRC, multiple writers (= multi-party clearance needed)\n\nIf a track has all green flags (attested credits, high registration score, ISRC present, single or low-count writers), call it out as \"clean to clear.\"\n\n## Step 5 — If no results\n\nIf the search returns nothing, walk the user back through the brief:\n- Widen the BPM range first (most supervisors don't actually mind ±10 BPM)\n- Drop the key filter (key matching matters less than mood for most placements)\n- Drop the energy bounds and search by genre/mood text only\n- Suggest the user expand to adjacent moods (\"uplifting\" → also try \"warm\" or \"hopeful\")\n\nBe honest if the directory is small for a specific style — PICA's directory grows with org opt-ins; some niches are sparse.\n\n## What not to do\n\n- Don't claim to license tracks — this skill returns a shortlist, not a license. The user contacts the rights holder via the credits summary.\n- Don't speculate about pricing — sync fees are negotiated per-placement\n- Don't return results from outside the directory (no general web search, no Spotify metadata directly) — the directory is the source of truth for this skill\n- Don't return tracks with no attested credits without flagging them as \"rights chain unverified\"\n\n## Follow-on skills\n\n- `due-diligence-on-creator` (Stage 2 candidate) — for deeper research on a specific writer before reaching out\n",
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
export const SKILL_NAMES = ["find-music-for-sync-brief"];
|
|
14
|
+
//# sourceMappingURL=skills.generated.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.generated.js","sourceRoot":"","sources":["../../src/skills/skills.generated.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAoB7D,MAAM,CAAC,MAAM,MAAM,GAA0B;IAC3C,2BAA2B,EAAE;QAC3B,IAAI,EAAE,2BAA2B;QACjC,WAAW,EAAE,yNAAyN;QACtO,QAAQ,EAAE,CAAC,6BAA6B,EAAC,kCAAkC,EAAC,sBAAsB,EAAC,oCAAoC,EAAC,+BAA+B,CAAC;QACxK,QAAQ,EAAE,oEAAoE;QAC9E,cAAc,EAAE,CAAC,6BAA6B,EAAC,uBAAuB,EAAC,yBAAyB,CAAC;QACjG,MAAM,EAAE,uNAAuN;QAC/N,IAAI,EAAE,ijIAAijI;KACxjI;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAA0B,CAAC,2BAA2B,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release-notes.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/release-notes.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Copyright (c) 2024-2026 Withpica Ltd. All rights reserved.
|
|
2
|
+
import { DirectoryReleaseNotesTools } from "../release-notes.js";
|
|
3
|
+
describe("DirectoryReleaseNotesTools.directory_release_notes", () => {
|
|
4
|
+
const client = {};
|
|
5
|
+
const tools = new DirectoryReleaseNotesTools(client).getTools();
|
|
6
|
+
const tool = tools.find((t) => t.definition.name === "directory_release_notes");
|
|
7
|
+
it("registers as a single tool named directory_release_notes", () => {
|
|
8
|
+
expect(tools).toHaveLength(1);
|
|
9
|
+
expect(tool).toBeDefined();
|
|
10
|
+
});
|
|
11
|
+
it("returns the last 3 releases by default", async () => {
|
|
12
|
+
const result = await tool.executor({});
|
|
13
|
+
const data = JSON.parse(result.content[0].text);
|
|
14
|
+
expect(data.package).toBe("@withpica/mcp-server-directory");
|
|
15
|
+
expect(data.current_version).toMatch(/^\d+\.\d+\.\d+$/);
|
|
16
|
+
expect(Array.isArray(data.releases)).toBe(true);
|
|
17
|
+
expect(data.releases.length).toBeLessThanOrEqual(3);
|
|
18
|
+
expect(data.releases.length).toBeGreaterThan(0);
|
|
19
|
+
expect(data.resource_uri).toBe("release-notes://withpica/mcp-server-directory/latest");
|
|
20
|
+
});
|
|
21
|
+
it("respects since_version (strictly greater)", async () => {
|
|
22
|
+
const result = await tool.executor({ since_version: "0.0.1" });
|
|
23
|
+
const data = JSON.parse(result.content[0].text);
|
|
24
|
+
expect(data.releases.length).toBeGreaterThan(0);
|
|
25
|
+
for (const r of data.releases) {
|
|
26
|
+
expect(r.version).not.toBe("0.0.1");
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
it("filters to specified sections", async () => {
|
|
30
|
+
const result = await tool.executor({ sections: ["Added"] });
|
|
31
|
+
const data = JSON.parse(result.content[0].text);
|
|
32
|
+
for (const r of data.releases) {
|
|
33
|
+
for (const k of Object.keys(r.sections)) {
|
|
34
|
+
expect(k).toBe("Added");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
it("returns empty releases array when since_version exceeds current_version", async () => {
|
|
39
|
+
const result = await tool.executor({ since_version: "99.0.0" });
|
|
40
|
+
const data = JSON.parse(result.content[0].text);
|
|
41
|
+
expect(data.releases).toEqual([]);
|
|
42
|
+
});
|
|
43
|
+
it("clamps limit to max 20", async () => {
|
|
44
|
+
const result = await tool.executor({ limit: 9999 });
|
|
45
|
+
const data = JSON.parse(result.content[0].text);
|
|
46
|
+
expect(data.releases.length).toBeLessThanOrEqual(20);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
//# sourceMappingURL=release-notes.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release-notes.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/release-notes.test.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAGjE,QAAQ,CAAC,oDAAoD,EAAE,GAAG,EAAE;IAClE,MAAM,MAAM,GAAG,EAAqB,CAAC;IACrC,MAAM,KAAK,GAAG,IAAI,0BAA0B,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;IAChE,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CACrB,CAAC,CAAmC,EAAE,EAAE,CACtC,CAAC,CAAC,UAAU,CAAC,IAAI,KAAK,yBAAyB,CACjD,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;QAC5D,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACxD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAChD,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAC5B,sDAAsD,CACvD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC;QAC/D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAChD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC9B,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAChD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC9B,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACxC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;QACvF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;QACtC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { DirectoryClient } from "../client.js";
|
|
2
|
+
import { ToolDefinition, ToolExecutor } from "./index.js";
|
|
3
|
+
export declare class DirectoryChainTools {
|
|
4
|
+
private client;
|
|
5
|
+
constructor(client: DirectoryClient);
|
|
6
|
+
getTools(): Array<{
|
|
7
|
+
definition: ToolDefinition;
|
|
8
|
+
executor: ToolExecutor;
|
|
9
|
+
}>;
|
|
10
|
+
private chainLookup;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=chain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../../src/tools/chain.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1D,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAkB;gBAEpB,MAAM,EAAE,eAAe;IAInC,QAAQ,IAAI,KAAK,CAAC;QAAE,UAAU,EAAE,cAAc,CAAC;QAAC,QAAQ,EAAE,YAAY,CAAA;KAAE,CAAC;YAgE3D,WAAW;CAyC1B"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// Copyright (c) 2024-2026 Withpica Ltd. All rights reserved.
|
|
2
|
+
export class DirectoryChainTools {
|
|
3
|
+
client;
|
|
4
|
+
constructor(client) {
|
|
5
|
+
this.client = client;
|
|
6
|
+
}
|
|
7
|
+
getTools() {
|
|
8
|
+
return [
|
|
9
|
+
{
|
|
10
|
+
definition: {
|
|
11
|
+
name: "directory_chain",
|
|
12
|
+
tier: "read",
|
|
13
|
+
description: "Use when the user asks: 'show me the rights chain for X', " +
|
|
14
|
+
"'give me everything on this song', 'what's the full picture for X?', " +
|
|
15
|
+
"'trace the chain from this writer to that work'. " +
|
|
16
|
+
"Graph lookup — resolves a query, ISWC, or ISRC to its full rights chain in one call. " +
|
|
17
|
+
"Each result bundles the work, its writers and publishers (names + roles, no IPIs or splits), " +
|
|
18
|
+
"the linked recording (ISRC, DSP presence, duration), and audio characteristics (BPM, key, energy). " +
|
|
19
|
+
"Prefer over stitching list_works + lookup_work + lookup_person when you want the whole graph " +
|
|
20
|
+
"around a track in a single round-trip. " +
|
|
21
|
+
"Supports audio-only queries (min_bpm, key, mood, etc.) when you don't have a text query. " +
|
|
22
|
+
"→ then: directory_lookup_work (deeper work detail), directory_lookup_person (research a named writer)",
|
|
23
|
+
inputSchema: {
|
|
24
|
+
type: "object",
|
|
25
|
+
properties: {
|
|
26
|
+
q: {
|
|
27
|
+
type: "string",
|
|
28
|
+
description: "Free-text query (work title, creator name, etc.). Minimum 2 characters.",
|
|
29
|
+
},
|
|
30
|
+
identifier: {
|
|
31
|
+
type: "string",
|
|
32
|
+
description: "ISWC or ISRC — direct identifier lookup",
|
|
33
|
+
},
|
|
34
|
+
min_bpm: { type: "number", description: "Minimum BPM" },
|
|
35
|
+
max_bpm: { type: "number", description: "Maximum BPM" },
|
|
36
|
+
key: {
|
|
37
|
+
type: "string",
|
|
38
|
+
description: "Musical key (e.g. 'C', 'F#', 'Bb')",
|
|
39
|
+
},
|
|
40
|
+
key_mode: {
|
|
41
|
+
type: "string",
|
|
42
|
+
enum: ["major", "minor"],
|
|
43
|
+
description: "Key mode",
|
|
44
|
+
},
|
|
45
|
+
min_energy: {
|
|
46
|
+
type: "number",
|
|
47
|
+
description: "Minimum energy (0–1)",
|
|
48
|
+
},
|
|
49
|
+
max_energy: {
|
|
50
|
+
type: "number",
|
|
51
|
+
description: "Maximum energy (0–1)",
|
|
52
|
+
},
|
|
53
|
+
mood: {
|
|
54
|
+
type: "string",
|
|
55
|
+
description: "Mood filter (exact match)",
|
|
56
|
+
},
|
|
57
|
+
limit: {
|
|
58
|
+
type: "number",
|
|
59
|
+
description: "Max results (default 10, max 20)",
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
executor: this.chainLookup.bind(this),
|
|
65
|
+
},
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
async chainLookup(args) {
|
|
69
|
+
const params = {};
|
|
70
|
+
if (args.q)
|
|
71
|
+
params.q = String(args.q);
|
|
72
|
+
if (args.identifier)
|
|
73
|
+
params.identifier = String(args.identifier);
|
|
74
|
+
const numericKeys = [
|
|
75
|
+
"min_bpm",
|
|
76
|
+
"max_bpm",
|
|
77
|
+
"min_energy",
|
|
78
|
+
"max_energy",
|
|
79
|
+
"limit",
|
|
80
|
+
];
|
|
81
|
+
for (const k of numericKeys) {
|
|
82
|
+
if (args[k] != null)
|
|
83
|
+
params[k] = String(args[k]);
|
|
84
|
+
}
|
|
85
|
+
if (args.key)
|
|
86
|
+
params.key = args.key;
|
|
87
|
+
if (args.key_mode)
|
|
88
|
+
params.key_mode = args.key_mode;
|
|
89
|
+
if (args.mood)
|
|
90
|
+
params.mood = args.mood;
|
|
91
|
+
const response = await this.client.request("/chain", params);
|
|
92
|
+
const results = response.results || [];
|
|
93
|
+
return {
|
|
94
|
+
content: [
|
|
95
|
+
{
|
|
96
|
+
type: "text",
|
|
97
|
+
text: results.length === 0
|
|
98
|
+
? "No chain results."
|
|
99
|
+
: `Found ${results.length} chain result(s). See structuredContent for the full graph.`,
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
structuredContent: {
|
|
103
|
+
total: response.total ?? results.length,
|
|
104
|
+
results,
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.js","sourceRoot":"","sources":["../../src/tools/chain.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { DirectoryClient } from "../client.js";
|
|
2
|
+
/**
|
|
3
|
+
* ADR-230 — authority tier on every directory_* tool. Sister of the
|
|
4
|
+
* creator + team MCP's `Tier` declaration. Every directory tool is
|
|
5
|
+
* `read` (public catalogue lookup with no mutation surface), but the
|
|
6
|
+
* field is required for cross-surface uniformity and lint enforcement.
|
|
7
|
+
*/
|
|
8
|
+
export type Tier = "read" | "draft" | "write" | "destructive";
|
|
9
|
+
export interface ToolDefinition {
|
|
10
|
+
name: string;
|
|
11
|
+
/** ADR-230 — see {@link Tier}. Required on every directory tool. */
|
|
12
|
+
tier: Tier;
|
|
13
|
+
description: string;
|
|
14
|
+
inputSchema: {
|
|
15
|
+
type: string;
|
|
16
|
+
properties: Record<string, any>;
|
|
17
|
+
required?: string[];
|
|
18
|
+
additionalProperties?: boolean;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export interface ToolResult {
|
|
22
|
+
content: Array<{
|
|
23
|
+
type: string;
|
|
24
|
+
text: string;
|
|
25
|
+
}>;
|
|
26
|
+
structuredContent?: Record<string, unknown>;
|
|
27
|
+
isError?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export type ToolExecutor = (args: Record<string, any>) => Promise<any>;
|
|
30
|
+
export declare class ToolRegistry {
|
|
31
|
+
private tools;
|
|
32
|
+
constructor(client: DirectoryClient);
|
|
33
|
+
listTools(): ToolDefinition[];
|
|
34
|
+
executeTool(name: string, args: Record<string, any>): Promise<any>;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAU/C;;;;;GAKG;AACH,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,aAAa,CAAC;AAE9D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,IAAI,EAAE,IAAI,CAAC;IACX,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;QACpB,oBAAoB,CAAC,EAAE,OAAO,CAAC;KAChC,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;IAoBnC,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"}
|