@coldiq/mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.ts +8 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +47 -0
- package/dist/client.js.map +1 -0
- package/dist/executor.d.ts +21 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +130 -0
- package/dist/executor.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/registry.d.ts +49 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +3104 -0
- package/dist/registry.js.map +1 -0
- package/dist/tools/enrich-company.d.ts +22 -0
- package/dist/tools/enrich-company.d.ts.map +1 -0
- package/dist/tools/enrich-company.js +21 -0
- package/dist/tools/enrich-company.js.map +1 -0
- package/dist/tools/enrich-email.d.ts +24 -0
- package/dist/tools/enrich-email.d.ts.map +1 -0
- package/dist/tools/enrich-email.js +19 -0
- package/dist/tools/enrich-email.js.map +1 -0
- package/dist/tools/enrich-emails.d.ts +31 -0
- package/dist/tools/enrich-emails.d.ts.map +1 -0
- package/dist/tools/enrich-emails.js +146 -0
- package/dist/tools/enrich-emails.js.map +1 -0
- package/dist/tools/enrich-person.d.ts +26 -0
- package/dist/tools/enrich-person.d.ts.map +1 -0
- package/dist/tools/enrich-person.js +23 -0
- package/dist/tools/enrich-person.js.map +1 -0
- package/dist/tools/fetch-page-content.d.ts +22 -0
- package/dist/tools/fetch-page-content.d.ts.map +1 -0
- package/dist/tools/fetch-page-content.js +32 -0
- package/dist/tools/fetch-page-content.js.map +1 -0
- package/dist/tools/find-email.d.ts +24 -0
- package/dist/tools/find-email.d.ts.map +1 -0
- package/dist/tools/find-email.js +19 -0
- package/dist/tools/find-email.js.map +1 -0
- package/dist/tools/find-emails.d.ts +31 -0
- package/dist/tools/find-emails.d.ts.map +1 -0
- package/dist/tools/find-emails.js +146 -0
- package/dist/tools/find-emails.js.map +1 -0
- package/dist/tools/find-influencers.d.ts +29 -0
- package/dist/tools/find-influencers.d.ts.map +1 -0
- package/dist/tools/find-influencers.js +30 -0
- package/dist/tools/find-influencers.js.map +1 -0
- package/dist/tools/find-people.d.ts +26 -0
- package/dist/tools/find-people.d.ts.map +1 -0
- package/dist/tools/find-people.js +61 -0
- package/dist/tools/find-people.js.map +1 -0
- package/dist/tools/find-phone.d.ts +24 -0
- package/dist/tools/find-phone.d.ts.map +1 -0
- package/dist/tools/find-phone.js +48 -0
- package/dist/tools/find-phone.js.map +1 -0
- package/dist/tools/find-signals.d.ts +26 -0
- package/dist/tools/find-signals.d.ts.map +1 -0
- package/dist/tools/find-signals.js +82 -0
- package/dist/tools/find-signals.js.map +1 -0
- package/dist/tools/search-ads.d.ts +33 -0
- package/dist/tools/search-ads.d.ts.map +1 -0
- package/dist/tools/search-ads.js +33 -0
- package/dist/tools/search-ads.js.map +1 -0
- package/dist/tools/search-companies.d.ts +42 -0
- package/dist/tools/search-companies.d.ts.map +1 -0
- package/dist/tools/search-companies.js +37 -0
- package/dist/tools/search-companies.js.map +1 -0
- package/dist/tools/search-jobs.d.ts +51 -0
- package/dist/tools/search-jobs.d.ts.map +1 -0
- package/dist/tools/search-jobs.js +64 -0
- package/dist/tools/search-jobs.js.map +1 -0
- package/dist/tools/search-places.d.ts +47 -0
- package/dist/tools/search-places.d.ts.map +1 -0
- package/dist/tools/search-places.js +42 -0
- package/dist/tools/search-places.js.map +1 -0
- package/dist/tools/search-reddit.d.ts +27 -0
- package/dist/tools/search-reddit.d.ts.map +1 -0
- package/dist/tools/search-reddit.js +30 -0
- package/dist/tools/search-reddit.js.map +1 -0
- package/dist/tools/search-seo.d.ts +37 -0
- package/dist/tools/search-seo.d.ts.map +1 -0
- package/dist/tools/search-seo.js +49 -0
- package/dist/tools/search-seo.js.map +1 -0
- package/dist/tools/search-web.d.ts +23 -0
- package/dist/tools/search-web.d.ts.map +1 -0
- package/dist/tools/search-web.js +20 -0
- package/dist/tools/search-web.js.map +1 -0
- package/dist/tools/verify-email.d.ts +20 -0
- package/dist/tools/verify-email.d.ts.map +1 -0
- package/dist/tools/verify-email.js +15 -0
- package/dist/tools/verify-email.js.map +1 -0
- package/package.json +28 -0
- package/src/client.ts +60 -0
- package/src/executor.ts +182 -0
- package/src/index.ts +155 -0
- package/src/registry.ts +3159 -0
- package/src/tools/enrich-company.ts +25 -0
- package/src/tools/enrich-person.ts +27 -0
- package/src/tools/fetch-page-content.ts +36 -0
- package/src/tools/find-email.ts +23 -0
- package/src/tools/find-emails.ts +190 -0
- package/src/tools/find-influencers.ts +34 -0
- package/src/tools/find-people.ts +69 -0
- package/src/tools/find-phone.ts +53 -0
- package/src/tools/find-signals.ts +93 -0
- package/src/tools/search-ads.ts +44 -0
- package/src/tools/search-companies.ts +41 -0
- package/src/tools/search-jobs.ts +73 -0
- package/src/tools/search-places.ts +52 -0
- package/src/tools/search-reddit.ts +34 -0
- package/src/tools/search-seo.ts +59 -0
- package/src/tools/search-web.ts +24 -0
- package/src/tools/verify-email.ts +19 -0
- package/test-ads-live.ts +77 -0
- package/test-company-live.ts +91 -0
- package/test-email-live.ts +171 -0
- package/test-influencers-live.ts +66 -0
- package/test-jobs-live.ts +69 -0
- package/test-linkupapi-live.ts +137 -0
- package/test-phone-live.ts +41 -0
- package/test-places-live.ts +89 -0
- package/test-reddit-live.ts +66 -0
- package/test-search-live.ts +79 -0
- package/test-seo-live.ts +68 -0
- package/test-web-live.ts +67 -0
- package/tests/client.test.ts +90 -0
- package/tests/executor.test.ts +83 -0
- package/tests/gtm/01-icp-to-emails.test.ts +43 -0
- package/tests/gtm/02-icp-bulk-emails.test.ts +38 -0
- package/tests/gtm/03-icp-to-phones.test.ts +39 -0
- package/tests/gtm/04-funding-signal-outreach.test.ts +42 -0
- package/tests/gtm/05-hiring-signal-decisionmakers.test.ts +41 -0
- package/tests/gtm/06-intent-signal-outreach.test.ts +44 -0
- package/tests/gtm/07-places-to-content.test.ts +50 -0
- package/tests/gtm/08-domain-to-account.test.ts +44 -0
- package/tests/gtm/09-linkedin-to-everything.test.ts +41 -0
- package/tests/gtm/10-jobs-vs-signals-routing.test.ts +38 -0
- package/tests/gtm/11-find-vs-enrich-routing.test.ts +39 -0
- package/tests/gtm/12-bogus-domain-graceful.test.ts +42 -0
- package/tests/gtm/13-private-linkedin-graceful.test.ts +44 -0
- package/tests/gtm/14-empty-handoff.test.ts +43 -0
- package/tests/gtm/15-seo-reddit-research.test.ts +38 -0
- package/tests/gtm/README.md +59 -0
- package/tests/gtm/harness.ts +217 -0
- package/tests/gtm/tools-bridge.ts +232 -0
- package/tests/gtm-scenarios.md +32 -0
- package/tests/live/smoke-report.ts +255 -0
- package/tests/live/smoke.test.ts +134 -0
- package/tests/registry-enrich-person.test.ts +447 -0
- package/tests/registry-fetch-page-content.test.ts +90 -0
- package/tests/registry-find-people.test.ts +467 -0
- package/tests/registry-find-signals.test.ts +470 -0
- package/tests/registry-linkupapi.test.ts +331 -0
- package/tests/registry-search-companies.test.ts +188 -0
- package/tests/registry-search-jobs.test.ts +116 -0
- package/tests/registry.test.ts +2210 -0
- package/tests/tools/enrich-company.test.ts +92 -0
- package/tests/tools/enrich-email.test.ts +94 -0
- package/tests/tools/enrich-emails.test.ts +271 -0
- package/tests/tools/enrich-person.test.ts +140 -0
- package/tests/tools/fetch-page-content.test.ts +108 -0
- package/tests/tools/find-influencers.test.ts +91 -0
- package/tests/tools/find-people.test.ts +344 -0
- package/tests/tools/find-phone.test.ts +100 -0
- package/tests/tools/find-signals.test.ts +110 -0
- package/tests/tools/search-ads.test.ts +182 -0
- package/tests/tools/search-companies.test.ts +58 -0
- package/tests/tools/search-jobs.test.ts +210 -0
- package/tests/tools/search-places.test.ts +114 -0
- package/tests/tools/search-reddit.test.ts +125 -0
- package/tests/tools/search-seo.test.ts +183 -0
- package/tests/tools/search-web.test.ts +79 -0
- package/tests/tools/verify-email.test.ts +68 -0
- package/tsconfig.json +17 -0
- package/vitest.config.ts +7 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const searchSeoName = "search_seo";
|
|
3
|
+
export declare const searchSeoDescription: string;
|
|
4
|
+
export declare const searchSeoSchema: {
|
|
5
|
+
category: z.ZodEnum<["keywords", "serp", "backlinks", "domain", "labs", "page"]>;
|
|
6
|
+
target: z.ZodOptional<z.ZodString>;
|
|
7
|
+
keyword: z.ZodOptional<z.ZodString>;
|
|
8
|
+
keywords: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
9
|
+
location: z.ZodOptional<z.ZodString>;
|
|
10
|
+
language: z.ZodOptional<z.ZodString>;
|
|
11
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
12
|
+
date_from: z.ZodOptional<z.ZodString>;
|
|
13
|
+
date_to: z.ZodOptional<z.ZodString>;
|
|
14
|
+
time_range: z.ZodOptional<z.ZodString>;
|
|
15
|
+
engine: z.ZodDefault<z.ZodEnum<["google", "bing", "youtube"]>>;
|
|
16
|
+
device: z.ZodOptional<z.ZodEnum<["desktop", "mobile"]>>;
|
|
17
|
+
action: z.ZodOptional<z.ZodEnum<["technologies", "whois"]>>;
|
|
18
|
+
lab_action: z.ZodOptional<z.ZodEnum<["ranked-keywords", "competitors", "keyword-ideas", "rank-overview"]>>;
|
|
19
|
+
url: z.ZodOptional<z.ZodString>;
|
|
20
|
+
page_action: z.ZodDefault<z.ZodEnum<["lighthouse", "content"]>>;
|
|
21
|
+
enable_javascript: z.ZodOptional<z.ZodBoolean>;
|
|
22
|
+
full_data: z.ZodOptional<z.ZodBoolean>;
|
|
23
|
+
};
|
|
24
|
+
export declare function searchSeoHandler(input: Record<string, unknown>): Promise<{
|
|
25
|
+
content: {
|
|
26
|
+
type: "text";
|
|
27
|
+
text: string;
|
|
28
|
+
}[];
|
|
29
|
+
isError: boolean;
|
|
30
|
+
} | {
|
|
31
|
+
content: {
|
|
32
|
+
type: "text";
|
|
33
|
+
text: string;
|
|
34
|
+
}[];
|
|
35
|
+
isError?: undefined;
|
|
36
|
+
}>;
|
|
37
|
+
//# sourceMappingURL=search-seo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-seo.d.ts","sourceRoot":"","sources":["../../src/tools/search-seo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,aAAa,eAAe,CAAA;AAEzC,eAAO,MAAM,oBAAoB,QAQiD,CAAA;AAElF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;CAmC3B,CAAA;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;GAMpE"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { executeWithFallback, isExecutionError } from '../executor.js';
|
|
3
|
+
export const searchSeoName = 'search_seo';
|
|
4
|
+
export const searchSeoDescription = 'Search SEO data — 6 categories. Pick category + required fields:\n' +
|
|
5
|
+
'• keywords: pass keywords[] — search volume or trends\n' +
|
|
6
|
+
'• serp: pass keyword (single string) — Google/Bing/YouTube organic results\n' +
|
|
7
|
+
'• backlinks: pass target (domain or URL) — summary, links, referring domains\n' +
|
|
8
|
+
'• domain: pass target + action ("technologies" | "whois")\n' +
|
|
9
|
+
'• labs: pass target for rank-overview/competitors/ranked-keywords; OR pass keywords[] for keyword-ideas\n' +
|
|
10
|
+
'• page: pass url + page_action ("lighthouse" | "content")\n' +
|
|
11
|
+
'Optional shared: location, language, limit. All sync. Cost varies by endpoint.';
|
|
12
|
+
export const searchSeoSchema = {
|
|
13
|
+
category: z.enum(['keywords', 'serp', 'backlinks', 'domain', 'labs', 'page'])
|
|
14
|
+
.describe('Which SEO category to use. Required.'),
|
|
15
|
+
target: z.string().optional()
|
|
16
|
+
.describe('Domain or URL. Required for: backlinks, domain, labs.'),
|
|
17
|
+
keyword: z.string().optional()
|
|
18
|
+
.describe('Single keyword. Required for: serp.'),
|
|
19
|
+
keywords: z.array(z.string()).optional()
|
|
20
|
+
.describe('Keyword list. Required for: keywords/search-volume, labs/keyword-ideas.'),
|
|
21
|
+
location: z.string().optional()
|
|
22
|
+
.describe('Location name e.g. "United States", "London,England,United Kingdom".'),
|
|
23
|
+
language: z.string().optional()
|
|
24
|
+
.describe('Language code e.g. "en".'),
|
|
25
|
+
limit: z.number().int().min(1).max(700).default(10),
|
|
26
|
+
date_from: z.string().optional().describe('YYYY-MM-DD. keywords/trends.'),
|
|
27
|
+
date_to: z.string().optional().describe('YYYY-MM-DD. keywords/trends.'),
|
|
28
|
+
time_range: z.string().optional().describe('keywords/trends: "past_7_days", "past_30_days", etc.'),
|
|
29
|
+
engine: z.enum(['google', 'bing', 'youtube']).default('google'),
|
|
30
|
+
device: z.enum(['desktop', 'mobile']).optional(),
|
|
31
|
+
action: z.enum(['technologies', 'whois']).optional()
|
|
32
|
+
.describe('domain: "technologies" (tech stack) or "whois". Default: technologies.'),
|
|
33
|
+
lab_action: z.enum(['ranked-keywords', 'competitors', 'keyword-ideas', 'rank-overview']).optional()
|
|
34
|
+
.describe('labs action. Default: rank-overview when target set; keyword-ideas when keywords[] set.'),
|
|
35
|
+
url: z.string().url().optional()
|
|
36
|
+
.describe('Full URL to analyze. Required for page category.'),
|
|
37
|
+
page_action: z.enum(['lighthouse', 'content']).default('lighthouse')
|
|
38
|
+
.describe('page: "lighthouse" (Core Web Vitals audit) or "content" (parse page text).'),
|
|
39
|
+
enable_javascript: z.boolean().optional(),
|
|
40
|
+
full_data: z.boolean().optional().describe('Lighthouse only: include full audit data.'),
|
|
41
|
+
};
|
|
42
|
+
export async function searchSeoHandler(input) {
|
|
43
|
+
const result = await executeWithFallback('search_seo', input);
|
|
44
|
+
if (isExecutionError(result)) {
|
|
45
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], isError: true };
|
|
46
|
+
}
|
|
47
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=search-seo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-seo.js","sourceRoot":"","sources":["../../src/tools/search-seo.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const searchWebName = "search_web";
|
|
3
|
+
export declare const searchWebDescription: string;
|
|
4
|
+
export declare const searchWebSchema: {
|
|
5
|
+
query: z.ZodString;
|
|
6
|
+
num_results: z.ZodDefault<z.ZodNumber>;
|
|
7
|
+
country: z.ZodOptional<z.ZodString>;
|
|
8
|
+
search_type: z.ZodDefault<z.ZodEnum<["general", "neural"]>>;
|
|
9
|
+
};
|
|
10
|
+
export declare function searchWebHandler(input: Record<string, unknown>): Promise<{
|
|
11
|
+
content: {
|
|
12
|
+
type: "text";
|
|
13
|
+
text: string;
|
|
14
|
+
}[];
|
|
15
|
+
isError: boolean;
|
|
16
|
+
} | {
|
|
17
|
+
content: {
|
|
18
|
+
type: "text";
|
|
19
|
+
text: string;
|
|
20
|
+
}[];
|
|
21
|
+
isError?: undefined;
|
|
22
|
+
}>;
|
|
23
|
+
//# sourceMappingURL=search-web.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-web.d.ts","sourceRoot":"","sources":["../../src/tools/search-web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,aAAa,eAAe,CAAA;AAEzC,eAAO,MAAM,oBAAoB,QAGoE,CAAA;AAErG,eAAO,MAAM,eAAe;;;;;CAK3B,CAAA;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;GAMpE"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { executeWithFallback, isExecutionError } from '../executor.js';
|
|
3
|
+
export const searchWebName = 'search_web';
|
|
4
|
+
export const searchWebDescription = 'Search the web for market research, company news, or general lookups. Supports Google search (default) and neural/semantic search via Exa. ' +
|
|
5
|
+
'NEVER use this to find, verify, or look up people, contacts, LinkedIn profiles, or executives — even as a fallback when find_people returns uncertain results. ' +
|
|
6
|
+
'find_people is the only tool for people lookups; do not supplement or replace it with web search.';
|
|
7
|
+
export const searchWebSchema = {
|
|
8
|
+
query: z.string().describe('Search query'),
|
|
9
|
+
num_results: z.number().min(1).max(100).default(10).describe('Number of results (default: 10, max: 100)'),
|
|
10
|
+
country: z.string().optional().describe('Country code for geo-targeting (e.g. "us", "fr")'),
|
|
11
|
+
search_type: z.enum(['general', 'neural']).default('general').describe('"general" for Google search (default), "neural" for semantic search via Exa'),
|
|
12
|
+
};
|
|
13
|
+
export async function searchWebHandler(input) {
|
|
14
|
+
const result = await executeWithFallback('search_web', input);
|
|
15
|
+
if (isExecutionError(result)) {
|
|
16
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], isError: true };
|
|
17
|
+
}
|
|
18
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=search-web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-web.js","sourceRoot":"","sources":["../../src/tools/search-web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAEtE,MAAM,CAAC,MAAM,aAAa,GAAG,YAAY,CAAA;AAEzC,MAAM,CAAC,MAAM,oBAAoB,GAC/B,6IAA6I;IAC7I,iKAAiK;IACjK,mGAAmG,CAAA;AAErG,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;IAC1C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,2CAA2C,CAAC;IACzG,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kDAAkD,CAAC;IAC3F,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,6EAA6E,CAAC;CACtJ,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAA8B;IACnE,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;IAC7D,IAAI,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IACvG,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAA;AACxF,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const verifyEmailName = "verify_email";
|
|
3
|
+
export declare const verifyEmailDescription = "Check whether an email address is valid and deliverable. Returns verification status (valid, invalid, catch-all, unknown). Use before cold outreach to protect sender reputation.";
|
|
4
|
+
export declare const verifyEmailSchema: {
|
|
5
|
+
email: z.ZodString;
|
|
6
|
+
};
|
|
7
|
+
export declare function verifyEmailHandler(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=verify-email.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-email.d.ts","sourceRoot":"","sources":["../../src/tools/verify-email.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,eAAe,iBAAiB,CAAA;AAE7C,eAAO,MAAM,sBAAsB,sLACkJ,CAAA;AAErL,eAAO,MAAM,iBAAiB;;CAE7B,CAAA;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;GAMtE"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { executeWithFallback, isExecutionError } from '../executor.js';
|
|
3
|
+
export const verifyEmailName = 'verify_email';
|
|
4
|
+
export const verifyEmailDescription = 'Check whether an email address is valid and deliverable. Returns verification status (valid, invalid, catch-all, unknown). Use before cold outreach to protect sender reputation.';
|
|
5
|
+
export const verifyEmailSchema = {
|
|
6
|
+
email: z.string().email().describe('Email address to verify'),
|
|
7
|
+
};
|
|
8
|
+
export async function verifyEmailHandler(input) {
|
|
9
|
+
const result = await executeWithFallback('verify_email', input);
|
|
10
|
+
if (isExecutionError(result)) {
|
|
11
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], isError: true };
|
|
12
|
+
}
|
|
13
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=verify-email.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-email.js","sourceRoot":"","sources":["../../src/tools/verify-email.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAEtE,MAAM,CAAC,MAAM,eAAe,GAAG,cAAc,CAAA;AAE7C,MAAM,CAAC,MAAM,sBAAsB,GACjC,mLAAmL,CAAA;AAErL,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,yBAAyB,CAAC;CAC9D,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAA8B;IACrE,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,cAAc,EAAE,KAAK,CAAC,CAAA;IAC/D,IAAI,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IACvG,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAA;AACxF,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@coldiq/mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"coldiq-mcp": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"dev": "tsx src/index.ts",
|
|
12
|
+
"test": "vitest run",
|
|
13
|
+
"test:watch": "vitest",
|
|
14
|
+
"test:gtm": "LIVE_TESTS=1 vitest run tests/gtm",
|
|
15
|
+
"test:gtm:one": "LIVE_TESTS=1 vitest run"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
19
|
+
"zod": "^3.24.2"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@anthropic-ai/sdk": "^0.52.0",
|
|
23
|
+
"tsx": "^4.19.3",
|
|
24
|
+
"typescript": "^5.8.2",
|
|
25
|
+
"vitest": "^3.1.3",
|
|
26
|
+
"zod-to-json-schema": "^3.25.0"
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export type ApiResponse = {
|
|
2
|
+
ok: boolean
|
|
3
|
+
status: number
|
|
4
|
+
data: unknown
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
let _apiUrl: string
|
|
8
|
+
let _apiKey: string
|
|
9
|
+
|
|
10
|
+
export function initClient(apiUrl?: string, apiKey?: string): void {
|
|
11
|
+
_apiUrl = apiUrl ?? process.env.COLDIQ_API_URL ?? 'https://api.coldiq.com'
|
|
12
|
+
_apiKey = apiKey ?? process.env.COLDIQ_API_KEY ?? ''
|
|
13
|
+
if (!_apiKey) {
|
|
14
|
+
throw new Error('COLDIQ_API_KEY is required — set it in .mcp.json env or as an environment variable')
|
|
15
|
+
}
|
|
16
|
+
// Strip trailing slash
|
|
17
|
+
_apiUrl = _apiUrl.replace(/\/+$/, '')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function callApi(
|
|
21
|
+
method: 'GET' | 'POST',
|
|
22
|
+
path: string,
|
|
23
|
+
body?: unknown,
|
|
24
|
+
queryParams?: Record<string, string>,
|
|
25
|
+
): Promise<ApiResponse> {
|
|
26
|
+
const url = new URL(`${_apiUrl}/v1${path}`)
|
|
27
|
+
if (queryParams) {
|
|
28
|
+
for (const [k, v] of Object.entries(queryParams)) {
|
|
29
|
+
if (v !== undefined && v !== '') url.searchParams.set(k, v)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const headers: Record<string, string> = {
|
|
34
|
+
Authorization: `Bearer ${_apiKey}`,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const init: RequestInit = { method, headers }
|
|
38
|
+
|
|
39
|
+
if (method === 'POST' && body !== undefined) {
|
|
40
|
+
headers['Content-Type'] = 'application/json'
|
|
41
|
+
init.body = JSON.stringify(body)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const res = await fetch(url.toString(), init)
|
|
46
|
+
let data: unknown
|
|
47
|
+
try {
|
|
48
|
+
data = await res.json()
|
|
49
|
+
} catch {
|
|
50
|
+
data = { error: 'Non-JSON response from API' }
|
|
51
|
+
}
|
|
52
|
+
return { ok: res.ok, status: res.status, data }
|
|
53
|
+
} catch (err) {
|
|
54
|
+
return {
|
|
55
|
+
ok: false,
|
|
56
|
+
status: 0,
|
|
57
|
+
data: { error: err instanceof Error ? err.message : String(err) },
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
package/src/executor.ts
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { callApi } from './client.js'
|
|
2
|
+
import { getProviders, getSearchWebProviders } from './registry.js'
|
|
3
|
+
import type { Capability, ProviderEntry } from './registry.js'
|
|
4
|
+
|
|
5
|
+
export interface ExecutionResult {
|
|
6
|
+
data: unknown
|
|
7
|
+
_meta: {
|
|
8
|
+
provider: string
|
|
9
|
+
latencyMs: number
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ExecutionError {
|
|
14
|
+
error: string
|
|
15
|
+
providers_tried: Array<{ id: string; status: number; error: string }>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function isExecutionError(result: ExecutionResult | ExecutionError): result is ExecutionError {
|
|
19
|
+
return 'error' in result && 'providers_tried' in result
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { isExecutionError }
|
|
23
|
+
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Logging — user-facing vs developer debug
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
/** User-facing logs: which provider was picked, success/failure */
|
|
29
|
+
function log(msg: string): void {
|
|
30
|
+
console.error(`[coldiq] ${msg}`)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Developer debug logs: polling details, internals. Set COLDIQ_DEBUG=1 to enable. */
|
|
34
|
+
function debug(msg: string): void {
|
|
35
|
+
if (process.env.COLDIQ_DEBUG) {
|
|
36
|
+
console.error(`[coldiq:debug] ${msg}`)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Async polling
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
async function executeAsync(
|
|
45
|
+
provider: ProviderEntry,
|
|
46
|
+
payload: { body?: unknown; queryParams?: Record<string, string> },
|
|
47
|
+
): Promise<{ ok: boolean; data: unknown }> {
|
|
48
|
+
const asyncCfg = provider.async!
|
|
49
|
+
|
|
50
|
+
// Step 1: create the job
|
|
51
|
+
debug(`${provider.id} async: creating job...`)
|
|
52
|
+
const createRes = await callApi(provider.method, provider.endpoint, payload.body, payload.queryParams)
|
|
53
|
+
if (!createRes.ok) {
|
|
54
|
+
debug(`${provider.id} async: create failed (${createRes.status})`)
|
|
55
|
+
return createRes
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Step 2: extract job ID
|
|
59
|
+
let jobId: string
|
|
60
|
+
try {
|
|
61
|
+
jobId = asyncCfg.extractId(createRes.data)
|
|
62
|
+
} catch {
|
|
63
|
+
return { ok: false, data: { error: 'Could not extract job ID from async response' } }
|
|
64
|
+
}
|
|
65
|
+
if (!jobId) return { ok: false, data: { error: 'Empty job ID from async response' } }
|
|
66
|
+
debug(`${provider.id} async: job created (${jobId}), polling...`)
|
|
67
|
+
|
|
68
|
+
// Step 3: poll until complete or timeout
|
|
69
|
+
const deadline = Date.now() + asyncCfg.timeoutMs
|
|
70
|
+
let pollCount = 0
|
|
71
|
+
while (Date.now() < deadline) {
|
|
72
|
+
await sleep(asyncCfg.pollIntervalMs)
|
|
73
|
+
pollCount++
|
|
74
|
+
|
|
75
|
+
const pollRes = await callApi('GET', asyncCfg.pollEndpoint(jobId))
|
|
76
|
+
if (!pollRes.ok) continue // transient poll errors — retry
|
|
77
|
+
|
|
78
|
+
const status = (pollRes.data as Record<string, unknown>).status ?? 'unknown'
|
|
79
|
+
const progress = (pollRes.data as Record<string, unknown>).progress_percentage ?? '?'
|
|
80
|
+
debug(`${provider.id} async: poll #${pollCount} — status=${status}, progress=${progress}%`)
|
|
81
|
+
|
|
82
|
+
if (asyncCfg.isComplete(pollRes.data)) {
|
|
83
|
+
debug(`${provider.id} async: complete`)
|
|
84
|
+
return pollRes
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
debug(`${provider.id} async: timed out after ${asyncCfg.timeoutMs / 1000}s`)
|
|
89
|
+
return { ok: false, data: { error: `Async operation timed out after ${asyncCfg.timeoutMs / 1000}s` } }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function sleep(ms: number): Promise<void> {
|
|
93
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// Execute a single provider
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
|
|
100
|
+
async function executeSingle(
|
|
101
|
+
provider: ProviderEntry,
|
|
102
|
+
input: Record<string, unknown>,
|
|
103
|
+
): Promise<{ ok: boolean; status: number; data: unknown; latencyMs: number }> {
|
|
104
|
+
const start = Date.now()
|
|
105
|
+
const payload = provider.mapParams(input)
|
|
106
|
+
|
|
107
|
+
debug(`${provider.id}: payload = ${JSON.stringify(payload)}`)
|
|
108
|
+
|
|
109
|
+
let result: { ok: boolean; status: number; data: unknown }
|
|
110
|
+
|
|
111
|
+
if (provider.async) {
|
|
112
|
+
const asyncResult = await executeAsync(provider, payload)
|
|
113
|
+
result = { ...asyncResult, status: asyncResult.ok ? 200 : 500 }
|
|
114
|
+
} else {
|
|
115
|
+
result = await callApi(provider.method, provider.endpoint, payload.body, payload.queryParams)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return { ...result, latencyMs: Date.now() - start }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
// Fallback execution — try providers in order, return first success
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
export async function executeWithFallback(
|
|
126
|
+
capability: Capability,
|
|
127
|
+
input: Record<string, unknown>,
|
|
128
|
+
): Promise<ExecutionResult | ExecutionError> {
|
|
129
|
+
const providers =
|
|
130
|
+
capability === 'search_web'
|
|
131
|
+
? getSearchWebProviders(input.search_type === 'neural')
|
|
132
|
+
: getProviders(capability)
|
|
133
|
+
|
|
134
|
+
const errors: ExecutionError['providers_tried'] = []
|
|
135
|
+
|
|
136
|
+
for (const provider of providers) {
|
|
137
|
+
if (provider.isApplicable && !provider.isApplicable(input)) {
|
|
138
|
+
debug(`${capability} → skipping ${provider.id} (input not applicable)`)
|
|
139
|
+
continue
|
|
140
|
+
}
|
|
141
|
+
log(`${capability} → trying ${provider.id}`)
|
|
142
|
+
const result = await executeSingle(provider, input)
|
|
143
|
+
|
|
144
|
+
let payload = result.data
|
|
145
|
+
if (result.ok && provider.postFilter) {
|
|
146
|
+
payload = provider.postFilter(payload, input)
|
|
147
|
+
}
|
|
148
|
+
if (result.ok && provider.hasResult(payload)) {
|
|
149
|
+
log(`${capability} → ${provider.id} ✓ (${result.latencyMs}ms)`)
|
|
150
|
+
return { data: payload, _meta: { provider: provider.id, latencyMs: result.latencyMs } }
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Record the failure
|
|
154
|
+
const rawErr = result.data && typeof result.data === 'object' && 'error' in result.data
|
|
155
|
+
? (result.data as Record<string, unknown>).error
|
|
156
|
+
: undefined
|
|
157
|
+
const errMsg = rawErr !== undefined
|
|
158
|
+
? (typeof rawErr === 'string' ? rawErr : JSON.stringify(rawErr))
|
|
159
|
+
: `Status ${result.status}, no results`
|
|
160
|
+
log(`${capability} → ${provider.id} ✗ ${errMsg}`)
|
|
161
|
+
errors.push({ id: provider.id, status: result.status, error: errMsg })
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
error: `All ${errors.length} providers failed for ${capability}`,
|
|
166
|
+
providers_tried: errors,
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
// Waterfall execution — try providers until one returns a result
|
|
172
|
+
// Used for enrich_email: stop on first provider that finds an email
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
|
|
175
|
+
export async function executeWaterfall(
|
|
176
|
+
capability: Capability,
|
|
177
|
+
input: Record<string, unknown>,
|
|
178
|
+
): Promise<ExecutionResult | ExecutionError> {
|
|
179
|
+
// Waterfall is functionally the same as fallback — try each until one succeeds
|
|
180
|
+
// The distinction is semantic: waterfall means "I expect most to fail, stop on first hit"
|
|
181
|
+
return executeWithFallback(capability, input)
|
|
182
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
4
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
5
|
+
import { initClient } from './client.js'
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
searchCompaniesName,
|
|
9
|
+
searchCompaniesDescription,
|
|
10
|
+
searchCompaniesSchema,
|
|
11
|
+
searchCompaniesHandler,
|
|
12
|
+
} from './tools/search-companies.js'
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
findPeopleName,
|
|
16
|
+
findPeopleDescription,
|
|
17
|
+
findPeopleSchema,
|
|
18
|
+
findPeopleHandler,
|
|
19
|
+
} from './tools/find-people.js'
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
findEmailName,
|
|
23
|
+
findEmailDescription,
|
|
24
|
+
findEmailSchema,
|
|
25
|
+
findEmailHandler,
|
|
26
|
+
} from './tools/find-email.js'
|
|
27
|
+
|
|
28
|
+
import {
|
|
29
|
+
enrichPersonName,
|
|
30
|
+
enrichPersonDescription,
|
|
31
|
+
enrichPersonSchema,
|
|
32
|
+
enrichPersonHandler,
|
|
33
|
+
} from './tools/enrich-person.js'
|
|
34
|
+
|
|
35
|
+
import {
|
|
36
|
+
findEmailsName,
|
|
37
|
+
findEmailsDescription,
|
|
38
|
+
findEmailsSchema,
|
|
39
|
+
findEmailsHandler,
|
|
40
|
+
} from './tools/find-emails.js'
|
|
41
|
+
|
|
42
|
+
import {
|
|
43
|
+
verifyEmailName,
|
|
44
|
+
verifyEmailDescription,
|
|
45
|
+
verifyEmailSchema,
|
|
46
|
+
verifyEmailHandler,
|
|
47
|
+
} from './tools/verify-email.js'
|
|
48
|
+
|
|
49
|
+
import {
|
|
50
|
+
findPhoneName,
|
|
51
|
+
findPhoneDescription,
|
|
52
|
+
findPhoneSchema,
|
|
53
|
+
findPhoneHandler,
|
|
54
|
+
} from './tools/find-phone.js'
|
|
55
|
+
|
|
56
|
+
import {
|
|
57
|
+
enrichCompanyName,
|
|
58
|
+
enrichCompanyDescription,
|
|
59
|
+
enrichCompanySchema,
|
|
60
|
+
enrichCompanyHandler,
|
|
61
|
+
} from './tools/enrich-company.js'
|
|
62
|
+
|
|
63
|
+
import {
|
|
64
|
+
searchWebName,
|
|
65
|
+
searchWebDescription,
|
|
66
|
+
searchWebSchema,
|
|
67
|
+
searchWebHandler,
|
|
68
|
+
} from './tools/search-web.js'
|
|
69
|
+
|
|
70
|
+
import {
|
|
71
|
+
searchJobsName,
|
|
72
|
+
searchJobsDescription,
|
|
73
|
+
searchJobsSchema,
|
|
74
|
+
searchJobsHandler,
|
|
75
|
+
} from './tools/search-jobs.js'
|
|
76
|
+
|
|
77
|
+
import {
|
|
78
|
+
searchAdsName,
|
|
79
|
+
searchAdsDescription,
|
|
80
|
+
searchAdsSchema,
|
|
81
|
+
searchAdsHandler,
|
|
82
|
+
} from './tools/search-ads.js'
|
|
83
|
+
|
|
84
|
+
import {
|
|
85
|
+
searchPlacesName,
|
|
86
|
+
searchPlacesDescription,
|
|
87
|
+
searchPlacesSchema,
|
|
88
|
+
searchPlacesHandler,
|
|
89
|
+
} from './tools/search-places.js'
|
|
90
|
+
|
|
91
|
+
import {
|
|
92
|
+
findInfluencersName,
|
|
93
|
+
findInfluencersDescription,
|
|
94
|
+
findInfluencersSchema,
|
|
95
|
+
findInfluencersHandler,
|
|
96
|
+
} from './tools/find-influencers.js'
|
|
97
|
+
|
|
98
|
+
import {
|
|
99
|
+
searchRedditName,
|
|
100
|
+
searchRedditDescription,
|
|
101
|
+
searchRedditSchema,
|
|
102
|
+
searchRedditHandler,
|
|
103
|
+
} from './tools/search-reddit.js'
|
|
104
|
+
|
|
105
|
+
import {
|
|
106
|
+
searchSeoName,
|
|
107
|
+
searchSeoDescription,
|
|
108
|
+
searchSeoSchema,
|
|
109
|
+
searchSeoHandler,
|
|
110
|
+
} from './tools/search-seo.js'
|
|
111
|
+
|
|
112
|
+
import {
|
|
113
|
+
findSignalsName,
|
|
114
|
+
findSignalsDescription,
|
|
115
|
+
findSignalsSchema,
|
|
116
|
+
findSignalsHandler,
|
|
117
|
+
} from './tools/find-signals.js'
|
|
118
|
+
|
|
119
|
+
import {
|
|
120
|
+
fetchPageContentName,
|
|
121
|
+
fetchPageContentDescription,
|
|
122
|
+
fetchPageContentSchema,
|
|
123
|
+
fetchPageContentHandler,
|
|
124
|
+
} from './tools/fetch-page-content.js'
|
|
125
|
+
|
|
126
|
+
// Initialize HTTP client (reads env vars)
|
|
127
|
+
initClient()
|
|
128
|
+
|
|
129
|
+
const server = new McpServer({
|
|
130
|
+
name: 'coldiq',
|
|
131
|
+
version: '0.1.0',
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
// Register all tools
|
|
135
|
+
server.tool(searchCompaniesName, searchCompaniesDescription, searchCompaniesSchema, searchCompaniesHandler)
|
|
136
|
+
server.tool(findPeopleName, findPeopleDescription, findPeopleSchema, findPeopleHandler)
|
|
137
|
+
server.tool(findEmailName, findEmailDescription, findEmailSchema, findEmailHandler)
|
|
138
|
+
server.tool(enrichPersonName, enrichPersonDescription, enrichPersonSchema, enrichPersonHandler)
|
|
139
|
+
server.tool(findEmailsName, findEmailsDescription, findEmailsSchema, findEmailsHandler)
|
|
140
|
+
server.tool(verifyEmailName, verifyEmailDescription, verifyEmailSchema, verifyEmailHandler)
|
|
141
|
+
server.tool(findPhoneName, findPhoneDescription, findPhoneSchema, findPhoneHandler)
|
|
142
|
+
server.tool(enrichCompanyName, enrichCompanyDescription, enrichCompanySchema, enrichCompanyHandler)
|
|
143
|
+
server.tool(searchWebName, searchWebDescription, searchWebSchema, searchWebHandler)
|
|
144
|
+
server.tool(searchJobsName, searchJobsDescription, searchJobsSchema, searchJobsHandler)
|
|
145
|
+
server.tool(searchAdsName, searchAdsDescription, searchAdsSchema, searchAdsHandler)
|
|
146
|
+
server.tool(searchPlacesName, searchPlacesDescription, searchPlacesSchema, searchPlacesHandler)
|
|
147
|
+
server.tool(findInfluencersName, findInfluencersDescription, findInfluencersSchema, findInfluencersHandler)
|
|
148
|
+
server.tool(searchRedditName, searchRedditDescription, searchRedditSchema, searchRedditHandler)
|
|
149
|
+
server.tool(searchSeoName, searchSeoDescription, searchSeoSchema, searchSeoHandler)
|
|
150
|
+
server.tool(findSignalsName, findSignalsDescription, findSignalsSchema, findSignalsHandler)
|
|
151
|
+
server.tool(fetchPageContentName, fetchPageContentDescription, fetchPageContentSchema, fetchPageContentHandler)
|
|
152
|
+
|
|
153
|
+
// Connect via stdio transport
|
|
154
|
+
const transport = new StdioServerTransport()
|
|
155
|
+
await server.connect(transport)
|