@breaknorm_hu/mcp-server 0.1.3 → 0.1.5

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.
Files changed (2) hide show
  1. package/dist/index.js +46 -27
  2. 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 the Breaknorm contact database. Returns contacts matching filters. Use get_search_filters first to discover available filter values. Results paginated (max 25/page). For page 2+, pass searchToken from page 1.",
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("Filter by seniority: c_level, vp, director, manager, head, senior, founder, partner"),
70
- department: z.array(z.string()).optional().describe("Filter by department: sales, marketing, it, hr, finance, engineering, c_suite"),
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 in the Breaknorm database.",
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),
@@ -150,6 +154,20 @@ var tools = [
150
154
  return { data: trimmed };
151
155
  }
152
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
+ return client.get("/search/naics-suggest", {
166
+ description: str(args.description),
167
+ precision: str(args.precision) || "balanced"
168
+ });
169
+ }
170
+ },
153
171
  {
154
172
  name: "get_contact",
155
173
  description: "Get details of a single contact (public fields, no revealed data).",
@@ -286,33 +304,34 @@ var SERVER_NAME = "breaknorm";
286
304
  var SERVER_VERSION = "0.1.0";
287
305
  var INSTRUCTIONS = `Breaknorm MCP Server \u2014 B2B contact database for the Hungarian market.
288
306
 
289
- IMPORTANT RULES:
290
- 1. Before ANY paid operation (reveal_contact, bulk_reveal_contacts, score_companies),
291
- ALWAYS call estimate_cost first and present the cost to the user for approval.
292
- Never execute paid operations without explicit user confirmation.
307
+ CRITICAL RULES \u2014 READ CAREFULLY:
308
+
309
+ 1. NEVER search by company name one by one! ALWAYS use filters to get bulk results.
310
+ Wrong: search_contacts(q: "Company A"), search_contacts(q: "Company B"), ...
311
+ Right: suggest_industry_codes("marketing \xFCgyn\xF6ks\xE9gek") \u2192 search_contacts(naicsCodes: [...], seniority: ["c_level"])
293
312
 
294
- 2. Recommended workflow for building a lead list:
295
- a. get_credits \u2014 check current balance
296
- b. get_search_filters \u2014 discover available filter values
297
- c. search_companies \u2014 find target companies matching criteria
298
- d. search_contacts \u2014 find people at those companies
299
- e. estimate_cost \u2014 calculate total cost for reveals
300
- f. [Wait for user approval of the cost]
301
- g. bulk_reveal_contacts \u2014 get email/phone data
302
- h. create_list + add_contacts_to_list \u2014 organize results
303
- i. export_list \u2014 export as CSV if needed
313
+ 2. INDUSTRY SEARCH WORKFLOW \u2014 this is how it works:
314
+ a. suggest_industry_codes("rekl\xE1m \xE9s m\xE9dia \xFCgyn\xF6ks\xE9gek") \u2192 returns NAICS codes
315
+ b. search_companies(naicsCodes: [codes from step a], employee_min: 5) \u2192 returns ALL matching companies at once
316
+ c. search_contacts(naicsCodes: [same codes], seniority: ["c_level", "director"]) \u2192 returns ALL decision-makers at once
317
+ This gives you hundreds of results in 2-3 API calls instead of searching one by one!
304
318
 
305
- 3. Credit costs:
306
- - Email reveal: 1 credit per contact
307
- - Phone reveal: 10 credits per contact
308
- - Both (email + phone): 11 credits per contact
309
- - ICP company scoring: 1 credit per company
319
+ 3. Before ANY paid operation (reveal, scoring), call estimate_cost first and get user approval.
310
320
 
311
- 4. Search results are paginated (max 25 per page). For page 2+,
312
- you must pass the searchToken from the page 1 response.
321
+ 4. Recommended workflow for building a lead list:
322
+ a. get_credits \u2014 check balance
323
+ b. suggest_industry_codes \u2014 convert industry description to NAICS codes
324
+ c. search_companies \u2014 find companies with naicsCodes + size + location filters
325
+ d. search_contacts \u2014 find decision-makers with naicsCodes + seniority + department filters
326
+ e. estimate_cost \u2014 calculate cost
327
+ f. [Wait for user approval]
328
+ g. bulk_reveal_contacts \u2014 get emails (up to 1000 at once!)
329
+ h. create_list + add_contacts_to_list \u2014 organize
330
+ i. export_list \u2014 CSV export
313
331
 
314
- 5. Bulk operations (reveal, ICP scoring) are async. They return a jobId.
315
- Use check_job_status to poll for completion.`;
332
+ 5. Credit costs: email=1, phone=10, both=11, ICP scoring=1 per company
333
+ 6. Search is FREE and paginated (25/page). Use searchToken for page 2+.
334
+ 7. Bulk operations are async \u2014 poll with check_job_status.`;
316
335
  async function main() {
317
336
  const apiKey = process.env.BREAKNORM_API_KEY;
318
337
  if (!apiKey) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@breaknorm_hu/mcp-server",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Breaknorm MCP Server — AI agent interface for B2B contact database",
5
5
  "type": "module",
6
6
  "bin": {