@breaknorm_hu/mcp-server 0.1.6 → 0.2.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/index.js +44 -69
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -60,75 +60,51 @@ function str(val) {
|
|
|
60
60
|
}
|
|
61
61
|
var tools = [
|
|
62
62
|
{
|
|
63
|
-
name: "
|
|
64
|
-
description: "Search contacts with
|
|
63
|
+
name: "search_leads",
|
|
64
|
+
description: "Search for leads (contacts + company data in one result). This is THE main search tool. Returns contacts with their company info. Use suggest_industry_codes FIRST to get NAICS codes, then pass them here. You can request up to 500 results at once (no need to paginate for small queries). NEVER search by company name one by one!",
|
|
65
65
|
schema: z.object({
|
|
66
|
-
q: z.string().optional().describe("Free text search (name, title, company)"),
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
q: z.string().optional().describe("Free text search (name, title, company name)"),
|
|
67
|
+
naicsCodes: z.array(z.string()).optional().describe("NAICS codes from suggest_industry_codes \u2014 THE way to filter by industry"),
|
|
68
|
+
industry: z.array(z.string()).optional().describe("Industry name filter (use naicsCodes instead when possible)"),
|
|
69
69
|
city: z.array(z.string()).optional().describe("Filter by city names"),
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
county: z.array(z.string()).optional().describe("Filter by county (megye)"),
|
|
71
|
+
country: z.string().optional().describe("2-letter country code, default: HU"),
|
|
72
|
+
seniority: z.array(z.string()).optional().describe("c_level, vp, director, manager, head, senior, founder, partner, managing_director"),
|
|
73
|
+
department: z.array(z.string()).optional().describe("sales, marketing, it, hr, finance, engineering, c_suite, operations, legal, product"),
|
|
74
|
+
title: z.string().optional().describe("Job title keyword (e.g. '\xFCgyvezet\u0151', 'CEO', 'igazgat\xF3')"),
|
|
72
75
|
employee_min: z.number().int().optional().describe("Min company employees"),
|
|
73
76
|
employee_max: z.number().int().optional().describe("Max company employees"),
|
|
74
77
|
revenue_min: z.number().optional().describe("Min annual revenue in HUF"),
|
|
75
78
|
revenue_max: z.number().optional().describe("Max annual revenue in HUF"),
|
|
76
79
|
has_email: z.enum(["yes", "maybe", "no"]).optional().describe("Filter by email availability"),
|
|
77
|
-
|
|
78
|
-
|
|
80
|
+
has_phone: z.enum(["yes", "maybe", "no"]).optional().describe("Filter by phone availability"),
|
|
81
|
+
is_revealed: z.boolean().optional().describe("Only show already-revealed contacts"),
|
|
82
|
+
icp_score_min: z.number().min(0).max(100).optional().describe("Min ICP score (0-100)"),
|
|
83
|
+
limit: z.number().int().min(1).max(500).default(25).describe("Results to return (max 500, default 25). Use higher values to get more results at once!"),
|
|
84
|
+
page: z.number().int().default(1).describe("Page number (default 1)"),
|
|
79
85
|
searchToken: z.string().optional().describe("Required for page 2+, from page 1 response")
|
|
80
86
|
}),
|
|
81
87
|
handler: async (client, args) => {
|
|
82
|
-
return client.get("/
|
|
88
|
+
return client.get("/leads/search", {
|
|
83
89
|
q: str(args.q),
|
|
84
|
-
industry: arrayParam(args.industry),
|
|
85
90
|
naicsCodes: arrayParam(args.naicsCodes),
|
|
91
|
+
industry: arrayParam(args.industry),
|
|
86
92
|
city: arrayParam(args.city),
|
|
93
|
+
county: arrayParam(args.county),
|
|
94
|
+
country: str(args.country),
|
|
87
95
|
seniority: arrayParam(args.seniority),
|
|
88
96
|
department: arrayParam(args.department),
|
|
97
|
+
title: str(args.title),
|
|
89
98
|
employee_min: str(args.employee_min),
|
|
90
99
|
employee_max: str(args.employee_max),
|
|
91
100
|
revenue_min: str(args.revenue_min),
|
|
92
101
|
revenue_max: str(args.revenue_max),
|
|
93
102
|
has_email: str(args.has_email),
|
|
94
|
-
|
|
103
|
+
has_phone: str(args.has_phone),
|
|
104
|
+
is_revealed: str(args.is_revealed),
|
|
105
|
+
icp_score_min: str(args.icp_score_min),
|
|
95
106
|
limit: str(args.limit),
|
|
96
|
-
searchToken: str(args.searchToken)
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
name: "search_companies",
|
|
102
|
-
description: "Search companies with filters. Use suggest_industry_codes FIRST for industry filtering. NEVER search one by one \u2014 use filters!",
|
|
103
|
-
schema: z.object({
|
|
104
|
-
q: z.string().optional().describe("Company name search"),
|
|
105
|
-
industry: z.array(z.string()).optional(),
|
|
106
|
-
naicsCodes: z.array(z.string()).optional().describe("NAICS codes from suggest_industry_codes \u2014 BEST way to filter by industry"),
|
|
107
|
-
city: z.array(z.string()).optional(),
|
|
108
|
-
employee_min: z.number().int().optional(),
|
|
109
|
-
employee_max: z.number().int().optional(),
|
|
110
|
-
revenue_min: z.number().optional().describe("Min annual revenue in HUF"),
|
|
111
|
-
revenue_max: z.number().optional().describe("Max annual revenue in HUF"),
|
|
112
|
-
has_website: z.boolean().optional(),
|
|
113
|
-
page: z.number().int().default(1),
|
|
114
|
-
limit: z.number().int().max(25).default(25),
|
|
115
|
-
sort: z.enum(["relevance", "name", "employee_count", "revenue", "icp_score"]).default("relevance"),
|
|
116
|
-
searchToken: z.string().optional()
|
|
117
|
-
}),
|
|
118
|
-
handler: async (client, args) => {
|
|
119
|
-
return client.get("/companies/search", {
|
|
120
|
-
q: str(args.q),
|
|
121
|
-
industry: arrayParam(args.industry),
|
|
122
|
-
naicsCodes: arrayParam(args.naicsCodes),
|
|
123
|
-
city: arrayParam(args.city),
|
|
124
|
-
employee_min: str(args.employee_min),
|
|
125
|
-
employee_max: str(args.employee_max),
|
|
126
|
-
revenue_min: str(args.revenue_min),
|
|
127
|
-
revenue_max: str(args.revenue_max),
|
|
128
|
-
has_website: str(args.has_website),
|
|
129
107
|
page: str(args.page),
|
|
130
|
-
limit: str(args.limit),
|
|
131
|
-
sort: str(args.sort),
|
|
132
108
|
searchToken: str(args.searchToken)
|
|
133
109
|
});
|
|
134
110
|
}
|
|
@@ -312,34 +288,33 @@ var SERVER_NAME = "breaknorm";
|
|
|
312
288
|
var SERVER_VERSION = "0.1.0";
|
|
313
289
|
var INSTRUCTIONS = `Breaknorm MCP Server \u2014 B2B contact database for the Hungarian market.
|
|
314
290
|
|
|
315
|
-
CRITICAL RULES
|
|
291
|
+
CRITICAL RULES:
|
|
316
292
|
|
|
317
|
-
1.
|
|
318
|
-
|
|
319
|
-
Right: suggest_industry_codes("marketing \xFCgyn\xF6ks\xE9gek") \u2192 search_contacts(naicsCodes: [...], seniority: ["c_level"])
|
|
293
|
+
1. USE search_leads FOR EVERYTHING \u2014 it returns contacts WITH company data in one call.
|
|
294
|
+
You can request up to 500 results at once (limit: 500). No need to paginate for most queries!
|
|
320
295
|
|
|
321
|
-
2.
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
c. search_contacts(naicsCodes: [same codes], seniority: ["c_level", "director"]) \u2192 returns ALL decision-makers at once
|
|
325
|
-
This gives you hundreds of results in 2-3 API calls instead of searching one by one!
|
|
296
|
+
2. NEVER search by company name one by one! Use filters:
|
|
297
|
+
Wrong: search_leads(q: "Company A"), search_leads(q: "Company B"), ...
|
|
298
|
+
Right: suggest_industry_codes("marketing") \u2192 search_leads(naicsCodes: [...], seniority: ["c_level"], limit: 200)
|
|
326
299
|
|
|
327
|
-
3.
|
|
300
|
+
3. INDUSTRY SEARCH \u2014 always use NAICS codes:
|
|
301
|
+
a. suggest_industry_codes("rekl\xE1m \xE9s m\xE9dia \xFCgyn\xF6ks\xE9gek") \u2192 get NAICS codes ONCE
|
|
302
|
+
b. search_leads(naicsCodes: [codes], employee_min: 5, seniority: ["c_level"], limit: 200)
|
|
303
|
+
c. If you need more pages, reuse the SAME naicsCodes \u2014 NEVER call suggest_industry_codes again!
|
|
328
304
|
|
|
329
|
-
4.
|
|
305
|
+
4. WORKFLOW for building a lead list:
|
|
330
306
|
a. get_credits \u2014 check balance
|
|
331
|
-
b. suggest_industry_codes \u2014
|
|
332
|
-
c.
|
|
333
|
-
d.
|
|
334
|
-
e.
|
|
335
|
-
f.
|
|
336
|
-
g.
|
|
337
|
-
h.
|
|
338
|
-
i. export_list \u2014 CSV export
|
|
307
|
+
b. suggest_industry_codes \u2014 get NAICS codes (ONCE!)
|
|
308
|
+
c. search_leads \u2014 find leads with all filters, up to 500 at once
|
|
309
|
+
d. estimate_cost \u2014 calculate reveal cost
|
|
310
|
+
e. [Wait for user approval of the cost]
|
|
311
|
+
f. bulk_reveal_contacts \u2014 get emails (up to 1000 at once)
|
|
312
|
+
g. create_list + add_contacts_to_list \u2014 organize
|
|
313
|
+
h. export_list \u2014 CSV export
|
|
339
314
|
|
|
340
|
-
5.
|
|
341
|
-
6.
|
|
342
|
-
7. Bulk operations are async \u2014 poll with check_job_status.`;
|
|
315
|
+
5. Before ANY paid operation (reveal, scoring), call estimate_cost and get user approval.
|
|
316
|
+
6. Credit costs: email=1, phone=10, both=11, ICP scoring=1 per company.
|
|
317
|
+
7. Search is FREE. Bulk operations are async \u2014 poll with check_job_status.`;
|
|
343
318
|
async function main() {
|
|
344
319
|
const apiKey = process.env.BREAKNORM_API_KEY;
|
|
345
320
|
if (!apiKey) {
|