@coldiq/mcp 0.3.15 → 0.3.17
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/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/skills.d.ts +20 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/skills.js +89 -0
- package/dist/skills.js.map +1 -0
- package/dist/tools/list-skills.d.ts +17 -0
- package/dist/tools/list-skills.d.ts.map +1 -0
- package/dist/tools/list-skills.js +22 -0
- package/dist/tools/list-skills.js.map +1 -0
- package/dist/tools/load-skill.d.ts +20 -0
- package/dist/tools/load-skill.d.ts.map +1 -0
- package/dist/tools/load-skill.js +29 -0
- package/dist/tools/load-skill.js.map +1 -0
- package/dist/tools/search-companies.js +2 -2
- package/dist/tools/search-companies.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +16 -0
- package/src/skills.ts +108 -0
- package/src/tools/list-skills.ts +25 -0
- package/src/tools/load-skill.ts +32 -0
- package/src/tools/search-companies.ts +2 -2
- package/tests/skills.test.ts +130 -0
- package/tests/tools/list-skills.test.ts +44 -0
- package/tests/tools/load-skill.test.ts +53 -0
package/dist/index.js
CHANGED
|
@@ -24,6 +24,8 @@ import { getSessionUsageName, getSessionUsageDescription, getSessionUsageSchema,
|
|
|
24
24
|
import { extractPostEngagementName, extractPostEngagementDescription, extractPostEngagementSchema, extractPostEngagementHandler, } from './tools/extract-post-engagement.js';
|
|
25
25
|
import { getPlaceReviewsName, getPlaceReviewsDescription, getPlaceReviewsSchema, getPlaceReviewsHandler, } from './tools/get-place-reviews.js';
|
|
26
26
|
import { listDataSourcesName, listDataSourcesDescription, listDataSourcesSchema, listDataSourcesHandler, } from './tools/list-data-sources.js';
|
|
27
|
+
import { listSkillsName, listSkillsDescription, listSkillsSchema, listSkillsHandler, } from './tools/list-skills.js';
|
|
28
|
+
import { loadSkillName, loadSkillDescription, loadSkillSchema, loadSkillHandler, } from './tools/load-skill.js';
|
|
27
29
|
// Initialize HTTP client (reads env vars)
|
|
28
30
|
initClient();
|
|
29
31
|
const server = new McpServer({
|
|
@@ -62,6 +64,8 @@ server.tool(fetchPageContentName, fetchPageContentDescription, fetchPageContentS
|
|
|
62
64
|
server.tool(getCreditBalanceName, getCreditBalanceDescription, getCreditBalanceSchema, getCreditBalanceHandler);
|
|
63
65
|
server.tool(getSessionUsageName, getSessionUsageDescription, getSessionUsageSchema, getSessionUsageHandler);
|
|
64
66
|
server.tool(listDataSourcesName, listDataSourcesDescription, listDataSourcesSchema, listDataSourcesHandler);
|
|
67
|
+
server.tool(listSkillsName, listSkillsDescription, listSkillsSchema, listSkillsHandler);
|
|
68
|
+
server.tool(loadSkillName, loadSkillDescription, loadSkillSchema, loadSkillHandler);
|
|
65
69
|
server.tool(extractPostEngagementName, extractPostEngagementDescription, extractPostEngagementSchema, extractPostEngagementHandler);
|
|
66
70
|
server.tool(getPlaceReviewsName, getPlaceReviewsDescription, getPlaceReviewsSchema, getPlaceReviewsHandler);
|
|
67
71
|
// Connect via stdio transport
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/skills.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface SkillEntry {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
url: string;
|
|
5
|
+
digest?: string;
|
|
6
|
+
}
|
|
7
|
+
/** Test seam: clear in-memory caches. */
|
|
8
|
+
export declare function __resetSkillsCache(): void;
|
|
9
|
+
/** The catalog: each skill's name + one-line description (no bodies). */
|
|
10
|
+
export declare function listSkills(): Promise<{
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
}[]>;
|
|
14
|
+
/**
|
|
15
|
+
* Full playbook body for `name`. Any `resources/<file>.md` the skill references
|
|
16
|
+
* is fetched and appended so the returned document is self-contained (agents
|
|
17
|
+
* reached over MCP can't follow the relative links themselves).
|
|
18
|
+
*/
|
|
19
|
+
export declare function loadSkill(name: string): Promise<string>;
|
|
20
|
+
//# sourceMappingURL=skills.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAUD,yCAAyC;AACzC,wBAAgB,kBAAkB,IAAI,IAAI,CAGzC;AA+BD,yEAAyE;AACzE,wBAAsB,UAAU,IAAI,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAGnF;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA6B7D"}
|
package/dist/skills.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// ColdIQ GTM skills, served over MCP.
|
|
2
|
+
//
|
|
3
|
+
// Skills are step-by-step playbooks authored in the coldiq-marketplace-skills
|
|
4
|
+
// repo. Claude Code and Cursor load them natively (progressive disclosure), but
|
|
5
|
+
// agents without a skills loader (Codex, Windsurf, Cline, …) can't. Since every
|
|
6
|
+
// agent that installs this MCP gets these two tools, the MCP is the universal
|
|
7
|
+
// delivery channel: list_skills surfaces the catalog, load_skill fetches one
|
|
8
|
+
// playbook on demand.
|
|
9
|
+
//
|
|
10
|
+
// Source is the repo's discovery index on GitHub raw, so a push to the skills
|
|
11
|
+
// repo updates what every agent sees — no MCP republish needed. Override with
|
|
12
|
+
// COLDIQ_SKILLS_INDEX_URL.
|
|
13
|
+
const DEFAULT_INDEX_URL = 'https://raw.githubusercontent.com/Cold-IQ/coldiq-marketplace-skills/main/.well-known/agent-skills/index.json';
|
|
14
|
+
const INDEX_TTL_MS = 10 * 60 * 1000; // re-fetch the catalog at most every 10 min
|
|
15
|
+
let _indexCache = null;
|
|
16
|
+
const _bodyCache = new Map();
|
|
17
|
+
/** Test seam: clear in-memory caches. */
|
|
18
|
+
export function __resetSkillsCache() {
|
|
19
|
+
_indexCache = null;
|
|
20
|
+
_bodyCache.clear();
|
|
21
|
+
}
|
|
22
|
+
function indexUrl() {
|
|
23
|
+
return process.env.COLDIQ_SKILLS_INDEX_URL || DEFAULT_INDEX_URL;
|
|
24
|
+
}
|
|
25
|
+
async function fetchText(url) {
|
|
26
|
+
const res = await fetch(url, { headers: { 'user-agent': 'coldiq-mcp' } });
|
|
27
|
+
if (!res.ok)
|
|
28
|
+
throw new Error(`request to ${url} failed (HTTP ${res.status})`);
|
|
29
|
+
return await res.text();
|
|
30
|
+
}
|
|
31
|
+
async function getIndex() {
|
|
32
|
+
if (_indexCache && Date.now() - _indexCache.fetchedAt < INDEX_TTL_MS) {
|
|
33
|
+
return _indexCache.skills;
|
|
34
|
+
}
|
|
35
|
+
const parsed = JSON.parse(await fetchText(indexUrl()));
|
|
36
|
+
const raw = Array.isArray(parsed?.skills) ? parsed.skills : [];
|
|
37
|
+
const skills = raw
|
|
38
|
+
.filter((s) => !!s && typeof s === 'object')
|
|
39
|
+
.map((s) => ({
|
|
40
|
+
name: String(s.name ?? ''),
|
|
41
|
+
description: String(s.description ?? ''),
|
|
42
|
+
url: String(s.url ?? ''),
|
|
43
|
+
digest: typeof s.digest === 'string' ? s.digest : undefined,
|
|
44
|
+
}))
|
|
45
|
+
.filter((s) => s.name && s.url);
|
|
46
|
+
_indexCache = { skills, fetchedAt: Date.now() };
|
|
47
|
+
return skills;
|
|
48
|
+
}
|
|
49
|
+
/** The catalog: each skill's name + one-line description (no bodies). */
|
|
50
|
+
export async function listSkills() {
|
|
51
|
+
const skills = await getIndex();
|
|
52
|
+
return skills.map((s) => ({ name: s.name, description: s.description }));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Full playbook body for `name`. Any `resources/<file>.md` the skill references
|
|
56
|
+
* is fetched and appended so the returned document is self-contained (agents
|
|
57
|
+
* reached over MCP can't follow the relative links themselves).
|
|
58
|
+
*/
|
|
59
|
+
export async function loadSkill(name) {
|
|
60
|
+
const skills = await getIndex();
|
|
61
|
+
const entry = skills.find((s) => s.name === name);
|
|
62
|
+
if (!entry) {
|
|
63
|
+
throw new Error(`unknown skill "${name}". Available: ${skills.map((s) => s.name).join(', ')}`);
|
|
64
|
+
}
|
|
65
|
+
if (_bodyCache.has(entry.url))
|
|
66
|
+
return _bodyCache.get(entry.url);
|
|
67
|
+
const body = await fetchText(entry.url);
|
|
68
|
+
const refs = new Set();
|
|
69
|
+
for (const m of body.matchAll(/resources\/([A-Za-z0-9._-]+\.md)/g))
|
|
70
|
+
refs.add(m[1]);
|
|
71
|
+
let combined = body;
|
|
72
|
+
if (refs.size > 0) {
|
|
73
|
+
const baseDir = entry.url.replace(/\/[^/]*$/, ''); // strip trailing SKILL.md
|
|
74
|
+
const sections = [];
|
|
75
|
+
for (const ref of refs) {
|
|
76
|
+
try {
|
|
77
|
+
const text = await fetchText(`${baseDir}/resources/${ref}`);
|
|
78
|
+
sections.push(`\n\n---\n\n## Resource: resources/${ref}\n\n${text.trim()}`);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// A missing resource shouldn't fail the whole skill load.
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
combined = body.replace(/\s+$/, '') + sections.join('') + '\n';
|
|
85
|
+
}
|
|
86
|
+
_bodyCache.set(entry.url, combined);
|
|
87
|
+
return combined;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const listSkillsName = "list_skills";
|
|
2
|
+
export declare const listSkillsDescription: string;
|
|
3
|
+
export declare const listSkillsSchema: {};
|
|
4
|
+
export declare function listSkillsHandler(_input: Record<string, unknown>): Promise<{
|
|
5
|
+
content: {
|
|
6
|
+
type: "text";
|
|
7
|
+
text: string;
|
|
8
|
+
}[];
|
|
9
|
+
isError?: undefined;
|
|
10
|
+
} | {
|
|
11
|
+
content: {
|
|
12
|
+
type: "text";
|
|
13
|
+
text: string;
|
|
14
|
+
}[];
|
|
15
|
+
isError: boolean;
|
|
16
|
+
}>;
|
|
17
|
+
//# sourceMappingURL=list-skills.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-skills.d.ts","sourceRoot":"","sources":["../../src/tools/list-skills.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,cAAc,gBAAgB,CAAA;AAE3C,eAAO,MAAM,qBAAqB,QAMkE,CAAA;AAEpG,eAAO,MAAM,gBAAgB,IAAK,CAAA;AAElC,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;GAUtE"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { listSkills } from '../skills.js';
|
|
2
|
+
export const listSkillsName = 'list_skills';
|
|
3
|
+
export const listSkillsDescription = 'List the available ColdIQ GTM playbooks ("skills") — step-by-step expert workflows for go-to-market ' +
|
|
4
|
+
'tasks: building a TAM, Apollo / company / people search, contact enrichment and email waterfalls, ' +
|
|
5
|
+
'signal detection, ICP & personas, cold-email copy, campaign delivery, and more. Returns each skill\'s ' +
|
|
6
|
+
'name and a one-line description of when to use it. Call this when starting a prospecting / outreach / ' +
|
|
7
|
+
'GTM task to check for a relevant playbook, then call load_skill to read the full step-by-step guide. ' +
|
|
8
|
+
'(Claude Code and Cursor load these skills natively; on other agents this is how you reach them.)';
|
|
9
|
+
export const listSkillsSchema = {};
|
|
10
|
+
export async function listSkillsHandler(_input) {
|
|
11
|
+
try {
|
|
12
|
+
const skills = await listSkills();
|
|
13
|
+
return { content: [{ type: 'text', text: JSON.stringify({ data: skills }) }] };
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
return {
|
|
17
|
+
content: [{ type: 'text', text: JSON.stringify({ error: `Could not load the ColdIQ skills catalog: ${err.message}` }) }],
|
|
18
|
+
isError: true,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=list-skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-skills.js","sourceRoot":"","sources":["../../src/tools/list-skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,MAAM,CAAC,MAAM,cAAc,GAAG,aAAa,CAAA;AAE3C,MAAM,CAAC,MAAM,qBAAqB,GAChC,sGAAsG;IACtG,oGAAoG;IACpG,wGAAwG;IACxG,wGAAwG;IACxG,uGAAuG;IACvG,kGAAkG,CAAA;AAEpG,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAA;AAElC,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAA+B;IACrE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAA;QACjC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;IACzF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,6CAA8C,GAAa,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;YAC5I,OAAO,EAAE,IAAI;SACd,CAAA;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const loadSkillName = "load_skill";
|
|
3
|
+
export declare const loadSkillDescription: string;
|
|
4
|
+
export declare const loadSkillSchema: {
|
|
5
|
+
name: z.ZodString;
|
|
6
|
+
};
|
|
7
|
+
export declare function loadSkillHandler(input: Record<string, unknown>): Promise<{
|
|
8
|
+
content: {
|
|
9
|
+
type: "text";
|
|
10
|
+
text: string;
|
|
11
|
+
}[];
|
|
12
|
+
isError: boolean;
|
|
13
|
+
} | {
|
|
14
|
+
content: {
|
|
15
|
+
type: "text";
|
|
16
|
+
text: string;
|
|
17
|
+
}[];
|
|
18
|
+
isError?: undefined;
|
|
19
|
+
}>;
|
|
20
|
+
//# sourceMappingURL=load-skill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-skill.d.ts","sourceRoot":"","sources":["../../src/tools/load-skill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,aAAa,eAAe,CAAA;AAEzC,eAAO,MAAM,oBAAoB,QAIK,CAAA;AAEtC,eAAO,MAAM,eAAe;;CAI3B,CAAA;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;GAcpE"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { loadSkill } from '../skills.js';
|
|
3
|
+
export const loadSkillName = 'load_skill';
|
|
4
|
+
export const loadSkillDescription = 'Load the full ColdIQ GTM playbook ("skill") by name — the complete step-by-step expert workflow, ' +
|
|
5
|
+
'including which ColdIQ tools/endpoints to call at each step. Call list_skills first to get the available ' +
|
|
6
|
+
'names. The returned guide (with any referenced reference docs inlined) tells you exactly how to run the ' +
|
|
7
|
+
'task using the other ColdIQ tools.';
|
|
8
|
+
export const loadSkillSchema = {
|
|
9
|
+
name: z
|
|
10
|
+
.string()
|
|
11
|
+
.describe('The skill name from list_skills, e.g. "contact-enrichment", "apollo-search", or "tam-scoring".'),
|
|
12
|
+
};
|
|
13
|
+
export async function loadSkillHandler(input) {
|
|
14
|
+
const name = String(input.name ?? '').trim();
|
|
15
|
+
if (!name) {
|
|
16
|
+
return {
|
|
17
|
+
content: [{ type: 'text', text: 'Provide a skill "name" — call list_skills to see the available skills.' }],
|
|
18
|
+
isError: true,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const body = await loadSkill(name);
|
|
23
|
+
return { content: [{ type: 'text', text: body }] };
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=load-skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-skill.js","sourceRoot":"","sources":["../../src/tools/load-skill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAExC,MAAM,CAAC,MAAM,aAAa,GAAG,YAAY,CAAA;AAEzC,MAAM,CAAC,MAAM,oBAAoB,GAC/B,mGAAmG;IACnG,2GAA2G;IAC3G,0GAA0G;IAC1G,oCAAoC,CAAA;AAEtC,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,QAAQ,CAAC,gGAAgG,CAAC;CAC9G,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAA8B;IACnE,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IAC5C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,wEAAwE,EAAE,CAAC;YACpH,OAAO,EAAE,IAAI;SACd,CAAA;IACH,CAAC;IACD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAA;QAClC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAA;IAC7D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IAC9F,CAAC;AACH,CAAC"}
|
|
@@ -2,7 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { callVerb } from '../verb-client.js';
|
|
3
3
|
import { getProvidersForCapability } from '../utils/provider-resolver.js';
|
|
4
4
|
export const searchCompaniesName = 'search_companies';
|
|
5
|
-
export const searchCompaniesDescription = 'Search B2B companies by industry, size, geography, founding year, tech stack, funding, revenue, exclusion lists, and hiring signals. Routing is automatic: strict firmographic filters (revenue, employee bands, exclusion lists) get high-precision providers first; tech-stack and funding-stage filters route to specialized providers; loose keyword/geo searches fall back to broad providers; a LinkedIn Sales Navigator search URL enables URL-based discovery as a final fallback. For buying-intent topic discovery (find companies associated with intent keywords like "sales automation" or "lead generation"), pass `keywords` with `use_providers: ["theirstack"]` — this routes to TheirStack\'s intent-keyword index instead of the default full-text match. ColdIQ automatically picks the best provider — pass use_providers only if you need a specific tool. Default limit: 25. ' +
|
|
5
|
+
export const searchCompaniesDescription = 'Search B2B companies by industry, size, geography, founding year, tech stack, funding, revenue, exclusion lists, and hiring signals. Routing is automatic: strict firmographic filters (revenue, employee bands, exclusion lists) get high-precision providers first; tech-stack and funding-stage filters route to specialized providers; loose keyword/geo searches fall back to broad providers; a LinkedIn Sales Navigator search URL enables URL-based discovery as a final fallback. For buying-intent topic discovery (find companies associated with intent keywords like "sales automation" or "lead generation"), pass `keywords` with `use_providers: ["theirstack"]` — this routes to TheirStack\'s intent-keyword index instead of the default full-text match. For "fast-growing" companies there is no exact workforce-growth % filter anywhere — pass min_workforce_growth_pct (and/or is_hiring / a recent-funding filter) and ColdIQ routes to active-hiring and recently-funded providers, the practical proxies for growth. ColdIQ automatically picks the best provider — pass use_providers only if you need a specific tool. Default limit: 25. ' +
|
|
6
6
|
'Response is compact by default (name, domain, website, linkedin_url, employees, revenue, industry, country, city, founded_year, categories) — everything needed to act on a company or feed it into find_people. Set fields="verbose" only when you specifically need the full firmographic record (funding history, technologies, keywords, NAICS codes, all socials, descriptions).';
|
|
7
7
|
export const searchCompaniesSchema = {
|
|
8
8
|
keywords: z.array(z.string()).optional().describe('Free-text topics, business models, or themes — e.g. ["SaaS", "fintech", "cybersecurity"]. Best for most discovery: matched broadly across company name, description, and tags. Prefer this over `industries` for terms like "SaaS" that are business models rather than formal industry categories.'),
|
|
@@ -25,7 +25,7 @@ export const searchCompaniesSchema = {
|
|
|
25
25
|
exclude_industries: z.array(z.string()).optional().describe('Industry names to exclude from results'),
|
|
26
26
|
exclude_countries: z.array(z.string()).optional().describe('2-letter ISO country codes to exclude from results'),
|
|
27
27
|
is_hiring: z.boolean().optional().describe('Filter to companies currently posting jobs'),
|
|
28
|
-
min_workforce_growth_pct: z.number().optional().describe('
|
|
28
|
+
min_workforce_growth_pct: z.number().optional().describe('Signals "fast-growing" intent. No provider applies an exact growth %, so this routes the search to active-hiring and recently-funded proxies rather than filtering on a literal percentage.'),
|
|
29
29
|
linkedin_search_url: z.string().optional().describe('LinkedIn Sales Navigator company search URL — when provided, enables URL-based prospect discovery as a final fallback. Most users should leave this unset.'),
|
|
30
30
|
limit: z.number().min(1).max(500).default(25).describe('Max results to return (default: 25, max: 500). Pulls above 100 auto-paginate the underlying provider; on Apollo each 100 companies costs 1 credit, billed only for pages actually returned.'),
|
|
31
31
|
fields: z.enum(['compact', 'verbose']).default('compact').describe('Response shape. "compact" (default) returns a small per-company record: name, domain, website, linkedin_url, employees, revenue, industry, country, city, founded_year, categories — plus total. "verbose" returns the raw provider passthrough (funding-round history, technologies, keyword arrays, NAICS codes, all socials, descriptions) — only use when you specifically need those fields.'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-companies.js","sourceRoot":"","sources":["../../src/tools/search-companies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAA;AAEzE,MAAM,CAAC,MAAM,mBAAmB,GAAG,kBAAkB,CAAA;AAErD,MAAM,CAAC,MAAM,0BAA0B,GACrC,
|
|
1
|
+
{"version":3,"file":"search-companies.js","sourceRoot":"","sources":["../../src/tools/search-companies.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -158,6 +158,20 @@ import {
|
|
|
158
158
|
listDataSourcesHandler,
|
|
159
159
|
} from './tools/list-data-sources.js'
|
|
160
160
|
|
|
161
|
+
import {
|
|
162
|
+
listSkillsName,
|
|
163
|
+
listSkillsDescription,
|
|
164
|
+
listSkillsSchema,
|
|
165
|
+
listSkillsHandler,
|
|
166
|
+
} from './tools/list-skills.js'
|
|
167
|
+
|
|
168
|
+
import {
|
|
169
|
+
loadSkillName,
|
|
170
|
+
loadSkillDescription,
|
|
171
|
+
loadSkillSchema,
|
|
172
|
+
loadSkillHandler,
|
|
173
|
+
} from './tools/load-skill.js'
|
|
174
|
+
|
|
161
175
|
// Initialize HTTP client (reads env vars)
|
|
162
176
|
initClient()
|
|
163
177
|
|
|
@@ -201,6 +215,8 @@ server.tool(fetchPageContentName, fetchPageContentDescription, fetchPageContentS
|
|
|
201
215
|
server.tool(getCreditBalanceName, getCreditBalanceDescription, getCreditBalanceSchema, getCreditBalanceHandler)
|
|
202
216
|
server.tool(getSessionUsageName, getSessionUsageDescription, getSessionUsageSchema, getSessionUsageHandler)
|
|
203
217
|
server.tool(listDataSourcesName, listDataSourcesDescription, listDataSourcesSchema, listDataSourcesHandler)
|
|
218
|
+
server.tool(listSkillsName, listSkillsDescription, listSkillsSchema, listSkillsHandler)
|
|
219
|
+
server.tool(loadSkillName, loadSkillDescription, loadSkillSchema, loadSkillHandler)
|
|
204
220
|
server.tool(extractPostEngagementName, extractPostEngagementDescription, extractPostEngagementSchema, extractPostEngagementHandler)
|
|
205
221
|
server.tool(getPlaceReviewsName, getPlaceReviewsDescription, getPlaceReviewsSchema, getPlaceReviewsHandler)
|
|
206
222
|
|
package/src/skills.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// ColdIQ GTM skills, served over MCP.
|
|
2
|
+
//
|
|
3
|
+
// Skills are step-by-step playbooks authored in the coldiq-marketplace-skills
|
|
4
|
+
// repo. Claude Code and Cursor load them natively (progressive disclosure), but
|
|
5
|
+
// agents without a skills loader (Codex, Windsurf, Cline, …) can't. Since every
|
|
6
|
+
// agent that installs this MCP gets these two tools, the MCP is the universal
|
|
7
|
+
// delivery channel: list_skills surfaces the catalog, load_skill fetches one
|
|
8
|
+
// playbook on demand.
|
|
9
|
+
//
|
|
10
|
+
// Source is the repo's discovery index on GitHub raw, so a push to the skills
|
|
11
|
+
// repo updates what every agent sees — no MCP republish needed. Override with
|
|
12
|
+
// COLDIQ_SKILLS_INDEX_URL.
|
|
13
|
+
|
|
14
|
+
const DEFAULT_INDEX_URL =
|
|
15
|
+
'https://raw.githubusercontent.com/Cold-IQ/coldiq-marketplace-skills/main/.well-known/agent-skills/index.json'
|
|
16
|
+
const INDEX_TTL_MS = 10 * 60 * 1000 // re-fetch the catalog at most every 10 min
|
|
17
|
+
|
|
18
|
+
export interface SkillEntry {
|
|
19
|
+
name: string
|
|
20
|
+
description: string
|
|
21
|
+
url: string
|
|
22
|
+
digest?: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface CachedIndex {
|
|
26
|
+
skills: SkillEntry[]
|
|
27
|
+
fetchedAt: number
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let _indexCache: CachedIndex | null = null
|
|
31
|
+
const _bodyCache = new Map<string, string>()
|
|
32
|
+
|
|
33
|
+
/** Test seam: clear in-memory caches. */
|
|
34
|
+
export function __resetSkillsCache(): void {
|
|
35
|
+
_indexCache = null
|
|
36
|
+
_bodyCache.clear()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function indexUrl(): string {
|
|
40
|
+
return process.env.COLDIQ_SKILLS_INDEX_URL || DEFAULT_INDEX_URL
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function fetchText(url: string): Promise<string> {
|
|
44
|
+
const res = await fetch(url, { headers: { 'user-agent': 'coldiq-mcp' } })
|
|
45
|
+
if (!res.ok) throw new Error(`request to ${url} failed (HTTP ${res.status})`)
|
|
46
|
+
return await res.text()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function getIndex(): Promise<SkillEntry[]> {
|
|
50
|
+
if (_indexCache && Date.now() - _indexCache.fetchedAt < INDEX_TTL_MS) {
|
|
51
|
+
return _indexCache.skills
|
|
52
|
+
}
|
|
53
|
+
const parsed = JSON.parse(await fetchText(indexUrl()))
|
|
54
|
+
const raw = Array.isArray(parsed?.skills) ? parsed.skills : []
|
|
55
|
+
const skills: SkillEntry[] = raw
|
|
56
|
+
.filter((s: unknown): s is Record<string, unknown> => !!s && typeof s === 'object')
|
|
57
|
+
.map((s: Record<string, unknown>) => ({
|
|
58
|
+
name: String(s.name ?? ''),
|
|
59
|
+
description: String(s.description ?? ''),
|
|
60
|
+
url: String(s.url ?? ''),
|
|
61
|
+
digest: typeof s.digest === 'string' ? s.digest : undefined,
|
|
62
|
+
}))
|
|
63
|
+
.filter((s: SkillEntry) => s.name && s.url)
|
|
64
|
+
_indexCache = { skills, fetchedAt: Date.now() }
|
|
65
|
+
return skills
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** The catalog: each skill's name + one-line description (no bodies). */
|
|
69
|
+
export async function listSkills(): Promise<{ name: string; description: string }[]> {
|
|
70
|
+
const skills = await getIndex()
|
|
71
|
+
return skills.map((s) => ({ name: s.name, description: s.description }))
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Full playbook body for `name`. Any `resources/<file>.md` the skill references
|
|
76
|
+
* is fetched and appended so the returned document is self-contained (agents
|
|
77
|
+
* reached over MCP can't follow the relative links themselves).
|
|
78
|
+
*/
|
|
79
|
+
export async function loadSkill(name: string): Promise<string> {
|
|
80
|
+
const skills = await getIndex()
|
|
81
|
+
const entry = skills.find((s) => s.name === name)
|
|
82
|
+
if (!entry) {
|
|
83
|
+
throw new Error(`unknown skill "${name}". Available: ${skills.map((s) => s.name).join(', ')}`)
|
|
84
|
+
}
|
|
85
|
+
if (_bodyCache.has(entry.url)) return _bodyCache.get(entry.url) as string
|
|
86
|
+
|
|
87
|
+
const body = await fetchText(entry.url)
|
|
88
|
+
const refs = new Set<string>()
|
|
89
|
+
for (const m of body.matchAll(/resources\/([A-Za-z0-9._-]+\.md)/g)) refs.add(m[1])
|
|
90
|
+
|
|
91
|
+
let combined = body
|
|
92
|
+
if (refs.size > 0) {
|
|
93
|
+
const baseDir = entry.url.replace(/\/[^/]*$/, '') // strip trailing SKILL.md
|
|
94
|
+
const sections: string[] = []
|
|
95
|
+
for (const ref of refs) {
|
|
96
|
+
try {
|
|
97
|
+
const text = await fetchText(`${baseDir}/resources/${ref}`)
|
|
98
|
+
sections.push(`\n\n---\n\n## Resource: resources/${ref}\n\n${text.trim()}`)
|
|
99
|
+
} catch {
|
|
100
|
+
// A missing resource shouldn't fail the whole skill load.
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
combined = body.replace(/\s+$/, '') + sections.join('') + '\n'
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
_bodyCache.set(entry.url, combined)
|
|
107
|
+
return combined
|
|
108
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { listSkills } from '../skills.js'
|
|
2
|
+
|
|
3
|
+
export const listSkillsName = 'list_skills'
|
|
4
|
+
|
|
5
|
+
export const listSkillsDescription =
|
|
6
|
+
'List the available ColdIQ GTM playbooks ("skills") — step-by-step expert workflows for go-to-market ' +
|
|
7
|
+
'tasks: building a TAM, Apollo / company / people search, contact enrichment and email waterfalls, ' +
|
|
8
|
+
'signal detection, ICP & personas, cold-email copy, campaign delivery, and more. Returns each skill\'s ' +
|
|
9
|
+
'name and a one-line description of when to use it. Call this when starting a prospecting / outreach / ' +
|
|
10
|
+
'GTM task to check for a relevant playbook, then call load_skill to read the full step-by-step guide. ' +
|
|
11
|
+
'(Claude Code and Cursor load these skills natively; on other agents this is how you reach them.)'
|
|
12
|
+
|
|
13
|
+
export const listSkillsSchema = {}
|
|
14
|
+
|
|
15
|
+
export async function listSkillsHandler(_input: Record<string, unknown>) {
|
|
16
|
+
try {
|
|
17
|
+
const skills = await listSkills()
|
|
18
|
+
return { content: [{ type: 'text' as const, text: JSON.stringify({ data: skills }) }] }
|
|
19
|
+
} catch (err) {
|
|
20
|
+
return {
|
|
21
|
+
content: [{ type: 'text' as const, text: JSON.stringify({ error: `Could not load the ColdIQ skills catalog: ${(err as Error).message}` }) }],
|
|
22
|
+
isError: true,
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { loadSkill } from '../skills.js'
|
|
3
|
+
|
|
4
|
+
export const loadSkillName = 'load_skill'
|
|
5
|
+
|
|
6
|
+
export const loadSkillDescription =
|
|
7
|
+
'Load the full ColdIQ GTM playbook ("skill") by name — the complete step-by-step expert workflow, ' +
|
|
8
|
+
'including which ColdIQ tools/endpoints to call at each step. Call list_skills first to get the available ' +
|
|
9
|
+
'names. The returned guide (with any referenced reference docs inlined) tells you exactly how to run the ' +
|
|
10
|
+
'task using the other ColdIQ tools.'
|
|
11
|
+
|
|
12
|
+
export const loadSkillSchema = {
|
|
13
|
+
name: z
|
|
14
|
+
.string()
|
|
15
|
+
.describe('The skill name from list_skills, e.g. "contact-enrichment", "apollo-search", or "tam-scoring".'),
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function loadSkillHandler(input: Record<string, unknown>) {
|
|
19
|
+
const name = String(input.name ?? '').trim()
|
|
20
|
+
if (!name) {
|
|
21
|
+
return {
|
|
22
|
+
content: [{ type: 'text' as const, text: 'Provide a skill "name" — call list_skills to see the available skills.' }],
|
|
23
|
+
isError: true,
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const body = await loadSkill(name)
|
|
28
|
+
return { content: [{ type: 'text' as const, text: body }] }
|
|
29
|
+
} catch (err) {
|
|
30
|
+
return { content: [{ type: 'text' as const, text: (err as Error).message }], isError: true }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -5,7 +5,7 @@ import { getProvidersForCapability } from '../utils/provider-resolver.js'
|
|
|
5
5
|
export const searchCompaniesName = 'search_companies'
|
|
6
6
|
|
|
7
7
|
export const searchCompaniesDescription =
|
|
8
|
-
'Search B2B companies by industry, size, geography, founding year, tech stack, funding, revenue, exclusion lists, and hiring signals. Routing is automatic: strict firmographic filters (revenue, employee bands, exclusion lists) get high-precision providers first; tech-stack and funding-stage filters route to specialized providers; loose keyword/geo searches fall back to broad providers; a LinkedIn Sales Navigator search URL enables URL-based discovery as a final fallback. For buying-intent topic discovery (find companies associated with intent keywords like "sales automation" or "lead generation"), pass `keywords` with `use_providers: ["theirstack"]` — this routes to TheirStack\'s intent-keyword index instead of the default full-text match. ColdIQ automatically picks the best provider — pass use_providers only if you need a specific tool. Default limit: 25. ' +
|
|
8
|
+
'Search B2B companies by industry, size, geography, founding year, tech stack, funding, revenue, exclusion lists, and hiring signals. Routing is automatic: strict firmographic filters (revenue, employee bands, exclusion lists) get high-precision providers first; tech-stack and funding-stage filters route to specialized providers; loose keyword/geo searches fall back to broad providers; a LinkedIn Sales Navigator search URL enables URL-based discovery as a final fallback. For buying-intent topic discovery (find companies associated with intent keywords like "sales automation" or "lead generation"), pass `keywords` with `use_providers: ["theirstack"]` — this routes to TheirStack\'s intent-keyword index instead of the default full-text match. For "fast-growing" companies there is no exact workforce-growth % filter anywhere — pass min_workforce_growth_pct (and/or is_hiring / a recent-funding filter) and ColdIQ routes to active-hiring and recently-funded providers, the practical proxies for growth. ColdIQ automatically picks the best provider — pass use_providers only if you need a specific tool. Default limit: 25. ' +
|
|
9
9
|
'Response is compact by default (name, domain, website, linkedin_url, employees, revenue, industry, country, city, founded_year, categories) — everything needed to act on a company or feed it into find_people. Set fields="verbose" only when you specifically need the full firmographic record (funding history, technologies, keywords, NAICS codes, all socials, descriptions).'
|
|
10
10
|
|
|
11
11
|
export const searchCompaniesSchema = {
|
|
@@ -29,7 +29,7 @@ export const searchCompaniesSchema = {
|
|
|
29
29
|
exclude_industries: z.array(z.string()).optional().describe('Industry names to exclude from results'),
|
|
30
30
|
exclude_countries: z.array(z.string()).optional().describe('2-letter ISO country codes to exclude from results'),
|
|
31
31
|
is_hiring: z.boolean().optional().describe('Filter to companies currently posting jobs'),
|
|
32
|
-
min_workforce_growth_pct: z.number().optional().describe('
|
|
32
|
+
min_workforce_growth_pct: z.number().optional().describe('Signals "fast-growing" intent. No provider applies an exact growth %, so this routes the search to active-hiring and recently-funded proxies rather than filtering on a literal percentage.'),
|
|
33
33
|
linkedin_search_url: z.string().optional().describe('LinkedIn Sales Navigator company search URL — when provided, enables URL-based prospect discovery as a final fallback. Most users should leave this unset.'),
|
|
34
34
|
limit: z.number().min(1).max(500).default(25).describe('Max results to return (default: 25, max: 500). Pulls above 100 auto-paginate the underlying provider; on Apollo each 100 companies costs 1 credit, billed only for pages actually returned.'),
|
|
35
35
|
fields: z.enum(['compact', 'verbose']).default('compact').describe('Response shape. "compact" (default) returns a small per-company record: name, domain, website, linkedin_url, employees, revenue, industry, country, city, founded_year, categories — plus total. "verbose" returns the raw provider passthrough (funding-round history, technologies, keyword arrays, NAICS codes, all socials, descriptions) — only use when you specifically need those fields.'),
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
|
2
|
+
import { listSkills, loadSkill, __resetSkillsCache } from '../src/skills.js'
|
|
3
|
+
|
|
4
|
+
const INDEX = {
|
|
5
|
+
$schema: 'https://schemas.agentskills.io/discovery/0.2.0/schema.json',
|
|
6
|
+
name: 'coldiq',
|
|
7
|
+
skills: [
|
|
8
|
+
{
|
|
9
|
+
name: 'contact-enrichment',
|
|
10
|
+
type: 'skill-md',
|
|
11
|
+
description: 'Enrich contacts with emails and phones.',
|
|
12
|
+
url: 'https://raw.example/skills/contact-enrichment/SKILL.md',
|
|
13
|
+
digest: 'sha256:abc',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: 'coldiq-search-enrich',
|
|
17
|
+
type: 'skill-md',
|
|
18
|
+
description: 'Search and enrich at scale.',
|
|
19
|
+
url: 'https://raw.example/skills/lima-data-api/SKILL.md',
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const BODY_WITH_RES =
|
|
25
|
+
'# Contact enrichment\n\nSee [resources/async-job-pattern.md](resources/async-job-pattern.md) and ' +
|
|
26
|
+
'[resources/credit-optimization.md](resources/credit-optimization.md).\n'
|
|
27
|
+
|
|
28
|
+
function mockFetch(map: Record<string, { status?: number; body: string }>) {
|
|
29
|
+
return vi.fn(async (url: string | URL | Request) => {
|
|
30
|
+
const u = String(url)
|
|
31
|
+
const hit = map[u]
|
|
32
|
+
if (!hit) return { ok: false, status: 404, text: async () => 'not found' } as Response
|
|
33
|
+
const status = hit.status ?? 200
|
|
34
|
+
return { ok: status >= 200 && status < 300, status, text: async () => hit.body } as Response
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const originalFetch = globalThis.fetch
|
|
39
|
+
|
|
40
|
+
describe('skills module', () => {
|
|
41
|
+
beforeEach(() => {
|
|
42
|
+
__resetSkillsCache()
|
|
43
|
+
delete process.env.COLDIQ_SKILLS_INDEX_URL
|
|
44
|
+
})
|
|
45
|
+
afterEach(() => {
|
|
46
|
+
globalThis.fetch = originalFetch
|
|
47
|
+
vi.restoreAllMocks()
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('listSkills returns name + description from the index', async () => {
|
|
51
|
+
globalThis.fetch = mockFetch({
|
|
52
|
+
'https://raw.githubusercontent.com/Cold-IQ/coldiq-marketplace-skills/main/.well-known/agent-skills/index.json': {
|
|
53
|
+
body: JSON.stringify(INDEX),
|
|
54
|
+
},
|
|
55
|
+
}) as typeof fetch
|
|
56
|
+
const skills = await listSkills()
|
|
57
|
+
expect(skills).toHaveLength(2)
|
|
58
|
+
expect(skills[0]).toEqual({ name: 'contact-enrichment', description: 'Enrich contacts with emails and phones.' })
|
|
59
|
+
expect(skills.map((s) => s.name)).toContain('coldiq-search-enrich')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('honors COLDIQ_SKILLS_INDEX_URL override', async () => {
|
|
63
|
+
process.env.COLDIQ_SKILLS_INDEX_URL = 'https://custom/index.json'
|
|
64
|
+
globalThis.fetch = mockFetch({ 'https://custom/index.json': { body: JSON.stringify(INDEX) } }) as typeof fetch
|
|
65
|
+
const skills = await listSkills()
|
|
66
|
+
expect(skills).toHaveLength(2)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('caches the index (one network call across two listSkills)', async () => {
|
|
70
|
+
const f = mockFetch({
|
|
71
|
+
'https://raw.githubusercontent.com/Cold-IQ/coldiq-marketplace-skills/main/.well-known/agent-skills/index.json': {
|
|
72
|
+
body: JSON.stringify(INDEX),
|
|
73
|
+
},
|
|
74
|
+
})
|
|
75
|
+
globalThis.fetch = f as typeof fetch
|
|
76
|
+
await listSkills()
|
|
77
|
+
await listSkills()
|
|
78
|
+
expect(f).toHaveBeenCalledTimes(1)
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('loadSkill returns the body with referenced resources inlined', async () => {
|
|
82
|
+
globalThis.fetch = mockFetch({
|
|
83
|
+
'https://raw.githubusercontent.com/Cold-IQ/coldiq-marketplace-skills/main/.well-known/agent-skills/index.json': {
|
|
84
|
+
body: JSON.stringify(INDEX),
|
|
85
|
+
},
|
|
86
|
+
'https://raw.example/skills/contact-enrichment/SKILL.md': { body: BODY_WITH_RES },
|
|
87
|
+
'https://raw.example/skills/contact-enrichment/resources/async-job-pattern.md': { body: 'POLL LOOP DOC' },
|
|
88
|
+
'https://raw.example/skills/contact-enrichment/resources/credit-optimization.md': { body: 'CREDIT DOC' },
|
|
89
|
+
}) as typeof fetch
|
|
90
|
+
const doc = await loadSkill('contact-enrichment')
|
|
91
|
+
expect(doc).toContain('# Contact enrichment')
|
|
92
|
+
expect(doc).toContain('## Resource: resources/async-job-pattern.md')
|
|
93
|
+
expect(doc).toContain('POLL LOOP DOC')
|
|
94
|
+
expect(doc).toContain('## Resource: resources/credit-optimization.md')
|
|
95
|
+
expect(doc).toContain('CREDIT DOC')
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('loadSkill tolerates a missing resource (skips it, still returns body)', async () => {
|
|
99
|
+
globalThis.fetch = mockFetch({
|
|
100
|
+
'https://raw.githubusercontent.com/Cold-IQ/coldiq-marketplace-skills/main/.well-known/agent-skills/index.json': {
|
|
101
|
+
body: JSON.stringify(INDEX),
|
|
102
|
+
},
|
|
103
|
+
'https://raw.example/skills/contact-enrichment/SKILL.md': { body: BODY_WITH_RES },
|
|
104
|
+
// resources intentionally 404
|
|
105
|
+
}) as typeof fetch
|
|
106
|
+
const doc = await loadSkill('contact-enrichment')
|
|
107
|
+
expect(doc).toContain('# Contact enrichment')
|
|
108
|
+
expect(doc).not.toContain('POLL LOOP DOC')
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('loadSkill resolves folder≠name via the index url', async () => {
|
|
112
|
+
globalThis.fetch = mockFetch({
|
|
113
|
+
'https://raw.githubusercontent.com/Cold-IQ/coldiq-marketplace-skills/main/.well-known/agent-skills/index.json': {
|
|
114
|
+
body: JSON.stringify(INDEX),
|
|
115
|
+
},
|
|
116
|
+
'https://raw.example/skills/lima-data-api/SKILL.md': { body: '# Search & enrich\n' },
|
|
117
|
+
}) as typeof fetch
|
|
118
|
+
const doc = await loadSkill('coldiq-search-enrich')
|
|
119
|
+
expect(doc).toContain('# Search & enrich')
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('loadSkill throws a helpful error for an unknown skill', async () => {
|
|
123
|
+
globalThis.fetch = mockFetch({
|
|
124
|
+
'https://raw.githubusercontent.com/Cold-IQ/coldiq-marketplace-skills/main/.well-known/agent-skills/index.json': {
|
|
125
|
+
body: JSON.stringify(INDEX),
|
|
126
|
+
},
|
|
127
|
+
}) as typeof fetch
|
|
128
|
+
await expect(loadSkill('does-not-exist')).rejects.toThrow(/unknown skill/i)
|
|
129
|
+
})
|
|
130
|
+
})
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
|
2
|
+
import {
|
|
3
|
+
listSkillsHandler,
|
|
4
|
+
listSkillsName,
|
|
5
|
+
listSkillsSchema,
|
|
6
|
+
} from '../../src/tools/list-skills.js'
|
|
7
|
+
import { __resetSkillsCache } from '../../src/skills.js'
|
|
8
|
+
|
|
9
|
+
const INDEX_URL =
|
|
10
|
+
'https://raw.githubusercontent.com/Cold-IQ/coldiq-marketplace-skills/main/.well-known/agent-skills/index.json'
|
|
11
|
+
const originalFetch = globalThis.fetch
|
|
12
|
+
|
|
13
|
+
describe('list_skills handler', () => {
|
|
14
|
+
beforeEach(() => __resetSkillsCache())
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
globalThis.fetch = originalFetch
|
|
17
|
+
vi.restoreAllMocks()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('is a zero-arg tool', () => {
|
|
21
|
+
expect(listSkillsName).toBe('list_skills')
|
|
22
|
+
expect(listSkillsSchema).toEqual({})
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('returns the catalog as { data: [...] }', async () => {
|
|
26
|
+
globalThis.fetch = vi.fn(async () => ({
|
|
27
|
+
ok: true,
|
|
28
|
+
status: 200,
|
|
29
|
+
text: async () =>
|
|
30
|
+
JSON.stringify({ skills: [{ name: 'tam-scoring', description: 'Score a TAM.', url: 'https://x/SKILL.md' }] }),
|
|
31
|
+
})) as unknown as typeof fetch
|
|
32
|
+
const res = await listSkillsHandler({})
|
|
33
|
+
expect(res.isError).toBeFalsy()
|
|
34
|
+
const parsed = JSON.parse(res.content[0].text)
|
|
35
|
+
expect(parsed.data).toEqual([{ name: 'tam-scoring', description: 'Score a TAM.' }])
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('returns an error result (not a throw) when the index is unreachable', async () => {
|
|
39
|
+
globalThis.fetch = vi.fn(async () => ({ ok: false, status: 500, text: async () => 'err' })) as unknown as typeof fetch
|
|
40
|
+
const res = await listSkillsHandler({})
|
|
41
|
+
expect(res.isError).toBe(true)
|
|
42
|
+
expect(JSON.parse(res.content[0].text).error).toMatch(/could not load/i)
|
|
43
|
+
})
|
|
44
|
+
})
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
|
2
|
+
import { loadSkillHandler, loadSkillName, loadSkillSchema } from '../../src/tools/load-skill.js'
|
|
3
|
+
import { __resetSkillsCache } from '../../src/skills.js'
|
|
4
|
+
|
|
5
|
+
const INDEX_URL =
|
|
6
|
+
'https://raw.githubusercontent.com/Cold-IQ/coldiq-marketplace-skills/main/.well-known/agent-skills/index.json'
|
|
7
|
+
|
|
8
|
+
function mockFetch(map: Record<string, string>) {
|
|
9
|
+
return vi.fn(async (url: string | URL | Request) => {
|
|
10
|
+
const body = map[String(url)]
|
|
11
|
+
return { ok: body !== undefined, status: body !== undefined ? 200 : 404, text: async () => body ?? 'nf' } as Response
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
const originalFetch = globalThis.fetch
|
|
15
|
+
|
|
16
|
+
describe('load_skill handler', () => {
|
|
17
|
+
beforeEach(() => __resetSkillsCache())
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
globalThis.fetch = originalFetch
|
|
20
|
+
vi.restoreAllMocks()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('declares a required name arg', () => {
|
|
24
|
+
expect(loadSkillName).toBe('load_skill')
|
|
25
|
+
expect(Object.keys(loadSkillSchema)).toContain('name')
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('returns the skill body as text', async () => {
|
|
29
|
+
globalThis.fetch = mockFetch({
|
|
30
|
+
[INDEX_URL]: JSON.stringify({ skills: [{ name: 'apollo-search', description: 'd', url: 'https://x/skills/apollo-search/SKILL.md' }] }),
|
|
31
|
+
'https://x/skills/apollo-search/SKILL.md': '# Apollo search\nstep 1',
|
|
32
|
+
}) as typeof fetch
|
|
33
|
+
const res = await loadSkillHandler({ name: 'apollo-search' })
|
|
34
|
+
expect(res.isError).toBeFalsy()
|
|
35
|
+
expect(res.content[0].text).toContain('# Apollo search')
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('errors (not throws) on a missing name', async () => {
|
|
39
|
+
const res = await loadSkillHandler({})
|
|
40
|
+
expect(res.isError).toBe(true)
|
|
41
|
+
expect(res.content[0].text).toMatch(/list_skills/)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('errors with the available list on an unknown skill', async () => {
|
|
45
|
+
globalThis.fetch = mockFetch({
|
|
46
|
+
[INDEX_URL]: JSON.stringify({ skills: [{ name: 'apollo-search', description: 'd', url: 'https://x/SKILL.md' }] }),
|
|
47
|
+
}) as typeof fetch
|
|
48
|
+
const res = await loadSkillHandler({ name: 'nope' })
|
|
49
|
+
expect(res.isError).toBe(true)
|
|
50
|
+
expect(res.content[0].text).toMatch(/unknown skill/i)
|
|
51
|
+
expect(res.content[0].text).toMatch(/apollo-search/)
|
|
52
|
+
})
|
|
53
|
+
})
|