@coldiq/mcp 0.3.30 → 0.3.31
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 +12 -3
- package/dist/index.js.map +1 -1
- package/dist/tools/search-companies.d.ts +6 -0
- package/dist/tools/search-companies.d.ts.map +1 -1
- package/dist/tools/search-companies.js +47 -0
- package/dist/tools/search-companies.js.map +1 -1
- package/dist/version.d.ts +10 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +20 -0
- package/dist/version.js.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +12 -3
- package/src/tools/search-companies.ts +46 -0
- package/src/version.ts +19 -0
- package/tests/tools/search-companies.test.ts +94 -0
- package/tests/version.test.ts +16 -0
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
import { initClient } from './client.js';
|
|
5
|
+
import { readPackageVersion } from './version.js';
|
|
5
6
|
import { searchCompaniesName, searchCompaniesDescription, searchCompaniesSchema, searchCompaniesHandler, } from './tools/search-companies.js';
|
|
6
7
|
import { findPeopleName, findPeopleDescription, findPeopleSchema, findPeopleHandler, } from './tools/find-people.js';
|
|
7
8
|
import { findEmailName, findEmailDescription, findEmailSchema, findEmailHandler, } from './tools/find-email.js';
|
|
@@ -35,11 +36,19 @@ import { getPlaceReviewsName, getPlaceReviewsDescription, getPlaceReviewsSchema,
|
|
|
35
36
|
import { listDataSourcesName, listDataSourcesDescription, listDataSourcesSchema, listDataSourcesHandler, } from './tools/list-data-sources.js';
|
|
36
37
|
import { listSkillsName, listSkillsDescription, listSkillsSchema, listSkillsHandler, } from './tools/list-skills.js';
|
|
37
38
|
import { loadSkillName, loadSkillDescription, loadSkillSchema, loadSkillHandler, } from './tools/load-skill.js';
|
|
38
|
-
// Initialize HTTP client (reads env vars)
|
|
39
|
-
|
|
39
|
+
// Initialize HTTP client (reads env vars). A missing/empty COLDIQ_API_KEY is a
|
|
40
|
+
// user-config error, not a bug — print the message without a stack trace.
|
|
41
|
+
try {
|
|
42
|
+
initClient();
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
const packageVersion = readPackageVersion(import.meta.url);
|
|
40
49
|
const server = new McpServer({
|
|
41
50
|
name: 'coldiq',
|
|
42
|
-
version:
|
|
51
|
+
version: packageVersion,
|
|
43
52
|
}, {
|
|
44
53
|
// Surfaced to the model at init. Enforces batching on the multi-company
|
|
45
54
|
// prospecting flow — the dominant latency driver. Looping these tools
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -35,5 +35,11 @@ export declare function searchCompaniesHandler(input: Record<string, unknown>):
|
|
|
35
35
|
text: string;
|
|
36
36
|
}];
|
|
37
37
|
isError?: boolean;
|
|
38
|
+
} | {
|
|
39
|
+
content: {
|
|
40
|
+
type: "text";
|
|
41
|
+
text: string;
|
|
42
|
+
}[];
|
|
43
|
+
isError: boolean;
|
|
38
44
|
}>;
|
|
39
45
|
//# sourceMappingURL=search-companies.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-companies.d.ts","sourceRoot":"","sources":["../../src/tools/search-companies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,mBAAmB,qBAAqB,CAAA;AAErD,eAAO,MAAM,0BAA0B,QAEkV,CAAA;AAEzX,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BjC,CAAA;
|
|
1
|
+
{"version":3,"file":"search-companies.d.ts","sourceRoot":"","sources":["../../src/tools/search-companies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,mBAAmB,qBAAqB,CAAA;AAErD,eAAO,MAAM,0BAA0B,QAEkV,CAAA;AAEzX,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BjC,CAAA;AAkCD,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;GAgB1E"}
|
|
@@ -32,7 +32,54 @@ export const searchCompaniesSchema = {
|
|
|
32
32
|
fields: z.enum(['compact', 'verbose']).default('compact').describe('Response shape. "compact" (default) returns a small per-company record: name, domain, website, linkedin_url, employees, revenue, industry, country, city, founded_year, categories — plus total. "verbose" returns the raw provider passthrough (funding-round history, technologies, keyword arrays, NAICS codes, all socials, descriptions) — only use when you specifically need those fields.'),
|
|
33
33
|
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_companies').join(', ')}. Provider names are matched fuzzily, so minor typos are tolerated.`),
|
|
34
34
|
};
|
|
35
|
+
// A call must carry at least one filter that actually NARROWS the result set,
|
|
36
|
+
// otherwise it forwards an unbounded query upstream and bills for arbitrary
|
|
37
|
+
// companies. This is an explicit allowlist of narrowing keys, not a denylist of
|
|
38
|
+
// response-shaping ones, on purpose: a future response-shaping field (e.g. a
|
|
39
|
+
// `sort` or `page` knob) added to the schema must never silently count as a
|
|
40
|
+
// filter and reopen the billing hole. Exclusion fields (`exclude_*`) are
|
|
41
|
+
// deliberately absent — excluding a domain narrows nothing on its own. Kept in
|
|
42
|
+
// sync with the server-side guard in src/router/verb-handler.ts.
|
|
43
|
+
const NARROWING_FILTER_KEYS = [
|
|
44
|
+
'keywords', 'countries', 'locations', 'industries', 'technologies',
|
|
45
|
+
'min_employees', 'max_employees', 'min_founded_year', 'max_founded_year',
|
|
46
|
+
'funding_stages', 'min_funding_amount', 'max_funding_amount',
|
|
47
|
+
'min_funding_year', 'max_funding_year', 'min_revenue', 'max_revenue',
|
|
48
|
+
'is_hiring', 'min_workforce_growth_pct', 'linkedin_search_url',
|
|
49
|
+
];
|
|
50
|
+
// A value narrows only when it actually constrains: a non-blank string, an array
|
|
51
|
+
// with at least one non-blank element, a non-zero finite number (a `min_*` of 0
|
|
52
|
+
// is a no-op bound), or boolean `true` (is_hiring is ignored upstream unless true).
|
|
53
|
+
function isNarrowingValue(value) {
|
|
54
|
+
if (value === undefined || value === null)
|
|
55
|
+
return false;
|
|
56
|
+
if (typeof value === 'string')
|
|
57
|
+
return value.trim().length > 0;
|
|
58
|
+
if (typeof value === 'number')
|
|
59
|
+
return Number.isFinite(value) && value !== 0;
|
|
60
|
+
if (typeof value === 'boolean')
|
|
61
|
+
return value === true;
|
|
62
|
+
if (Array.isArray(value))
|
|
63
|
+
return value.some((el) => (typeof el === 'string' ? el.trim().length > 0 : el != null));
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
function hasDiscriminatingFilter(input) {
|
|
67
|
+
return NARROWING_FILTER_KEYS.some((key) => isNarrowingValue(input[key]));
|
|
68
|
+
}
|
|
35
69
|
export async function searchCompaniesHandler(input) {
|
|
70
|
+
if (!hasDiscriminatingFilter(input)) {
|
|
71
|
+
return {
|
|
72
|
+
content: [
|
|
73
|
+
{
|
|
74
|
+
type: 'text',
|
|
75
|
+
text: JSON.stringify({
|
|
76
|
+
error: 'search_companies needs at least one filter (keywords, countries, industries, employee range, technologies, funding, …). An unfiltered search would return arbitrary companies and still consume credits.',
|
|
77
|
+
}),
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
isError: true,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
36
83
|
return callVerb('/companies/search', input);
|
|
37
84
|
}
|
|
38
85
|
//# sourceMappingURL=search-companies.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-companies.js","sourceRoot":"","sources":["../../src/tools/search-companies.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"search-companies.js","sourceRoot":"","sources":["../../src/tools/search-companies.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The MCP server reports its own npm version to the client at init. package.json
|
|
3
|
+
* sits outside tsconfig rootDir, so it can't be imported — read it at runtime.
|
|
4
|
+
* The built entry (dist/index.js) sits exactly one directory below the package
|
|
5
|
+
* root, so '../package.json' resolves in both `tsx src/…` dev and the published
|
|
6
|
+
* dist layout. Falls back to '0.0.0' rather than throwing, so a packaging change
|
|
7
|
+
* that moves the file can never crash server startup over a cosmetic version string.
|
|
8
|
+
*/
|
|
9
|
+
export declare function readPackageVersion(fromUrl: string): string;
|
|
10
|
+
//# sourceMappingURL=version.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAQ1D"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
/**
|
|
3
|
+
* The MCP server reports its own npm version to the client at init. package.json
|
|
4
|
+
* sits outside tsconfig rootDir, so it can't be imported — read it at runtime.
|
|
5
|
+
* The built entry (dist/index.js) sits exactly one directory below the package
|
|
6
|
+
* root, so '../package.json' resolves in both `tsx src/…` dev and the published
|
|
7
|
+
* dist layout. Falls back to '0.0.0' rather than throwing, so a packaging change
|
|
8
|
+
* that moves the file can never crash server startup over a cosmetic version string.
|
|
9
|
+
*/
|
|
10
|
+
export function readPackageVersion(fromUrl) {
|
|
11
|
+
try {
|
|
12
|
+
const require = createRequire(fromUrl);
|
|
13
|
+
const { version } = require('../package.json');
|
|
14
|
+
return typeof version === 'string' && version.length > 0 ? version : '0.0.0';
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return '0.0.0';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,CAAA;QACtC,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAyB,CAAA;QACtE,OAAO,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAA;IAC9E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAA;IAChB,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
4
4
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
5
5
|
import { initClient } from './client.js'
|
|
6
|
+
import { readPackageVersion } from './version.js'
|
|
6
7
|
|
|
7
8
|
import {
|
|
8
9
|
searchCompaniesName,
|
|
@@ -182,13 +183,21 @@ import {
|
|
|
182
183
|
loadSkillHandler,
|
|
183
184
|
} from './tools/load-skill.js'
|
|
184
185
|
|
|
185
|
-
// Initialize HTTP client (reads env vars)
|
|
186
|
-
|
|
186
|
+
// Initialize HTTP client (reads env vars). A missing/empty COLDIQ_API_KEY is a
|
|
187
|
+
// user-config error, not a bug — print the message without a stack trace.
|
|
188
|
+
try {
|
|
189
|
+
initClient()
|
|
190
|
+
} catch (err) {
|
|
191
|
+
console.error(err instanceof Error ? err.message : String(err))
|
|
192
|
+
process.exit(1)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const packageVersion = readPackageVersion(import.meta.url)
|
|
187
196
|
|
|
188
197
|
const server = new McpServer(
|
|
189
198
|
{
|
|
190
199
|
name: 'coldiq',
|
|
191
|
-
version:
|
|
200
|
+
version: packageVersion,
|
|
192
201
|
},
|
|
193
202
|
{
|
|
194
203
|
// Surfaced to the model at init. Enforces batching on the multi-company
|
|
@@ -37,6 +37,52 @@ export const searchCompaniesSchema = {
|
|
|
37
37
|
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_companies').join(', ')}. Provider names are matched fuzzily, so minor typos are tolerated.`),
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
// A call must carry at least one filter that actually NARROWS the result set,
|
|
41
|
+
// otherwise it forwards an unbounded query upstream and bills for arbitrary
|
|
42
|
+
// companies. This is an explicit allowlist of narrowing keys, not a denylist of
|
|
43
|
+
// response-shaping ones, on purpose: a future response-shaping field (e.g. a
|
|
44
|
+
// `sort` or `page` knob) added to the schema must never silently count as a
|
|
45
|
+
// filter and reopen the billing hole. Exclusion fields (`exclude_*`) are
|
|
46
|
+
// deliberately absent — excluding a domain narrows nothing on its own. Kept in
|
|
47
|
+
// sync with the server-side guard in src/router/verb-handler.ts.
|
|
48
|
+
const NARROWING_FILTER_KEYS = [
|
|
49
|
+
'keywords', 'countries', 'locations', 'industries', 'technologies',
|
|
50
|
+
'min_employees', 'max_employees', 'min_founded_year', 'max_founded_year',
|
|
51
|
+
'funding_stages', 'min_funding_amount', 'max_funding_amount',
|
|
52
|
+
'min_funding_year', 'max_funding_year', 'min_revenue', 'max_revenue',
|
|
53
|
+
'is_hiring', 'min_workforce_growth_pct', 'linkedin_search_url',
|
|
54
|
+
] as const
|
|
55
|
+
|
|
56
|
+
// A value narrows only when it actually constrains: a non-blank string, an array
|
|
57
|
+
// with at least one non-blank element, a non-zero finite number (a `min_*` of 0
|
|
58
|
+
// is a no-op bound), or boolean `true` (is_hiring is ignored upstream unless true).
|
|
59
|
+
function isNarrowingValue(value: unknown): boolean {
|
|
60
|
+
if (value === undefined || value === null) return false
|
|
61
|
+
if (typeof value === 'string') return value.trim().length > 0
|
|
62
|
+
if (typeof value === 'number') return Number.isFinite(value) && value !== 0
|
|
63
|
+
if (typeof value === 'boolean') return value === true
|
|
64
|
+
if (Array.isArray(value)) return value.some((el) => (typeof el === 'string' ? el.trim().length > 0 : el != null))
|
|
65
|
+
return true
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function hasDiscriminatingFilter(input: Record<string, unknown>): boolean {
|
|
69
|
+
return NARROWING_FILTER_KEYS.some((key) => isNarrowingValue(input[key]))
|
|
70
|
+
}
|
|
71
|
+
|
|
40
72
|
export async function searchCompaniesHandler(input: Record<string, unknown>) {
|
|
73
|
+
if (!hasDiscriminatingFilter(input)) {
|
|
74
|
+
return {
|
|
75
|
+
content: [
|
|
76
|
+
{
|
|
77
|
+
type: 'text' as const,
|
|
78
|
+
text: JSON.stringify({
|
|
79
|
+
error:
|
|
80
|
+
'search_companies needs at least one filter (keywords, countries, industries, employee range, technologies, funding, …). An unfiltered search would return arbitrary companies and still consume credits.',
|
|
81
|
+
}),
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
isError: true,
|
|
85
|
+
}
|
|
86
|
+
}
|
|
41
87
|
return callVerb('/companies/search', input)
|
|
42
88
|
}
|
package/src/version.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createRequire } from 'node:module'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The MCP server reports its own npm version to the client at init. package.json
|
|
5
|
+
* sits outside tsconfig rootDir, so it can't be imported — read it at runtime.
|
|
6
|
+
* The built entry (dist/index.js) sits exactly one directory below the package
|
|
7
|
+
* root, so '../package.json' resolves in both `tsx src/…` dev and the published
|
|
8
|
+
* dist layout. Falls back to '0.0.0' rather than throwing, so a packaging change
|
|
9
|
+
* that moves the file can never crash server startup over a cosmetic version string.
|
|
10
|
+
*/
|
|
11
|
+
export function readPackageVersion(fromUrl: string): string {
|
|
12
|
+
try {
|
|
13
|
+
const require = createRequire(fromUrl)
|
|
14
|
+
const { version } = require('../package.json') as { version?: string }
|
|
15
|
+
return typeof version === 'string' && version.length > 0 ? version : '0.0.0'
|
|
16
|
+
} catch {
|
|
17
|
+
return '0.0.0'
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
2
|
+
import { initClient } from '../../src/client.js'
|
|
3
|
+
import { searchCompaniesHandler } from '../../src/tools/search-companies.js'
|
|
4
|
+
|
|
5
|
+
describe('search_companies handler', () => {
|
|
6
|
+
const originalFetch = globalThis.fetch
|
|
7
|
+
let fetchSpy: ReturnType<typeof vi.fn>
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
initClient('http://test-api.local', 'test-key')
|
|
11
|
+
// Default: a spy that records calls but must NOT be invoked by rejection paths.
|
|
12
|
+
// Forwarding tests override globalThis.fetch with a real Response mock.
|
|
13
|
+
fetchSpy = vi.fn()
|
|
14
|
+
globalThis.fetch = fetchSpy as typeof fetch
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
globalThis.fetch = originalFetch
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const okFetch = () =>
|
|
22
|
+
vi.fn(async () => new Response(JSON.stringify({ companies: [], total: 0 }), { status: 200 })) as typeof fetch
|
|
23
|
+
|
|
24
|
+
it('rejects a call with no discriminating filter without hitting the API', async () => {
|
|
25
|
+
const result = await searchCompaniesHandler({})
|
|
26
|
+
|
|
27
|
+
expect(result.isError).toBe(true)
|
|
28
|
+
expect(JSON.parse(result.content[0].text).error).toMatch(/at least one filter/)
|
|
29
|
+
expect(fetchSpy).not.toHaveBeenCalled()
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('rejects when only response-shaping fields are set', async () => {
|
|
33
|
+
const result = await searchCompaniesHandler({ limit: 200, fields: 'compact', use_providers: ['apollo'] })
|
|
34
|
+
|
|
35
|
+
expect(result.isError).toBe(true)
|
|
36
|
+
expect(fetchSpy).not.toHaveBeenCalled()
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('rejects when filters are present but empty', async () => {
|
|
40
|
+
const result = await searchCompaniesHandler({ keywords: [], countries: [], linkedin_search_url: ' ' })
|
|
41
|
+
|
|
42
|
+
expect(result.isError).toBe(true)
|
|
43
|
+
expect(fetchSpy).not.toHaveBeenCalled()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('rejects arrays that contain only blank strings', async () => {
|
|
47
|
+
const result = await searchCompaniesHandler({ keywords: ['', ' '] })
|
|
48
|
+
|
|
49
|
+
expect(result.isError).toBe(true)
|
|
50
|
+
expect(fetchSpy).not.toHaveBeenCalled()
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('rejects is_hiring:false (upstream ignores it unless true)', async () => {
|
|
54
|
+
const result = await searchCompaniesHandler({ is_hiring: false, limit: 200 })
|
|
55
|
+
|
|
56
|
+
expect(result.isError).toBe(true)
|
|
57
|
+
expect(fetchSpy).not.toHaveBeenCalled()
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('rejects no-op zero min-bounds', async () => {
|
|
61
|
+
const result = await searchCompaniesHandler({ min_employees: 0, min_funding_amount: 0 })
|
|
62
|
+
|
|
63
|
+
expect(result.isError).toBe(true)
|
|
64
|
+
expect(fetchSpy).not.toHaveBeenCalled()
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('rejects an exclusion-only search (excludes narrow nothing on their own)', async () => {
|
|
68
|
+
const result = await searchCompaniesHandler({ exclude_domains: ['coldiq.com'] })
|
|
69
|
+
|
|
70
|
+
expect(result.isError).toBe(true)
|
|
71
|
+
expect(fetchSpy).not.toHaveBeenCalled()
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('forwards to the verb when at least one real filter is set', async () => {
|
|
75
|
+
globalThis.fetch = vi.fn(async () => {
|
|
76
|
+
return new Response(JSON.stringify({ companies: [], total: 0, _meta: { provider: 'apollo' } }), { status: 200 })
|
|
77
|
+
}) as typeof fetch
|
|
78
|
+
|
|
79
|
+
const result = await searchCompaniesHandler({ keywords: ['sales automation'], limit: 5 })
|
|
80
|
+
|
|
81
|
+
expect(result.isError).toBeFalsy()
|
|
82
|
+
expect(globalThis.fetch).toHaveBeenCalledOnce()
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('treats boolean true and non-zero numeric filters as discriminating', async () => {
|
|
86
|
+
globalThis.fetch = okFetch()
|
|
87
|
+
|
|
88
|
+
const hiring = await searchCompaniesHandler({ is_hiring: true })
|
|
89
|
+
const sized = await searchCompaniesHandler({ min_employees: 11 })
|
|
90
|
+
|
|
91
|
+
expect(hiring.isError).toBeFalsy()
|
|
92
|
+
expect(sized.isError).toBeFalsy()
|
|
93
|
+
})
|
|
94
|
+
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { readPackageVersion } from '../src/version.js'
|
|
3
|
+
|
|
4
|
+
describe('readPackageVersion', () => {
|
|
5
|
+
it('reports the real package.json version relative to the caller URL', () => {
|
|
6
|
+
// This test file sits at mcp/tests/, so '../package.json' from here is mcp/package.json.
|
|
7
|
+
const version = readPackageVersion(import.meta.url)
|
|
8
|
+
expect(version).toMatch(/^\d+\.\d+\.\d+/)
|
|
9
|
+
expect(version).not.toBe('0.1.0') // the old hardcoded placeholder
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('falls back to 0.0.0 instead of throwing when package.json cannot be resolved', () => {
|
|
13
|
+
const version = readPackageVersion('file:///nonexistent/deeply/nested/module.js')
|
|
14
|
+
expect(version).toBe('0.0.0')
|
|
15
|
+
})
|
|
16
|
+
})
|