@coldiq/mcp 0.3.15 → 0.3.16

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 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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"}
@@ -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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coldiq/mcp",
3
- "version": "0.3.15",
3
+ "version": "0.3.16",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
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
+ }
@@ -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
+ })