@coldiq/mcp 0.5.1 → 0.5.3

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.
@@ -4,6 +4,7 @@ export declare const callEndpointDescription: string;
4
4
  export declare const callEndpointSchema: {
5
5
  api: z.ZodString;
6
6
  path: z.ZodString;
7
+ method: z.ZodOptional<z.ZodEnum<["GET", "POST", "PUT", "PATCH", "DELETE"]>>;
7
8
  params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
8
9
  };
9
10
  export declare function callEndpointHandler(input: Record<string, unknown>): Promise<{
@@ -1 +1 @@
1
- {"version":3,"file":"call-endpoint.d.ts","sourceRoot":"","sources":["../../src/tools/call-endpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,gBAAgB,kBAAkB,CAAA;AAE/C,eAAO,MAAM,uBAAuB,QAKgB,CAAA;AAEpD,eAAO,MAAM,kBAAkB;;;;CAO9B,CAAA;AAED,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;GASvE"}
1
+ {"version":3,"file":"call-endpoint.d.ts","sourceRoot":"","sources":["../../src/tools/call-endpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,gBAAgB,kBAAkB,CAAA;AAE/C,eAAO,MAAM,uBAAuB,QAKgB,CAAA;AAEpD,eAAO,MAAM,kBAAkB;;;;;CAS9B,CAAA;AAED,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;GASvE"}
@@ -9,13 +9,15 @@ export const callEndpointDescription = 'Call any ColdIQ marketplace endpoint dir
9
9
  export const callEndpointSchema = {
10
10
  api: z.string().describe('Provider key from search_endpoints / get_endpoint_details, e.g. "coldiq".'),
11
11
  path: z.string().describe('Endpoint path without the /v1 prefix, e.g. "/limadata/prospect/people/filter".'),
12
+ method: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']).optional()
13
+ .describe('HTTP method from search_endpoints. Set this when one path supports more than one method.'),
12
14
  params: z
13
15
  .record(z.unknown())
14
16
  .optional()
15
17
  .describe('Provider-native request params (request body fields, plus any path/query params), as shown in get_endpoint_details.'),
16
18
  };
17
19
  export async function callEndpointHandler(input) {
18
- const res = await callApi('POST', '/endpoints/use', { api: input.api, path: input.path, params: input.params });
20
+ const res = await callApi('POST', '/endpoints/use', { api: input.api, path: input.path, method: input.method, params: input.params });
19
21
  if (!res.ok) {
20
22
  return {
21
23
  content: [{ type: 'text', text: JSON.stringify({ error: 'Endpoint call failed', status: res.status, data: res.data }) }],
@@ -1 +1 @@
1
- {"version":3,"file":"call-endpoint.js","sourceRoot":"","sources":["../../src/tools/call-endpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,CAAC,MAAM,gBAAgB,GAAG,eAAe,CAAA;AAE/C,MAAM,CAAC,MAAM,uBAAuB,GAClC,yGAAyG;IACzG,mGAAmG;IACnG,6FAA6F;IAC7F,0GAA0G;IAC1G,kDAAkD,CAAA;AAEpD,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2EAA2E,CAAC;IACrG,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gFAAgF,CAAC;IAC3G,MAAM,EAAE,CAAC;SACN,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SACnB,QAAQ,EAAE;SACV,QAAQ,CAAC,qHAAqH,CAAC;CACnI,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,KAA8B;IACtE,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAA;IAC/G,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YACjI,OAAO,EAAE,IAAI;SACd,CAAA;IACH,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAA;AACjF,CAAC"}
1
+ {"version":3,"file":"call-endpoint.js","sourceRoot":"","sources":["../../src/tools/call-endpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,CAAC,MAAM,gBAAgB,GAAG,eAAe,CAAA;AAE/C,MAAM,CAAC,MAAM,uBAAuB,GAClC,yGAAyG;IACzG,mGAAmG;IACnG,6FAA6F;IAC7F,0GAA0G;IAC1G,kDAAkD,CAAA;AAEpD,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2EAA2E,CAAC;IACrG,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gFAAgF,CAAC;IAC3G,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE;SACjE,QAAQ,CAAC,0FAA0F,CAAC;IACvG,MAAM,EAAE,CAAC;SACN,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SACnB,QAAQ,EAAE;SACV,QAAQ,CAAC,qHAAqH,CAAC;CACnI,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,KAA8B;IACtE,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAA;IACrI,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YACjI,OAAO,EAAE,IAAI;SACd,CAAA;IACH,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAA;AACjF,CAAC"}
@@ -7,7 +7,7 @@ export const findSignalsDescription = 'Retrieve sales intelligence signals — f
7
7
  'Company-targeted (funding | acquisition | hiring | job_change | intent): accepts companies/domains/industries/countries/since filters. ' +
8
8
  'funding additionally accepts `round_type` (e.g. ["Series A", "Seed"]). ' +
9
9
  'intent has two modes: (a) DISCOVERY — pass `topics` (e.g. ["sales-automation"]) with no companies/domains to find companies showing intent on those topics; (b) VERIFY — pass companies/domains to check intent on known companies. Requires topics OR companies/domains. ' +
10
- 'Feed-style (news | startup_post): country and since only does NOT filter by company. Passing companies/domains for these types is rejected. ' +
10
+ 'Feed-style: news accepts country only; startup_post accepts country and since. Neither filters by company or domain. ' +
11
11
  'hiring returns individual job postings with company context (title, location, descriptionText, company industries) — for richer job-board queries with description/seniority/easy-apply filters use search_jobs instead.';
12
12
  export const findSignalsSchema = {
13
13
  signal_type: z
@@ -15,7 +15,7 @@ export const findSignalsSchema = {
15
15
  .describe('Signal type to retrieve. ' +
16
16
  'Company-targeted: "funding" (fundraising rounds), "acquisition" (M&A), "hiring" (individual job postings indexed by Signalbase, with company context), ' +
17
17
  '"job_change" (people who recently changed roles), "intent" (companies showing buying intent — discover by `topics` or verify on known companies/domains). ' +
18
- 'Feed-style (country/date filter only — company filter not supported): "news" (company news events), "startup_post" (Product Hunt, Hacker News, etc.)'),
18
+ 'Feed-style: "news" (country filter only), "startup_post" (Product Hunt, Hacker News, etc.)'),
19
19
  companies: z
20
20
  .array(z.string())
21
21
  .optional()
@@ -23,11 +23,11 @@ export const findSignalsSchema = {
23
23
  domains: z
24
24
  .array(z.string())
25
25
  .optional()
26
- .describe('Company domains to filter signals for (e.g. ["coldiq.com"]). Used by "hiring" (jobs AT these domains) and "intent". For intent VERIFY mode: pass companies or domains. For intent DISCOVERY mode: omit both and pass topics instead.'),
26
+ .describe('Company domains to filter signals for (e.g. ["coldiq.com"]). Used by hiring and intent. For intent DISCOVERY mode: omit domains and pass topics instead. News and startup_post do not support domain filtering.'),
27
27
  since: z
28
28
  .string()
29
29
  .optional()
30
- .describe('Return signals after this date. ISO date format, e.g. "2026-01-01". Honored by funding, acquisition, hiring, job_change, and startup_post. NOT supported for intent (TheirStack has no date filter on intent) — passing it has no effect.'),
30
+ .describe('Return signals after this date. ISO date format, e.g. "2026-01-01". Honored by funding, acquisition, hiring, job_change, and startup_post. PredictLeads news discovery has no date filter.'),
31
31
  industries: z
32
32
  .array(z.string())
33
33
  .optional()
@@ -1 +1 @@
1
- {"version":3,"file":"find-signals.js","sourceRoot":"","sources":["../../src/tools/find-signals.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,eAAe,GAAG,cAAc,CAAA;AAE7C,MAAM,CAAC,MAAM,sBAAsB,GACjC,4IAA4I;IAC5I,gDAAgD;IAChD,yIAAyI;IACzI,yEAAyE;IACzE,4QAA4Q;IAC5Q,gJAAgJ;IAChJ,0NAA0N,CAAA;AAE5N,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,WAAW,EAAE,CAAC;SACX,IAAI,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;SAC1F,QAAQ,CACP,2BAA2B;QAC3B,yJAAyJ;QACzJ,4JAA4J;QAC5J,sJAAsJ,CACvJ;IACH,SAAS,EAAE,CAAC;SACT,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CAAC,4YAA4Y,CAAC;IACzZ,OAAO,EAAE,CAAC;SACP,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CAAC,sOAAsO,CAAC;IACnP,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,2OAA2O,CAAC;IACxP,UAAU,EAAE,CAAC;SACV,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CAAC,6hBAA6hB,CAAC;IAC1iB,SAAS,EAAE,CAAC;SACT,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CAAC,0FAA0F,CAAC;IACvG,UAAU,EAAE,CAAC;SACV,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CAAC,6RAA6R,CAAC;IAC1S,MAAM,EAAE,CAAC;SACN,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CAAC,6bAA6b,CAAC;IAC1c,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,GAAG,CAAC;SACR,OAAO,CAAC,EAAE,CAAC;SACX,QAAQ,CAAC,8CAA8C,CAAC;IAC3D,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gLAAgL,yBAAyB,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,qEAAqE,CAAC;CAClW,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAA8B;IACrE,OAAO,QAAQ,CAAC,eAAe,EAAE,KAAK,CAAC,CAAA;AACzC,CAAC"}
1
+ {"version":3,"file":"find-signals.js","sourceRoot":"","sources":["../../src/tools/find-signals.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,eAAe,GAAG,cAAc,CAAA;AAE7C,MAAM,CAAC,MAAM,sBAAsB,GACjC,4IAA4I;IAC5I,gDAAgD;IAChD,yIAAyI;IACzI,yEAAyE;IACzE,4QAA4Q;IAC5Q,uHAAuH;IACvH,0NAA0N,CAAA;AAE5N,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,WAAW,EAAE,CAAC;SACX,IAAI,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;SAC1F,QAAQ,CACP,2BAA2B;QAC3B,yJAAyJ;QACzJ,4JAA4J;QAC5J,4FAA4F,CAC7F;IACH,SAAS,EAAE,CAAC;SACT,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CAAC,4YAA4Y,CAAC;IACzZ,OAAO,EAAE,CAAC;SACP,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CAAC,iNAAiN,CAAC;IAC9N,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,4LAA4L,CAAC;IACzM,UAAU,EAAE,CAAC;SACV,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CAAC,6hBAA6hB,CAAC;IAC1iB,SAAS,EAAE,CAAC;SACT,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CAAC,0FAA0F,CAAC;IACvG,UAAU,EAAE,CAAC;SACV,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CAAC,6RAA6R,CAAC;IAC1S,MAAM,EAAE,CAAC;SACN,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CAAC,6bAA6b,CAAC;IAC1c,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,GAAG,CAAC;SACR,OAAO,CAAC,EAAE,CAAC;SACX,QAAQ,CAAC,8CAA8C,CAAC;IAC3D,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gLAAgL,yBAAyB,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,qEAAqE,CAAC;CAClW,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAA8B;IACrE,OAAO,QAAQ,CAAC,eAAe,EAAE,KAAK,CAAC,CAAA;AACzC,CAAC"}
@@ -4,6 +4,7 @@ export declare const getEndpointDetailsDescription: string;
4
4
  export declare const getEndpointDetailsSchema: {
5
5
  api: z.ZodString;
6
6
  path: z.ZodString;
7
+ method: z.ZodOptional<z.ZodEnum<["GET", "POST", "PUT", "PATCH", "DELETE"]>>;
7
8
  };
8
9
  export declare function getEndpointDetailsHandler(input: Record<string, unknown>): Promise<{
9
10
  content: {
@@ -1 +1 @@
1
- {"version":3,"file":"get-endpoint-details.d.ts","sourceRoot":"","sources":["../../src/tools/get-endpoint-details.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,sBAAsB,yBAAyB,CAAA;AAE5D,eAAO,MAAM,6BAA6B,QAGV,CAAA;AAEhC,eAAO,MAAM,wBAAwB;;;CAGpC,CAAA;AAED,wBAAsB,yBAAyB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;GAS7E"}
1
+ {"version":3,"file":"get-endpoint-details.d.ts","sourceRoot":"","sources":["../../src/tools/get-endpoint-details.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,sBAAsB,yBAAyB,CAAA;AAE5D,eAAO,MAAM,6BAA6B,QAGV,CAAA;AAEhC,eAAO,MAAM,wBAAwB;;;;CAKpC,CAAA;AAED,wBAAsB,yBAAyB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;GAS7E"}
@@ -7,9 +7,11 @@ export const getEndpointDetailsDescription = 'Get the real request schema, param
7
7
  export const getEndpointDetailsSchema = {
8
8
  api: z.string().describe('Provider key from search_endpoints, e.g. "coldiq" (Lima Data), "apollo", or "exa".'),
9
9
  path: z.string().describe('Endpoint path without the /v1 prefix, e.g. "/limadata/prospect/people/filter".'),
10
+ method: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']).optional()
11
+ .describe('HTTP method from search_endpoints. Set this when one path supports more than one method.'),
10
12
  };
11
13
  export async function getEndpointDetailsHandler(input) {
12
- const res = await callApi('POST', '/endpoints/details', { api: input.api, path: input.path });
14
+ const res = await callApi('POST', '/endpoints/details', { api: input.api, path: input.path, method: input.method });
13
15
  if (!res.ok) {
14
16
  return {
15
17
  content: [{ type: 'text', text: JSON.stringify({ error: 'Endpoint not found or details unavailable', status: res.status, data: res.data }) }],
@@ -1 +1 @@
1
- {"version":3,"file":"get-endpoint-details.js","sourceRoot":"","sources":["../../src/tools/get-endpoint-details.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,CAAC,MAAM,sBAAsB,GAAG,sBAAsB,CAAA;AAE5D,MAAM,CAAC,MAAM,6BAA6B,GACxC,6GAA6G;IAC7G,uGAAuG;IACvG,8BAA8B,CAAA;AAEhC,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oFAAoF,CAAC;IAC9G,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gFAAgF,CAAC;CAC5G,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,KAA8B;IAC5E,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,oBAAoB,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;IAC7F,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,2CAA2C,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YACtJ,OAAO,EAAE,IAAI;SACd,CAAA;IACH,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAA;AACjF,CAAC"}
1
+ {"version":3,"file":"get-endpoint-details.js","sourceRoot":"","sources":["../../src/tools/get-endpoint-details.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,CAAC,MAAM,sBAAsB,GAAG,sBAAsB,CAAA;AAE5D,MAAM,CAAC,MAAM,6BAA6B,GACxC,6GAA6G;IAC7G,uGAAuG;IACvG,8BAA8B,CAAA;AAEhC,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oFAAoF,CAAC;IAC9G,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gFAAgF,CAAC;IAC3G,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE;SACjE,QAAQ,CAAC,0FAA0F,CAAC;CACxG,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,KAA8B;IAC5E,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,oBAAoB,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAA;IACnH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,2CAA2C,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YACtJ,OAAO,EAAE,IAAI;SACd,CAAA;IACH,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAA;AACjF,CAAC"}
@@ -5,7 +5,7 @@ export declare const searchWebSchema: {
5
5
  query: z.ZodString;
6
6
  num_results: z.ZodDefault<z.ZodNumber>;
7
7
  country: z.ZodOptional<z.ZodString>;
8
- search_type: z.ZodDefault<z.ZodEnum<["general", "neural"]>>;
8
+ search_type: z.ZodDefault<z.ZodEnum<["general", "neural", "deep", "deep-reasoning"]>>;
9
9
  use_providers: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
10
10
  };
11
11
  export declare function searchWebHandler(input: Record<string, unknown>): Promise<{
@@ -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 searchWebName = 'search_web';
5
- 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
+ export const searchWebDescription = 'Search the web for market research, company news, or general lookups. Supports Google search (default), Exa auto through the neural compatibility alias, and Exa deep modes. ' +
6
6
  '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. ' +
7
7
  'find_people is the only tool for people lookups; do not supplement or replace it with web search. ' +
8
8
  'ColdIQ automatically picks the best provider — pass use_providers only if you need a specific tool.';
@@ -10,7 +10,7 @@ export const searchWebSchema = {
10
10
  query: z.string().describe('Search query'),
11
11
  num_results: z.number().min(1).max(100).default(10).describe('Number of results (default: 10, max: 100)'),
12
12
  country: z.string().optional().describe('Country code for geo-targeting (e.g. "us", "fr")'),
13
- search_type: z.enum(['general', 'neural']).default('general').describe('"general" for Google search (default), "neural" for semantic search via Exa'),
13
+ search_type: z.enum(['general', 'neural', 'deep', 'deep-reasoning']).default('general').describe('"general" for the default web search, "neural" for Exa auto compatibility, or an Exa deep mode'),
14
14
  use_providers: z.array(z.string()).optional().describe(`Optional ordered list of providers to use. Leave empty to let ColdIQ automatically pick the best tool for your inputs — recommended for most use cases. Available providers: ${getProvidersForCapability('search_web').join(', ')}. Provider names are matched fuzzily, so minor typos are tolerated.`),
15
15
  };
16
16
  export async function searchWebHandler(input) {
@@ -1 +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,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAA;AAEzE,MAAM,CAAC,MAAM,aAAa,GAAG,YAAY,CAAA;AAEzC,MAAM,CAAC,MAAM,oBAAoB,GAC/B,6IAA6I;IAC7I,iKAAiK;IACjK,oGAAoG;IACpG,qGAAqG,CAAA;AAEvG,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;IACrJ,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gLAAgL,yBAAyB,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,qEAAqE,CAAC;CAChW,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAA8B;IACnE,OAAO,QAAQ,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;AACvC,CAAC"}
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,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAA;AAEzE,MAAM,CAAC,MAAM,aAAa,GAAG,YAAY,CAAA;AAEzC,MAAM,CAAC,MAAM,oBAAoB,GAC/B,+KAA+K;IAC/K,iKAAiK;IACjK,oGAAoG;IACpG,qGAAqG,CAAA;AAEvG,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,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,gGAAgG,CAAC;IAClM,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gLAAgL,yBAAyB,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,qEAAqE,CAAC;CAChW,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAA8B;IACnE,OAAO,QAAQ,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;AACvC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coldiq/mcp",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
package/src/executor.ts CHANGED
@@ -261,7 +261,7 @@ export async function executeWithFallback(
261
261
 
262
262
  let allProviders =
263
263
  capability === 'search_web'
264
- ? getSearchWebProviders(input.search_type === 'neural')
264
+ ? getSearchWebProviders(input.search_type !== undefined && input.search_type !== 'general')
265
265
  : getProviders(capability)
266
266
 
267
267
  // When the caller pinned specific providers, filter to those in order.
package/src/registry.ts CHANGED
@@ -71,6 +71,27 @@ function isNonEmptyArray(v: unknown): boolean {
71
71
  return Array.isArray(v) && v.length > 0
72
72
  }
73
73
 
74
+ // Keep this standalone-package mirror in sync with
75
+ // src/providers/icypeas/reverse-email-classify.ts.
76
+ function isIcypeasReverseEmailFound(body: unknown): boolean {
77
+ if (!body || typeof body !== 'object' || Array.isArray(body)) return false
78
+ const response = body as Record<string, unknown>
79
+ const status = typeof response.status === 'string' ? response.status : ''
80
+ if (status !== 'FOUND' && status !== 'DEBITED') return false
81
+ if (response.success !== true || typeof response.results !== 'string') return false
82
+
83
+ try {
84
+ const url = new URL(response.results)
85
+ const hostname = url.hostname.toLowerCase()
86
+ const isLinkedInHost = hostname === 'linkedin.com' || hostname.endsWith('.linkedin.com')
87
+ return (url.protocol === 'http:' || url.protocol === 'https:')
88
+ && isLinkedInHost
89
+ && url.pathname.startsWith('/in/')
90
+ } catch {
91
+ return false
92
+ }
93
+ }
94
+
74
95
  // TheirStack attaches a per-job `company_object` whose enrichment arrays dominate the
75
96
  // payload (e.g. ~1,600-element technology_slugs/technology_names, plus long_description) —
76
97
  // tens of KB per job. Drop these heavy fields while keeping company identity (name, domain,
@@ -2295,7 +2316,9 @@ const searchWebProviders: ProviderEntry[] = [
2295
2316
  body: {
2296
2317
  query: input.query,
2297
2318
  numResults: input.num_results ?? 10,
2298
- type: input.search_type === 'neural' ? 'neural' : 'auto',
2319
+ type: input.search_type === 'deep' || input.search_type === 'deep-reasoning'
2320
+ ? input.search_type
2321
+ : 'auto',
2299
2322
  },
2300
2323
  }),
2301
2324
  hasResult: (data) => {
@@ -3410,10 +3433,7 @@ const enrichPersonProviders: ProviderEntry[] = [
3410
3433
  priority: 11,
3411
3434
  isApplicable: (input) => typeof input.email === 'string' && (input.email as string).includes('@'),
3412
3435
  mapParams: (input) => ({ body: { email: input.email } }),
3413
- hasResult: (data) => {
3414
- const d = data as Record<string, unknown>
3415
- return isNonEmptyArray(d.profiles) || (d.success === true && !!d.data)
3416
- },
3436
+ hasResult: isIcypeasReverseEmailFound,
3417
3437
  },
3418
3438
  {
3419
3439
  id: 'pdl-person-identify',
@@ -3442,6 +3462,36 @@ const enrichPersonProviders: ProviderEntry[] = [
3442
3462
  // find_signals
3443
3463
  // ---------------------------------------------------------------------------
3444
3464
 
3465
+ const PREDICTLEADS_COUNTRY_NAMES: Record<string, string> = {
3466
+ US: 'United States', GB: 'United Kingdom', UK: 'United Kingdom', CA: 'Canada',
3467
+ AU: 'Australia', DE: 'Germany', FR: 'France', NL: 'Netherlands', IN: 'India',
3468
+ SG: 'Singapore', JP: 'Japan', BR: 'Brazil', MX: 'Mexico', ZA: 'South Africa',
3469
+ }
3470
+
3471
+ function predictLeadsCompanyLocation(countries: unknown): string | undefined {
3472
+ if (!isNonEmptyArray(countries)) return undefined
3473
+ const value = String((countries as string[])[0]).trim()
3474
+ if (!value) return undefined
3475
+ return value.length > 3 ? value : PREDICTLEADS_COUNTRY_NAMES[value.toUpperCase()]
3476
+ }
3477
+
3478
+ function truncatePredictLeadsNews(data: unknown): unknown {
3479
+ if (!data || typeof data !== 'object') return data
3480
+ const value = data as Record<string, unknown>
3481
+ if (!Array.isArray(value.included)) return data
3482
+ return {
3483
+ ...value,
3484
+ included: value.included.map((item) => {
3485
+ if (!item || typeof item !== 'object') return item
3486
+ const attributes = (item as Record<string, unknown>).attributes
3487
+ if (!attributes || typeof attributes !== 'object') return item
3488
+ const body = (attributes as Record<string, unknown>).body
3489
+ if (typeof body !== 'string' || body.length <= 500) return item
3490
+ return { ...item as Record<string, unknown>, attributes: { ...attributes, body: `${body.slice(0, 500)}…`, body_truncated: true } }
3491
+ }),
3492
+ }
3493
+ }
3494
+
3445
3495
  const findSignalsProviders: ProviderEntry[] = [
3446
3496
  {
3447
3497
  id: 'signalbase-funding',
@@ -3647,11 +3697,13 @@ const findSignalsProviders: ProviderEntry[] = [
3647
3697
  isApplicable: (input) => input.signal_type === 'news',
3648
3698
  mapParams: (input) => {
3649
3699
  const qp: Record<string, string> = {}
3650
- if (isNonEmptyArray(input.countries)) qp.company_location = (input.countries as string[])[0]
3700
+ const location = predictLeadsCompanyLocation(input.countries)
3701
+ if (location) qp.company_location = location
3651
3702
  qp.limit = String(Math.min((input.limit as number | undefined) ?? 25, 100))
3652
3703
  return { queryParams: qp }
3653
3704
  },
3654
3705
  hasResult: (data) => isNonEmptyArray((data as Record<string, unknown>).data),
3706
+ postFilter: (data) => truncatePredictLeadsNews(data),
3655
3707
  },
3656
3708
  {
3657
3709
  id: 'predictleads-startup-posts',
@@ -13,6 +13,8 @@ export const callEndpointDescription =
13
13
  export const callEndpointSchema = {
14
14
  api: z.string().describe('Provider key from search_endpoints / get_endpoint_details, e.g. "coldiq".'),
15
15
  path: z.string().describe('Endpoint path without the /v1 prefix, e.g. "/limadata/prospect/people/filter".'),
16
+ method: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']).optional()
17
+ .describe('HTTP method from search_endpoints. Set this when one path supports more than one method.'),
16
18
  params: z
17
19
  .record(z.unknown())
18
20
  .optional()
@@ -20,7 +22,7 @@ export const callEndpointSchema = {
20
22
  }
21
23
 
22
24
  export async function callEndpointHandler(input: Record<string, unknown>) {
23
- const res = await callApi('POST', '/endpoints/use', { api: input.api, path: input.path, params: input.params })
25
+ const res = await callApi('POST', '/endpoints/use', { api: input.api, path: input.path, method: input.method, params: input.params })
24
26
  if (!res.ok) {
25
27
  return {
26
28
  content: [{ type: 'text' as const, text: JSON.stringify({ error: 'Endpoint call failed', status: res.status, data: res.data }) }],
@@ -10,7 +10,7 @@ export const findSignalsDescription =
10
10
  'Company-targeted (funding | acquisition | hiring | job_change | intent): accepts companies/domains/industries/countries/since filters. ' +
11
11
  'funding additionally accepts `round_type` (e.g. ["Series A", "Seed"]). ' +
12
12
  'intent has two modes: (a) DISCOVERY — pass `topics` (e.g. ["sales-automation"]) with no companies/domains to find companies showing intent on those topics; (b) VERIFY — pass companies/domains to check intent on known companies. Requires topics OR companies/domains. ' +
13
- 'Feed-style (news | startup_post): country and since only does NOT filter by company. Passing companies/domains for these types is rejected. ' +
13
+ 'Feed-style: news accepts country only; startup_post accepts country and since. Neither filters by company or domain. ' +
14
14
  'hiring returns individual job postings with company context (title, location, descriptionText, company industries) — for richer job-board queries with description/seniority/easy-apply filters use search_jobs instead.'
15
15
 
16
16
  export const findSignalsSchema = {
@@ -20,7 +20,7 @@ export const findSignalsSchema = {
20
20
  'Signal type to retrieve. ' +
21
21
  'Company-targeted: "funding" (fundraising rounds), "acquisition" (M&A), "hiring" (individual job postings indexed by Signalbase, with company context), ' +
22
22
  '"job_change" (people who recently changed roles), "intent" (companies showing buying intent — discover by `topics` or verify on known companies/domains). ' +
23
- 'Feed-style (country/date filter only — company filter not supported): "news" (company news events), "startup_post" (Product Hunt, Hacker News, etc.)'
23
+ 'Feed-style: "news" (country filter only), "startup_post" (Product Hunt, Hacker News, etc.)'
24
24
  ),
25
25
  companies: z
26
26
  .array(z.string())
@@ -29,11 +29,11 @@ export const findSignalsSchema = {
29
29
  domains: z
30
30
  .array(z.string())
31
31
  .optional()
32
- .describe('Company domains to filter signals for (e.g. ["coldiq.com"]). Used by "hiring" (jobs AT these domains) and "intent". For intent VERIFY mode: pass companies or domains. For intent DISCOVERY mode: omit both and pass topics instead.'),
32
+ .describe('Company domains to filter signals for (e.g. ["coldiq.com"]). Used by hiring and intent. For intent DISCOVERY mode: omit domains and pass topics instead. News and startup_post do not support domain filtering.'),
33
33
  since: z
34
34
  .string()
35
35
  .optional()
36
- .describe('Return signals after this date. ISO date format, e.g. "2026-01-01". Honored by funding, acquisition, hiring, job_change, and startup_post. NOT supported for intent (TheirStack has no date filter on intent) — passing it has no effect.'),
36
+ .describe('Return signals after this date. ISO date format, e.g. "2026-01-01". Honored by funding, acquisition, hiring, job_change, and startup_post. PredictLeads news discovery has no date filter.'),
37
37
  industries: z
38
38
  .array(z.string())
39
39
  .optional()
@@ -11,10 +11,12 @@ export const getEndpointDetailsDescription =
11
11
  export const getEndpointDetailsSchema = {
12
12
  api: z.string().describe('Provider key from search_endpoints, e.g. "coldiq" (Lima Data), "apollo", or "exa".'),
13
13
  path: z.string().describe('Endpoint path without the /v1 prefix, e.g. "/limadata/prospect/people/filter".'),
14
+ method: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']).optional()
15
+ .describe('HTTP method from search_endpoints. Set this when one path supports more than one method.'),
14
16
  }
15
17
 
16
18
  export async function getEndpointDetailsHandler(input: Record<string, unknown>) {
17
- const res = await callApi('POST', '/endpoints/details', { api: input.api, path: input.path })
19
+ const res = await callApi('POST', '/endpoints/details', { api: input.api, path: input.path, method: input.method })
18
20
  if (!res.ok) {
19
21
  return {
20
22
  content: [{ type: 'text' as const, text: JSON.stringify({ error: 'Endpoint not found or details unavailable', status: res.status, data: res.data }) }],
@@ -5,7 +5,7 @@ import { getProvidersForCapability } from '../utils/provider-resolver.js'
5
5
  export const searchWebName = 'search_web'
6
6
 
7
7
  export const searchWebDescription =
8
- 'Search the web for market research, company news, or general lookups. Supports Google search (default) and neural/semantic search via Exa. ' +
8
+ 'Search the web for market research, company news, or general lookups. Supports Google search (default), Exa auto through the neural compatibility alias, and Exa deep modes. ' +
9
9
  '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. ' +
10
10
  'find_people is the only tool for people lookups; do not supplement or replace it with web search. ' +
11
11
  'ColdIQ automatically picks the best provider — pass use_providers only if you need a specific tool.'
@@ -14,7 +14,7 @@ export const searchWebSchema = {
14
14
  query: z.string().describe('Search query'),
15
15
  num_results: z.number().min(1).max(100).default(10).describe('Number of results (default: 10, max: 100)'),
16
16
  country: z.string().optional().describe('Country code for geo-targeting (e.g. "us", "fr")'),
17
- search_type: z.enum(['general', 'neural']).default('general').describe('"general" for Google search (default), "neural" for semantic search via Exa'),
17
+ search_type: z.enum(['general', 'neural', 'deep', 'deep-reasoning']).default('general').describe('"general" for the default web search, "neural" for Exa auto compatibility, or an Exa deep mode'),
18
18
  use_providers: z.array(z.string()).optional().describe(`Optional ordered list of providers to use. Leave empty to let ColdIQ automatically pick the best tool for your inputs — recommended for most use cases. Available providers: ${getProvidersForCapability('search_web').join(', ')}. Provider names are matched fuzzily, so minor typos are tolerated.`),
19
19
  }
20
20
 
@@ -390,20 +390,22 @@ describe('icypeas-reverse-email-lookup', () => {
390
390
  })
391
391
  })
392
392
 
393
- it('hasResult: true when non-empty profiles array', () => {
394
- expect(p().hasResult({ profiles: [{ name: 'Michel Lieben' }] })).toBe(true)
395
- })
396
-
397
- it('hasResult: true when success + data', () => {
398
- expect(p().hasResult({ success: true, data: { name: 'Michel Lieben' } })).toBe(true)
399
- })
400
-
401
- it('hasResult: false when profiles is empty array', () => {
402
- expect(p().hasResult({ profiles: [] })).toBe(false)
403
- })
404
-
405
- it('hasResult: false on empty object', () => {
406
- expect(p().hasResult({})).toBe(false)
393
+ it('hasResult: true for the documented hit shape', () => {
394
+ expect(p().hasResult({
395
+ success: true,
396
+ status: 'FOUND',
397
+ results: 'https://www.linkedin.com/in/michel-lieben',
398
+ })).toBe(true)
399
+ })
400
+
401
+ it.each([
402
+ { success: true, status: 'NOT_FOUND', results: 'https://www.linkedin.com/in/michel-lieben' },
403
+ { success: false, validationErrors: ['Invalid email'] },
404
+ { success: true },
405
+ { profiles: [{ name: 'Michel Lieben' }] },
406
+ { success: true, data: { name: 'Michel Lieben' } },
407
+ ])('hasResult: false for a miss, invalid, or unknown body', (body) => {
408
+ expect(p().hasResult(body)).toBe(false)
407
409
  })
408
410
  })
409
411
 
@@ -616,8 +616,8 @@ describe('find_signals priority ordering', () => {
616
616
  }
617
617
  })
618
618
 
619
- it('signalbase-funding is first (priority 1)', () => {
620
- expect(providers()[0].id).toBe('signalbase-funding')
619
+ it('contains only pull-based providers', () => {
620
+ expect(providers().some((provider) => provider.id === 'coldiq-signal-feed')).toBe(false)
621
621
  })
622
622
 
623
623
  it('predictleads-startup-posts is last (priority 8)', () => {
@@ -20,6 +20,13 @@ const ALL_CAPABILITIES: Capability[] = [
20
20
  ]
21
21
 
22
22
  describe('registry', () => {
23
+ it('maps the neural compatibility alias to Exa auto and preserves deep modes', () => {
24
+ const exa = getConfiguredProviders('search_web').find((provider) => provider.id === 'exa')!
25
+ expect(exa.mapParams({ query: 'ColdIQ', search_type: 'neural' }).body).toMatchObject({ type: 'auto' })
26
+ expect(exa.mapParams({ query: 'ColdIQ', search_type: 'deep' }).body).toMatchObject({ type: 'deep' })
27
+ expect(exa.mapParams({ query: 'ColdIQ', search_type: 'deep-reasoning' }).body).toMatchObject({ type: 'deep-reasoning' })
28
+ })
29
+
23
30
  it('every capability has at least one provider', () => {
24
31
  for (const cap of ALL_CAPABILITIES) {
25
32
  const providers = getProviders(cap)
@@ -0,0 +1,11 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { z } from 'zod'
3
+ import { searchWebSchema } from '../src/tools/search-web.js'
4
+
5
+ const schema = z.object(searchWebSchema)
6
+
7
+ describe('search_web Exa compatibility', () => {
8
+ it.each(['general', 'neural', 'deep', 'deep-reasoning'])('accepts %s', (search_type) => {
9
+ expect(schema.safeParse({ query: 'ColdIQ', search_type }).success).toBe(true)
10
+ })
11
+ })
@@ -38,4 +38,20 @@ describe('call_endpoint handler', () => {
38
38
  expect(parsed.status).toBe(404)
39
39
  expect(parsed.error).toBe('Endpoint call failed')
40
40
  })
41
+
42
+ it('forwards the HTTP method for a shared endpoint path', async () => {
43
+ let capturedBody: unknown
44
+ globalThis.fetch = vi.fn(async (_url: string | URL | Request, opts?: RequestInit) => {
45
+ capturedBody = opts?.body ? JSON.parse(opts.body as string) : undefined
46
+ return new Response(JSON.stringify({ ok: true, status: 201, data: { id: 'run_1' } }), { status: 200 })
47
+ }) as typeof fetch
48
+
49
+ await callEndpointHandler({
50
+ api: 'exa', path: '/exa/agent/runs', method: 'POST', params: { query: 'Research ColdIQ' },
51
+ })
52
+
53
+ expect(capturedBody).toEqual({
54
+ api: 'exa', path: '/exa/agent/runs', method: 'POST', params: { query: 'Research ColdIQ' },
55
+ })
56
+ })
41
57
  })
@@ -34,4 +34,16 @@ describe('get_endpoint_details handler', () => {
34
34
  expect(parsed.status).toBe(404)
35
35
  expect(parsed.error).toBe('Endpoint not found or details unavailable')
36
36
  })
37
+
38
+ it('forwards the HTTP method for a shared endpoint path', async () => {
39
+ let capturedBody: unknown
40
+ globalThis.fetch = vi.fn(async (_url: string | URL | Request, opts?: RequestInit) => {
41
+ capturedBody = opts?.body ? JSON.parse(opts.body as string) : undefined
42
+ return new Response(JSON.stringify({ path: '/exa/agent/runs', method: 'POST' }), { status: 200 })
43
+ }) as typeof fetch
44
+
45
+ await getEndpointDetailsHandler({ api: 'exa', path: '/exa/agent/runs', method: 'POST' })
46
+
47
+ expect(capturedBody).toEqual({ api: 'exa', path: '/exa/agent/runs', method: 'POST' })
48
+ })
37
49
  })