@breaknorm_hu/mcp-server 0.1.2 → 0.1.4
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 +73 -30
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -61,13 +61,14 @@ function str(val) {
|
|
|
61
61
|
var tools = [
|
|
62
62
|
{
|
|
63
63
|
name: "search_contacts",
|
|
64
|
-
description: "Search
|
|
64
|
+
description: "Search contacts with filters. Use suggest_industry_codes FIRST to convert industry descriptions to NAICS codes, then pass them here. NEVER search by company name one by one \u2014 always use filters to get bulk results!",
|
|
65
65
|
schema: z.object({
|
|
66
66
|
q: z.string().optional().describe("Free text search (name, title, company)"),
|
|
67
67
|
industry: z.array(z.string()).optional().describe("Filter by industry names"),
|
|
68
|
+
naicsCodes: z.array(z.string()).optional().describe("NAICS codes from suggest_industry_codes \u2014 THIS IS THE BEST WAY TO FILTER BY INDUSTRY"),
|
|
68
69
|
city: z.array(z.string()).optional().describe("Filter by city names"),
|
|
69
|
-
seniority: z.array(z.string()).optional().describe("
|
|
70
|
-
department: z.array(z.string()).optional().describe("
|
|
70
|
+
seniority: z.array(z.string()).optional().describe("c_level, vp, director, manager, head, senior, founder, partner"),
|
|
71
|
+
department: z.array(z.string()).optional().describe("sales, marketing, it, hr, finance, engineering, c_suite"),
|
|
71
72
|
employee_min: z.number().int().optional().describe("Min company employees"),
|
|
72
73
|
employee_max: z.number().int().optional().describe("Max company employees"),
|
|
73
74
|
has_email: z.enum(["yes", "maybe", "no"]).optional().describe("Filter by email availability"),
|
|
@@ -79,6 +80,7 @@ var tools = [
|
|
|
79
80
|
return client.get("/contacts/search", {
|
|
80
81
|
q: str(args.q),
|
|
81
82
|
industry: arrayParam(args.industry),
|
|
83
|
+
naicsCodes: arrayParam(args.naicsCodes),
|
|
82
84
|
city: arrayParam(args.city),
|
|
83
85
|
seniority: arrayParam(args.seniority),
|
|
84
86
|
department: arrayParam(args.department),
|
|
@@ -93,10 +95,11 @@ var tools = [
|
|
|
93
95
|
},
|
|
94
96
|
{
|
|
95
97
|
name: "search_companies",
|
|
96
|
-
description: "Search companies
|
|
98
|
+
description: "Search companies with filters. Use suggest_industry_codes FIRST for industry filtering. NEVER search one by one \u2014 use filters!",
|
|
97
99
|
schema: z.object({
|
|
98
100
|
q: z.string().optional().describe("Company name search"),
|
|
99
101
|
industry: z.array(z.string()).optional(),
|
|
102
|
+
naicsCodes: z.array(z.string()).optional().describe("NAICS codes from suggest_industry_codes \u2014 BEST way to filter by industry"),
|
|
100
103
|
city: z.array(z.string()).optional(),
|
|
101
104
|
employee_min: z.number().int().optional(),
|
|
102
105
|
employee_max: z.number().int().optional(),
|
|
@@ -110,6 +113,7 @@ var tools = [
|
|
|
110
113
|
return client.get("/companies/search", {
|
|
111
114
|
q: str(args.q),
|
|
112
115
|
industry: arrayParam(args.industry),
|
|
116
|
+
naicsCodes: arrayParam(args.naicsCodes),
|
|
113
117
|
city: arrayParam(args.city),
|
|
114
118
|
employee_min: str(args.employee_min),
|
|
115
119
|
employee_max: str(args.employee_max),
|
|
@@ -123,9 +127,47 @@ var tools = [
|
|
|
123
127
|
},
|
|
124
128
|
{
|
|
125
129
|
name: "get_search_filters",
|
|
126
|
-
description: "Get
|
|
127
|
-
schema: z.object({
|
|
128
|
-
|
|
130
|
+
description: "Get available filter values with counts. Call this FIRST before searching. Returns top values per category (max 50 each to keep response small).",
|
|
131
|
+
schema: z.object({
|
|
132
|
+
category: z.enum(["all", "industries", "cities", "counties", "seniorities", "departments", "companyTypes"]).default("all").optional().describe("Which filter category to fetch. Use 'all' for overview (top 20 each) or a specific category for full list (top 50).")
|
|
133
|
+
}),
|
|
134
|
+
handler: async (client, args) => {
|
|
135
|
+
const result = await client.get("/search/filters");
|
|
136
|
+
const data = result.data;
|
|
137
|
+
const cat = args.category || "all";
|
|
138
|
+
const limit = cat === "all" ? 20 : 50;
|
|
139
|
+
if (cat !== "all" && data[cat]) {
|
|
140
|
+
return { data: { [cat]: data[cat].slice(0, limit) } };
|
|
141
|
+
}
|
|
142
|
+
const trimmed = {};
|
|
143
|
+
for (const [key, values] of Object.entries(data)) {
|
|
144
|
+
if (Array.isArray(values)) {
|
|
145
|
+
trimmed[key] = values.slice(0, limit);
|
|
146
|
+
if (values.length > limit) {
|
|
147
|
+
trimmed[`${key}_total`] = values.length;
|
|
148
|
+
trimmed[`${key}_note`] = `Showing top ${limit} of ${values.length}. Use category="${key}" for more.`;
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
trimmed[key] = values;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return { data: trimmed };
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: "suggest_industry_codes",
|
|
159
|
+
description: "IMPORTANT: Use this BEFORE searching by industry. Converts a natural language industry description (e.g. 'marketing \xFCgyn\xF6ks\xE9gek', 'IT szolg\xE1ltat\xF3k') into NAICS codes that the search endpoints understand. Pass the returned codes as the naicsCodes parameter in search_contacts or search_companies. This is how industry filtering works \u2014 do NOT search by company name one by one!",
|
|
160
|
+
schema: z.object({
|
|
161
|
+
description: z.string().describe("Industry description in natural language, e.g. 'rekl\xE1m \xE9s m\xE9dia \xFCgyn\xF6ks\xE9gek' or 'IT consulting'"),
|
|
162
|
+
precision: z.enum(["strict", "balanced", "broad"]).default("balanced").optional().describe("strict = exact match, balanced = recommended, broad = wider results")
|
|
163
|
+
}),
|
|
164
|
+
handler: async (client, args) => {
|
|
165
|
+
const result = await client.post("/search/naics-suggest", {
|
|
166
|
+
description: args.description,
|
|
167
|
+
precision: args.precision || "balanced"
|
|
168
|
+
});
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
129
171
|
},
|
|
130
172
|
{
|
|
131
173
|
name: "get_contact",
|
|
@@ -263,33 +305,34 @@ var SERVER_NAME = "breaknorm";
|
|
|
263
305
|
var SERVER_VERSION = "0.1.0";
|
|
264
306
|
var INSTRUCTIONS = `Breaknorm MCP Server \u2014 B2B contact database for the Hungarian market.
|
|
265
307
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
308
|
+
CRITICAL RULES \u2014 READ CAREFULLY:
|
|
309
|
+
|
|
310
|
+
1. NEVER search by company name one by one! ALWAYS use filters to get bulk results.
|
|
311
|
+
Wrong: search_contacts(q: "Company A"), search_contacts(q: "Company B"), ...
|
|
312
|
+
Right: suggest_industry_codes("marketing \xFCgyn\xF6ks\xE9gek") \u2192 search_contacts(naicsCodes: [...], seniority: ["c_level"])
|
|
270
313
|
|
|
271
|
-
2.
|
|
272
|
-
a.
|
|
273
|
-
b.
|
|
274
|
-
c.
|
|
275
|
-
|
|
276
|
-
e. estimate_cost \u2014 calculate total cost for reveals
|
|
277
|
-
f. [Wait for user approval of the cost]
|
|
278
|
-
g. bulk_reveal_contacts \u2014 get email/phone data
|
|
279
|
-
h. create_list + add_contacts_to_list \u2014 organize results
|
|
280
|
-
i. export_list \u2014 export as CSV if needed
|
|
314
|
+
2. INDUSTRY SEARCH WORKFLOW \u2014 this is how it works:
|
|
315
|
+
a. suggest_industry_codes("rekl\xE1m \xE9s m\xE9dia \xFCgyn\xF6ks\xE9gek") \u2192 returns NAICS codes
|
|
316
|
+
b. search_companies(naicsCodes: [codes from step a], employee_min: 5) \u2192 returns ALL matching companies at once
|
|
317
|
+
c. search_contacts(naicsCodes: [same codes], seniority: ["c_level", "director"]) \u2192 returns ALL decision-makers at once
|
|
318
|
+
This gives you hundreds of results in 2-3 API calls instead of searching one by one!
|
|
281
319
|
|
|
282
|
-
3.
|
|
283
|
-
- Email reveal: 1 credit per contact
|
|
284
|
-
- Phone reveal: 10 credits per contact
|
|
285
|
-
- Both (email + phone): 11 credits per contact
|
|
286
|
-
- ICP company scoring: 1 credit per company
|
|
320
|
+
3. Before ANY paid operation (reveal, scoring), call estimate_cost first and get user approval.
|
|
287
321
|
|
|
288
|
-
4.
|
|
289
|
-
|
|
322
|
+
4. Recommended workflow for building a lead list:
|
|
323
|
+
a. get_credits \u2014 check balance
|
|
324
|
+
b. suggest_industry_codes \u2014 convert industry description to NAICS codes
|
|
325
|
+
c. search_companies \u2014 find companies with naicsCodes + size + location filters
|
|
326
|
+
d. search_contacts \u2014 find decision-makers with naicsCodes + seniority + department filters
|
|
327
|
+
e. estimate_cost \u2014 calculate cost
|
|
328
|
+
f. [Wait for user approval]
|
|
329
|
+
g. bulk_reveal_contacts \u2014 get emails (up to 1000 at once!)
|
|
330
|
+
h. create_list + add_contacts_to_list \u2014 organize
|
|
331
|
+
i. export_list \u2014 CSV export
|
|
290
332
|
|
|
291
|
-
5.
|
|
292
|
-
|
|
333
|
+
5. Credit costs: email=1, phone=10, both=11, ICP scoring=1 per company
|
|
334
|
+
6. Search is FREE and paginated (25/page). Use searchToken for page 2+.
|
|
335
|
+
7. Bulk operations are async \u2014 poll with check_job_status.`;
|
|
293
336
|
async function main() {
|
|
294
337
|
const apiKey = process.env.BREAKNORM_API_KEY;
|
|
295
338
|
if (!apiKey) {
|