@localleads/mcp 0.1.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/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # @localleads/mcp
2
+
3
+ Stdio [Model Context Protocol](https://modelcontextprotocol.io) server for [LocalLeads](https://leads.postorbit.io). Connects Claude Desktop, Cursor, VS Code, and other local MCP clients to the LocalLeads REST API so the model can search Google Maps for businesses, enrich contacts, and check your credit balance without leaving the chat.
4
+
5
+ > **Using Claude.ai (web)?** Use the **remote** MCP connector at `https://leadsapi.postorbit.io/mcp` instead. It supports OAuth so claude.ai can connect with one click. See [the docs](https://leads.postorbit.io/docs/api/mcp) for details.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install -g @localleads/mcp
11
+ # or run on demand with npx (no install)
12
+ npx -y @localleads/mcp
13
+ ```
14
+
15
+ ## Configure
16
+
17
+ You need a LocalLeads API key (starts with `ll_`). Generate one at **Settings → Security → API Keys** in your LocalLeads dashboard.
18
+
19
+ ### Claude Desktop
20
+
21
+ Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
22
+
23
+ ```json
24
+ {
25
+ "mcpServers": {
26
+ "localleads": {
27
+ "command": "npx",
28
+ "args": ["-y", "@localleads/mcp"],
29
+ "env": {
30
+ "LOCALLEADS_API_KEY": "ll_your_key_here"
31
+ }
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ Restart Claude Desktop. The LocalLeads tool icon (🔨) appears in the chat toolbar.
38
+
39
+ ### Cursor / VS Code
40
+
41
+ Add to `.cursor/mcp.json` or `.vscode/mcp.json`:
42
+
43
+ ```json
44
+ {
45
+ "servers": {
46
+ "localleads": {
47
+ "command": "npx",
48
+ "args": ["-y", "@localleads/mcp"],
49
+ "env": {
50
+ "LOCALLEADS_API_KEY": "ll_your_key_here"
51
+ }
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ ## Tools
58
+
59
+ | Name | Cost | What it does |
60
+ |---|---|---|
61
+ | `search_leads` | charges credits | Search Google Maps for businesses in a location. Returns a query ID. |
62
+ | `get_query_progress` | free | Poll the status of an in-flight search. |
63
+ | `get_search_results` | free | Retrieve leads from a completed search. |
64
+ | `list_all_leads` | free | List every lead saved in the account, with filters. |
65
+ | `enrich_leads` | 1 credit per lead | Find verified business emails for one or more leads. |
66
+ | `get_enrichment_result` | free | Get the email + confidence score for an enriched lead. |
67
+ | `list_enrichment_jobs` | free | List in-flight search and enrichment jobs. |
68
+ | `check_credits` | free | Return current credit balance. |
69
+
70
+ ## Environment variables
71
+
72
+ | Var | Required | Description |
73
+ |---|---|---|
74
+ | `LOCALLEADS_API_KEY` | yes | Your `ll_…` API key. |
75
+ | `LOCALLEADS_API_BASE` | no | Override the API base URL. Defaults to `https://leadsapi.postorbit.io`. Must be `https://`. |
76
+
77
+ ## Maintainers
78
+
79
+ Publishing a new version? See [PUBLISHING.md](https://github.com/EtherLabZ/LocalLeads/blob/main/leads-mcp/PUBLISHING.md) for the 2FA / token workflow.
80
+
81
+ ## License
82
+
83
+ MIT
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * LocalLeads MCP Server
4
+ *
5
+ * Exposes the LocalLeads REST API as MCP tools so Claude (and any other MCP
6
+ * client) can search local business leads, enrich contacts, and manage
7
+ * credits without leaving the conversation.
8
+ *
9
+ * Config (environment variables):
10
+ * LOCALLEADS_API_KEY required Your API key (starts with ll_)
11
+ * LOCALLEADS_API_BASE optional Override the base URL (default: production)
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG"}
package/dist/index.js ADDED
@@ -0,0 +1,330 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * LocalLeads MCP Server
4
+ *
5
+ * Exposes the LocalLeads REST API as MCP tools so Claude (and any other MCP
6
+ * client) can search local business leads, enrich contacts, and manage
7
+ * credits without leaving the conversation.
8
+ *
9
+ * Config (environment variables):
10
+ * LOCALLEADS_API_KEY required Your API key (starts with ll_)
11
+ * LOCALLEADS_API_BASE optional Override the base URL (default: production)
12
+ */
13
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
14
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
15
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
16
+ // ─── Config ──────────────────────────────────────────────────────────────────
17
+ const API_KEY = process.env.LOCALLEADS_API_KEY ?? "";
18
+ const BASE_URL = process.env.LOCALLEADS_API_BASE ?? "https://leadsapi.postorbit.io";
19
+ if (!API_KEY) {
20
+ process.stderr.write("Error: LOCALLEADS_API_KEY environment variable is required.\n" +
21
+ "Generate one at https://leads.postorbit.io/dashboard/settings?tab=security\n");
22
+ process.exit(1);
23
+ }
24
+ // Only allow https:// base URLs to prevent accidental key exfiltration
25
+ if (!BASE_URL.startsWith("https://")) {
26
+ process.stderr.write("Error: LOCALLEADS_API_BASE must start with https://\n");
27
+ process.exit(1);
28
+ }
29
+ // ─── Input validation helpers ─────────────────────────────────────────────────
30
+ /**
31
+ * Validates a path segment (query ID, lead ID) to prevent path traversal.
32
+ * Allows alphanumeric characters, hyphens, and underscores only.
33
+ */
34
+ function assertSafeId(value, name) {
35
+ if (typeof value !== "string" || value.length === 0) {
36
+ throw new Error(`${name} must be a non-empty string`);
37
+ }
38
+ if (!/^[a-zA-Z0-9_-]+$/.test(value)) {
39
+ throw new Error(`${name} contains invalid characters. Only alphanumeric, hyphens, and underscores are allowed.`);
40
+ }
41
+ if (value.length > 128) {
42
+ throw new Error(`${name} is too long (max 128 characters)`);
43
+ }
44
+ return value;
45
+ }
46
+ /** Clamps a numeric argument to an inclusive range. */
47
+ function clampInt(value, min, max, fallback) {
48
+ const n = typeof value === "number" ? Math.floor(value) : fallback;
49
+ return Math.min(Math.max(n, min), max);
50
+ }
51
+ // ─── API client ──────────────────────────────────────────────────────────────
52
+ async function call(method, path, body) {
53
+ const url = `${BASE_URL}${path}`;
54
+ const res = await fetch(url, {
55
+ method,
56
+ headers: {
57
+ Authorization: `Bearer ${API_KEY}`,
58
+ "Content-Type": "application/json",
59
+ Accept: "application/json",
60
+ },
61
+ body: body !== undefined ? JSON.stringify(body) : undefined,
62
+ });
63
+ const json = (await res.json());
64
+ if (!json.success) {
65
+ throw new Error(json.error ?? `API error ${res.status}`);
66
+ }
67
+ // Return both data and meta when present (pagination)
68
+ if (json.meta !== undefined) {
69
+ return { data: json.data, meta: json.meta };
70
+ }
71
+ return json.data;
72
+ }
73
+ // ─── Tool definitions ─────────────────────────────────────────────────────────
74
+ const TOOLS = [
75
+ {
76
+ name: "search_leads",
77
+ description: "Search Google Maps for local businesses and generate a lead list. " +
78
+ "Returns a query ID you can poll with get_search_results. " +
79
+ "Each search costs 1 credit. Use check_credits first if unsure of balance.",
80
+ inputSchema: {
81
+ type: "object",
82
+ properties: {
83
+ query: {
84
+ type: "string",
85
+ description: 'What to search for, e.g. "plumbers", "coffee shops", "dentists"',
86
+ },
87
+ location: {
88
+ type: "string",
89
+ description: 'City or region to search in, e.g. "London", "Manchester", "New York"',
90
+ },
91
+ country: {
92
+ type: "string",
93
+ description: 'Two-letter ISO country code, e.g. "GB", "US", "AU"',
94
+ default: "GB",
95
+ },
96
+ resultLimit: {
97
+ type: "number",
98
+ description: "Maximum number of leads to return (1–100, default 20)",
99
+ default: 20,
100
+ },
101
+ },
102
+ required: ["query", "location"],
103
+ },
104
+ },
105
+ {
106
+ name: "get_search_results",
107
+ description: "Retrieve the leads from a completed search query. " +
108
+ "Poll this after search_leads until status is COMPLETED. " +
109
+ "Returns an array of business leads with name, address, phone, website, rating.",
110
+ inputSchema: {
111
+ type: "object",
112
+ properties: {
113
+ queryId: {
114
+ type: "string",
115
+ description: "The query ID returned by search_leads",
116
+ },
117
+ limit: {
118
+ type: "number",
119
+ description: "Number of leads to return per page (default 20, max 100)",
120
+ default: 20,
121
+ },
122
+ offset: {
123
+ type: "number",
124
+ description: "Pagination offset (default 0)",
125
+ default: 0,
126
+ },
127
+ },
128
+ required: ["queryId"],
129
+ },
130
+ },
131
+ {
132
+ name: "get_query_progress",
133
+ description: "Check the progress of an in-flight search query. " +
134
+ "Returns status (PENDING, PROCESSING, COMPLETED, FAILED) and percent complete.",
135
+ inputSchema: {
136
+ type: "object",
137
+ properties: {
138
+ queryId: {
139
+ type: "string",
140
+ description: "The query ID returned by search_leads",
141
+ },
142
+ },
143
+ required: ["queryId"],
144
+ },
145
+ },
146
+ {
147
+ name: "list_all_leads",
148
+ description: "List all leads saved in the account across all searches. " +
149
+ "Supports pagination and optional text filtering.",
150
+ inputSchema: {
151
+ type: "object",
152
+ properties: {
153
+ limit: {
154
+ type: "number",
155
+ description: "Leads per page (default 20, max 100)",
156
+ default: 20,
157
+ },
158
+ offset: {
159
+ type: "number",
160
+ description: "Pagination offset (default 0)",
161
+ default: 0,
162
+ },
163
+ search: {
164
+ type: "string",
165
+ description: "Optional text filter applied to business name and address",
166
+ },
167
+ },
168
+ required: [],
169
+ },
170
+ },
171
+ {
172
+ name: "enrich_leads",
173
+ description: "Start an enrichment job to find verified business emails for one or " +
174
+ "more leads. Returns a job ID. Each successful enrichment costs 1 credit.",
175
+ inputSchema: {
176
+ type: "object",
177
+ properties: {
178
+ leadIds: {
179
+ type: "array",
180
+ items: { type: "string" },
181
+ description: "IDs of leads to enrich. Either leadIds or queryId is required.",
182
+ },
183
+ queryId: {
184
+ type: "string",
185
+ description: "Enrich every lead in this query. Mutually exclusive with leadIds.",
186
+ },
187
+ maxCredits: {
188
+ type: "number",
189
+ description: "Optional safety cap on credits to spend.",
190
+ },
191
+ },
192
+ },
193
+ },
194
+ {
195
+ name: "get_enrichment_result",
196
+ description: "Retrieve the enrichment result (email, confidence score, etc.) for a lead " +
197
+ "that has been enriched. Returns null if enrichment has not been run yet.",
198
+ inputSchema: {
199
+ type: "object",
200
+ properties: {
201
+ leadId: {
202
+ type: "string",
203
+ description: "The ID of the lead",
204
+ },
205
+ },
206
+ required: ["leadId"],
207
+ },
208
+ },
209
+ {
210
+ name: "list_enrichment_jobs",
211
+ description: "List all pending and completed enrichment jobs for the account. " +
212
+ "Useful for checking bulk enrichment status.",
213
+ inputSchema: {
214
+ type: "object",
215
+ properties: {},
216
+ required: [],
217
+ },
218
+ },
219
+ {
220
+ name: "check_credits",
221
+ description: "Check the current credit balance for the account. " +
222
+ "Returns monthly credits, bonus credits, used credits, and available credits.",
223
+ inputSchema: {
224
+ type: "object",
225
+ properties: {},
226
+ required: [],
227
+ },
228
+ },
229
+ ];
230
+ // ─── Tool handlers ────────────────────────────────────────────────────────────
231
+ async function handleTool(name, args) {
232
+ switch (name) {
233
+ case "search_leads": {
234
+ const result = await call("POST", "/api/v1/leads/search", {
235
+ query: String(args.query ?? "").slice(0, 200),
236
+ location: String(args.location ?? "").slice(0, 200),
237
+ country: String(args.country ?? "GB").slice(0, 2).toUpperCase(),
238
+ resultLimit: clampInt(args.resultLimit, 1, 100, 20),
239
+ });
240
+ return JSON.stringify(result, null, 2);
241
+ }
242
+ case "get_search_results": {
243
+ const queryId = assertSafeId(args.queryId, "queryId");
244
+ const params = new URLSearchParams();
245
+ params.set("limit", String(clampInt(args.limit, 1, 100, 20)));
246
+ params.set("offset", String(clampInt(args.offset, 0, 100_000, 0)));
247
+ const result = await call("GET", `/api/v1/leads/query/${queryId}/leads?${params}`);
248
+ return JSON.stringify(result, null, 2);
249
+ }
250
+ case "get_query_progress": {
251
+ const queryId = assertSafeId(args.queryId, "queryId");
252
+ const result = await call("GET", `/api/v1/leads/query/${queryId}/progress`);
253
+ return JSON.stringify(result, null, 2);
254
+ }
255
+ case "list_all_leads": {
256
+ const params = new URLSearchParams();
257
+ params.set("limit", String(clampInt(args.limit, 1, 100, 20)));
258
+ params.set("offset", String(clampInt(args.offset, 0, 100_000, 0)));
259
+ if (typeof args.search === "string" && args.search.length > 0) {
260
+ params.set("search", args.search.slice(0, 200));
261
+ }
262
+ const result = await call("GET", `/api/v1/leads/all?${params}`);
263
+ return JSON.stringify(result, null, 2);
264
+ }
265
+ case "enrich_leads": {
266
+ const leadIds = Array.isArray(args.leadIds)
267
+ ? args.leadIds.map((id) => assertSafeId(id, "leadIds[]"))
268
+ : undefined;
269
+ const queryId = typeof args.queryId === "string" && args.queryId.length > 0
270
+ ? assertSafeId(args.queryId, "queryId")
271
+ : undefined;
272
+ if (!leadIds && !queryId) {
273
+ throw new Error("Either leadIds or queryId is required");
274
+ }
275
+ const result = await call("POST", "/api/v1/enrichment/start", {
276
+ leadIds,
277
+ queryId,
278
+ maxCredits: typeof args.maxCredits === "number" ? args.maxCredits : undefined,
279
+ });
280
+ return JSON.stringify(result, null, 2);
281
+ }
282
+ case "get_enrichment_result": {
283
+ const leadId = assertSafeId(args.leadId, "leadId");
284
+ const result = await call("GET", `/api/v1/enrichment/lead/${leadId}`);
285
+ return JSON.stringify(result, null, 2);
286
+ }
287
+ case "list_enrichment_jobs": {
288
+ const result = await call("GET", "/api/v1/enrichment/jobs");
289
+ return JSON.stringify(result, null, 2);
290
+ }
291
+ case "check_credits": {
292
+ const result = await call("GET", "/api/v1/credits/balance");
293
+ return JSON.stringify(result, null, 2);
294
+ }
295
+ default:
296
+ throw new Error(`Unknown tool: ${name}`);
297
+ }
298
+ }
299
+ // ─── Server ───────────────────────────────────────────────────────────────────
300
+ const server = new Server({
301
+ name: "localleads",
302
+ version: "1.0.0",
303
+ }, {
304
+ capabilities: {
305
+ tools: {},
306
+ },
307
+ });
308
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
309
+ tools: TOOLS,
310
+ }));
311
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
312
+ const { name, arguments: args = {} } = request.params;
313
+ try {
314
+ const text = await handleTool(name, args);
315
+ return {
316
+ content: [{ type: "text", text }],
317
+ };
318
+ }
319
+ catch (err) {
320
+ const message = err instanceof Error ? err.message : String(err);
321
+ return {
322
+ content: [{ type: "text", text: `Error: ${message}` }],
323
+ isError: true,
324
+ };
325
+ }
326
+ });
327
+ // ─── Start ────────────────────────────────────────────────────────────────────
328
+ const transport = new StdioServerTransport();
329
+ await server.connect(transport);
330
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@localleads/mcp",
3
+ "version": "0.1.0",
4
+ "description": "Stdio MCP server for LocalLeads — let Claude Desktop, Cursor, and other local MCP clients search business leads, enrich contacts, and check credits via the LocalLeads API. For Claude.ai use the remote MCP connector at https://leadsapi.postorbit.io/mcp instead.",
5
+ "type": "module",
6
+ "bin": {
7
+ "localleads-mcp": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "dev": "tsx src/index.ts",
16
+ "start": "node dist/index.js",
17
+ "prepublishOnly": "npm run build"
18
+ },
19
+ "dependencies": {
20
+ "@modelcontextprotocol/sdk": "^1.29.0"
21
+ },
22
+ "devDependencies": {
23
+ "@types/node": "^22.0.0",
24
+ "tsx": "^4.19.0",
25
+ "typescript": "^5.7.0"
26
+ },
27
+ "engines": {
28
+ "node": ">=18"
29
+ },
30
+ "keywords": [
31
+ "mcp",
32
+ "model-context-protocol",
33
+ "claude",
34
+ "claude-desktop",
35
+ "cursor",
36
+ "leads",
37
+ "local-business",
38
+ "google-maps",
39
+ "lead-generation",
40
+ "localleads"
41
+ ],
42
+ "license": "MIT",
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "https://github.com/EtherLabZ/LocalLeads.git",
46
+ "directory": "leads-mcp"
47
+ },
48
+ "homepage": "https://leads.postorbit.io/docs/api/mcp",
49
+ "bugs": {
50
+ "url": "https://github.com/EtherLabZ/LocalLeads/issues"
51
+ }
52
+ }