devtools-mcp-server 1.0.1

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,114 @@
1
+ # DevTools MCP Server
2
+
3
+ A powerful MCP (Model Context Protocol) server that gives AI coding assistants access to 30+ developer tools — QR codes, screenshots, PDFs, crypto prices, email validation, AI text processing, currency exchange, and much more.
4
+
5
+ Works with **Claude Code**, **Cursor**, **Windsurf**, **Cline**, and any MCP-compatible AI assistant.
6
+
7
+ ## Quick Start
8
+
9
+ ### With Claude Code
10
+ ```bash
11
+ claude mcp add devtools-mcp-server -- npx devtools-mcp-server
12
+ ```
13
+
14
+ ### With Cursor / Windsurf
15
+ Add to your MCP config:
16
+ ```json
17
+ {
18
+ "mcpServers": {
19
+ "devtools": {
20
+ "command": "npx",
21
+ "args": ["devtools-mcp-server"],
22
+ "env": {
23
+ "DEVTOOLS_API_KEY": "your-api-key"
24
+ }
25
+ }
26
+ }
27
+ }
28
+ ```
29
+
30
+ ## Get Your Free API Key
31
+
32
+ ```bash
33
+ curl -X POST https://api.commandsector.in/api-key \
34
+ -H "Content-Type: application/json" \
35
+ -d '{"email": "you@example.com"}'
36
+ ```
37
+
38
+ Free tier: 100 requests/day, 10/minute.
39
+
40
+ ## Available Tools (30)
41
+
42
+ ### QR Codes
43
+ - `generate_qr_code` — Generate QR codes in 6 styles (standard, rounded, dots, elegant, micro, bold), PNG/SVG/base64
44
+
45
+ ### Screenshots
46
+ - `take_screenshot` — Capture any website as PNG with custom viewport
47
+
48
+ ### Email Validation
49
+ - `validate_email` — Full validation: format, DNS/MX, disposable detection, typo suggestions
50
+ - `validate_emails_batch` — Validate multiple emails at once
51
+
52
+ ### PDF Tools
53
+ - `extract_pdf_text` — Extract text from PDF URLs
54
+ - `get_pdf_metadata` — Get PDF metadata (title, author, pages)
55
+
56
+ ### Crypto Prices
57
+ - `get_crypto_price` — Real-time price for any of 10,000+ coins
58
+ - `get_crypto_market` — Top coins by market cap
59
+ - `search_crypto` — Search by name or symbol
60
+ - `get_trending_crypto` — Currently trending coins
61
+
62
+ ### Currency Exchange
63
+ - `convert_currency` — Convert between 31 currencies (ECB rates)
64
+ - `get_exchange_rates` — Current exchange rates
65
+
66
+ ### IP Geolocation
67
+ - `geolocate_ip` — Country, city, timezone, ISP, coordinates
68
+
69
+ ### Text-to-Speech
70
+ - `text_to_speech` — 300+ voices, 70+ languages (Edge TTS)
71
+ - `list_tts_voices` — Browse available voices
72
+
73
+ ### AI Text Processing
74
+ - `summarize_text` — AI-powered summarization
75
+ - `translate_text` — Translation to any language
76
+ - `rewrite_text` — Rewrite in different tones
77
+
78
+ ### Developer Utilities
79
+ - `generate_uuid` — UUID v4 generation
80
+ - `generate_password` — Secure random passwords
81
+ - `hash_text` — MD5, SHA1, SHA256, SHA512
82
+ - `encode_base64` / `decode_base64` — Base64 encoding
83
+ - `format_json` — Pretty-print JSON
84
+
85
+ ### Image Generation
86
+ - `generate_placeholder_image` — Custom dimensions, colors, text
87
+ - `generate_social_card` — Social media / OG images
88
+ - `generate_avatar` — Unique avatars from name/email
89
+
90
+ ### Invoice Generation
91
+ - `generate_invoice` — Professional PDF invoices
92
+
93
+ ### URL Tools
94
+ - `extract_url_metadata` — Title, description, Open Graph data
95
+ - `expand_short_url` — Reveal shortened URL destinations
96
+
97
+ ## Environment Variables
98
+
99
+ | Variable | Required | Description |
100
+ |----------|----------|-------------|
101
+ | `DEVTOOLS_API_KEY` | Yes | Your API key (get free at signup endpoint) |
102
+ | `DEVTOOLS_API_URL` | No | Custom API URL (defaults to public endpoint) |
103
+
104
+ ## Pricing
105
+
106
+ | Tier | Price | Daily Limit | Rate Limit |
107
+ |------|-------|-------------|------------|
108
+ | Free | $0 | 100 requests | 10/min |
109
+ | Pro | $9.99/mo | 10,000 requests | 120/min |
110
+ | Enterprise | $49.99/mo | 1,000,000 requests | 600/min |
111
+
112
+ ## License
113
+
114
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,370 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
5
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
+ const zod_1 = require("zod");
7
+ const BASE_URL = process.env.DEVTOOLS_API_URL || "https://api.commandsector.in";
8
+ const API_KEY = process.env.DEVTOOLS_API_KEY || "";
9
+ async function apiCall(service, path, params, method = "GET", body) {
10
+ const url = new URL(`/api/${service}/${path}`, BASE_URL);
11
+ if (params) {
12
+ for (const [k, v] of Object.entries(params)) {
13
+ if (v !== undefined && v !== "")
14
+ url.searchParams.set(k, v);
15
+ }
16
+ }
17
+ const headers = {
18
+ "X-API-Key": API_KEY,
19
+ };
20
+ const options = { method, headers };
21
+ if (body && method === "POST") {
22
+ if (body instanceof FormData) {
23
+ options.body = body;
24
+ }
25
+ else {
26
+ headers["Content-Type"] = "application/json";
27
+ options.body = JSON.stringify(body);
28
+ }
29
+ }
30
+ const res = await fetch(url.toString(), options);
31
+ const contentType = res.headers.get("content-type") || "";
32
+ if (contentType.includes("application/json")) {
33
+ return await res.json();
34
+ }
35
+ else if (contentType.includes("image/") || contentType.includes("application/pdf") || contentType.includes("audio/")) {
36
+ const buffer = Buffer.from(await res.arrayBuffer());
37
+ return { binary: true, contentType, base64: buffer.toString("base64"), size: buffer.length };
38
+ }
39
+ else {
40
+ return { text: await res.text() };
41
+ }
42
+ }
43
+ function fmt(data) {
44
+ if (typeof data === "string")
45
+ return data;
46
+ return JSON.stringify(data, null, 2);
47
+ }
48
+ const server = new mcp_js_1.McpServer({
49
+ name: "devtools-mcp-server",
50
+ version: "1.0.0",
51
+ });
52
+ // ============== QR CODE TOOLS ==============
53
+ server.tool("generate_qr_code", "Generate a QR code image from text or URL. Returns PNG image data.", {
54
+ data: zod_1.z.string().describe("Text or URL to encode in QR code"),
55
+ size: zod_1.z.number().optional().describe("QR code size in pixels (default 300)"),
56
+ style: zod_1.z.enum(["standard", "rounded", "dots", "elegant", "micro", "bold"]).optional().describe("QR code style"),
57
+ format: zod_1.z.enum(["png", "svg", "base64"]).optional().describe("Output format (default png)"),
58
+ }, async ({ data, size, style, format }) => {
59
+ const params = { data };
60
+ if (size)
61
+ params.size = String(size);
62
+ if (style)
63
+ params.style = style;
64
+ if (format)
65
+ params.format = format;
66
+ const result = await apiCall("qr", "generate", params);
67
+ if (result.binary && result.base64) {
68
+ return { content: [{ type: "image", data: result.base64, mimeType: result.contentType }] };
69
+ }
70
+ return { content: [{ type: "text", text: fmt(result) }] };
71
+ });
72
+ // ============== SCREENSHOT TOOLS ==============
73
+ server.tool("take_screenshot", "Take a screenshot of any website URL. Returns PNG image.", {
74
+ url: zod_1.z.string().url().describe("Website URL to screenshot"),
75
+ width: zod_1.z.number().optional().describe("Viewport width (default 1280)"),
76
+ height: zod_1.z.number().optional().describe("Viewport height (default 720)"),
77
+ full_page: zod_1.z.boolean().optional().describe("Capture full scrollable page"),
78
+ }, async ({ url, width, height, full_page }) => {
79
+ const params = { url };
80
+ if (width)
81
+ params.width = String(width);
82
+ if (height)
83
+ params.height = String(height);
84
+ if (full_page)
85
+ params.full_page = "true";
86
+ const result = await apiCall("screenshot", "capture", params);
87
+ if (result.binary && result.base64) {
88
+ return { content: [{ type: "image", data: result.base64, mimeType: result.contentType }] };
89
+ }
90
+ return { content: [{ type: "text", text: fmt(result) }] };
91
+ });
92
+ // ============== EMAIL VALIDATION ==============
93
+ server.tool("validate_email", "Validate an email address - checks format, DNS/MX records, disposable domain detection, typo suggestions.", {
94
+ email: zod_1.z.string().describe("Email address to validate"),
95
+ }, async ({ email }) => {
96
+ const result = await apiCall("email", `validate/${encodeURIComponent(email)}`, {});
97
+ return { content: [{ type: "text", text: fmt(result) }] };
98
+ });
99
+ server.tool("validate_emails_batch", "Validate multiple email addresses at once.", {
100
+ emails: zod_1.z.array(zod_1.z.string()).describe("Array of email addresses to validate"),
101
+ }, async ({ emails }) => {
102
+ const result = await apiCall("email", "validate/batch", {}, "POST", { emails });
103
+ return { content: [{ type: "text", text: fmt(result) }] };
104
+ });
105
+ // ============== PDF TOOLS ==============
106
+ server.tool("extract_pdf_text", "Extract text content from a PDF file URL.", {
107
+ url: zod_1.z.string().url().describe("URL of the PDF file to extract text from"),
108
+ }, async ({ url }) => {
109
+ const result = await apiCall("pdf", "extract-text", { url });
110
+ return { content: [{ type: "text", text: fmt(result) }] };
111
+ });
112
+ server.tool("get_pdf_metadata", "Get metadata (title, author, pages, etc.) from a PDF file.", {
113
+ url: zod_1.z.string().url().describe("URL of the PDF file"),
114
+ }, async ({ url }) => {
115
+ const result = await apiCall("pdf", "metadata", { url });
116
+ return { content: [{ type: "text", text: fmt(result) }] };
117
+ });
118
+ // ============== CRYPTO PRICE TOOLS ==============
119
+ server.tool("get_crypto_price", "Get the current price and market data for a cryptocurrency.", {
120
+ coin_id: zod_1.z.string().describe("Coin ID (e.g., 'bitcoin', 'ethereum', 'solana')"),
121
+ currency: zod_1.z.string().optional().describe("Target currency (default 'usd')"),
122
+ }, async ({ coin_id, currency }) => {
123
+ const params = {};
124
+ if (currency)
125
+ params.vs_currency = currency;
126
+ const result = await apiCall("crypto", `coin/${coin_id}`, params);
127
+ return { content: [{ type: "text", text: fmt(result) }] };
128
+ });
129
+ server.tool("get_crypto_market", "Get top cryptocurrencies by market cap with prices and stats.", {
130
+ limit: zod_1.z.number().optional().describe("Number of coins to return (default 20, max 100)"),
131
+ currency: zod_1.z.string().optional().describe("Target currency (default 'usd')"),
132
+ }, async ({ limit, currency }) => {
133
+ const params = {};
134
+ if (limit)
135
+ params.limit = String(limit);
136
+ if (currency)
137
+ params.vs_currency = currency;
138
+ const result = await apiCall("crypto", "market", params);
139
+ return { content: [{ type: "text", text: fmt(result) }] };
140
+ });
141
+ server.tool("search_crypto", "Search for cryptocurrencies by name or symbol.", {
142
+ query: zod_1.z.string().describe("Search query (coin name or symbol)"),
143
+ }, async ({ query }) => {
144
+ const result = await apiCall("crypto", "search", { query });
145
+ return { content: [{ type: "text", text: fmt(result) }] };
146
+ });
147
+ server.tool("get_trending_crypto", "Get currently trending cryptocurrencies.", {}, async () => {
148
+ const result = await apiCall("crypto", "trending");
149
+ return { content: [{ type: "text", text: fmt(result) }] };
150
+ });
151
+ // ============== CURRENCY EXCHANGE ==============
152
+ server.tool("convert_currency", "Convert between currencies using real-time exchange rates from the European Central Bank.", {
153
+ amount: zod_1.z.number().describe("Amount to convert"),
154
+ from: zod_1.z.string().describe("Source currency code (e.g., 'USD', 'EUR', 'GBP')"),
155
+ to: zod_1.z.string().describe("Target currency code"),
156
+ }, async ({ amount, from, to }) => {
157
+ const result = await apiCall("currency", `convert/${amount}/${from}/${to}`);
158
+ return { content: [{ type: "text", text: fmt(result) }] };
159
+ });
160
+ server.tool("get_exchange_rates", "Get current exchange rates for a base currency.", {
161
+ base: zod_1.z.string().optional().describe("Base currency (default 'USD')"),
162
+ }, async ({ base }) => {
163
+ const params = {};
164
+ if (base)
165
+ params.base = base;
166
+ const result = await apiCall("currency", "rates", params);
167
+ return { content: [{ type: "text", text: fmt(result) }] };
168
+ });
169
+ // ============== IP GEOLOCATION ==============
170
+ server.tool("geolocate_ip", "Get geolocation data for an IP address - country, city, timezone, ISP, coordinates.", {
171
+ ip: zod_1.z.string().describe("IP address to look up"),
172
+ }, async ({ ip }) => {
173
+ const result = await apiCall("ip-geo", `lookup/${ip}`);
174
+ return { content: [{ type: "text", text: fmt(result) }] };
175
+ });
176
+ // ============== TEXT-TO-SPEECH ==============
177
+ server.tool("text_to_speech", "Convert text to speech audio using Microsoft Edge TTS. 300+ voices in 70+ languages.", {
178
+ text: zod_1.z.string().describe("Text to convert to speech"),
179
+ voice: zod_1.z.string().optional().describe("Voice name (e.g., 'en-US-AriaNeural', 'en-GB-SoniaNeural')"),
180
+ rate: zod_1.z.string().optional().describe("Speech rate (e.g., '+20%', '-10%')"),
181
+ }, async ({ text, voice, rate }) => {
182
+ const params = { text };
183
+ if (voice)
184
+ params.voice = voice;
185
+ if (rate)
186
+ params.rate = rate;
187
+ const result = await apiCall("tts", "synthesize", params);
188
+ if (result.binary) {
189
+ return { content: [{ type: "text", text: `Audio generated: ${result.size} bytes, format: ${result.contentType}. Base64 data available.` }] };
190
+ }
191
+ return { content: [{ type: "text", text: fmt(result) }] };
192
+ });
193
+ server.tool("list_tts_voices", "List available text-to-speech voices, optionally filtered by language.", {
194
+ language: zod_1.z.string().optional().describe("Filter by language code (e.g., 'en', 'es', 'fr')"),
195
+ }, async ({ language }) => {
196
+ const params = {};
197
+ if (language)
198
+ params.language = language;
199
+ const result = await apiCall("tts", "voices", params);
200
+ return { content: [{ type: "text", text: fmt(result) }] };
201
+ });
202
+ // ============== AI TEXT TOOLS ==============
203
+ server.tool("summarize_text", "Summarize a long text into key points using AI.", {
204
+ text: zod_1.z.string().describe("Text to summarize"),
205
+ length: zod_1.z.enum(["short", "medium", "long"]).optional().describe("Summary length"),
206
+ }, async ({ text, length }) => {
207
+ const body = { text };
208
+ if (length)
209
+ body.length = length;
210
+ const result = await apiCall("ai", "summarize", {}, "POST", body);
211
+ return { content: [{ type: "text", text: fmt(result) }] };
212
+ });
213
+ server.tool("translate_text", "Translate text to another language using AI.", {
214
+ text: zod_1.z.string().describe("Text to translate"),
215
+ target_language: zod_1.z.string().describe("Target language (e.g., 'Spanish', 'French', 'Japanese')"),
216
+ }, async ({ text, target_language }) => {
217
+ const result = await apiCall("ai", "translate", {}, "POST", { text, target_language });
218
+ return { content: [{ type: "text", text: fmt(result) }] };
219
+ });
220
+ server.tool("rewrite_text", "Rewrite text in a different tone or style using AI.", {
221
+ text: zod_1.z.string().describe("Text to rewrite"),
222
+ tone: zod_1.z.enum(["professional", "casual", "academic", "creative", "concise"]).optional().describe("Target tone"),
223
+ }, async ({ text, tone }) => {
224
+ const body = { text };
225
+ if (tone)
226
+ body.tone = tone;
227
+ const result = await apiCall("ai", "rewrite", {}, "POST", body);
228
+ return { content: [{ type: "text", text: fmt(result) }] };
229
+ });
230
+ // ============== DEVELOPER UTILITIES ==============
231
+ server.tool("generate_uuid", "Generate a UUID v4.", {}, async () => {
232
+ const result = await apiCall("devtools", "generate/uuid");
233
+ return { content: [{ type: "text", text: fmt(result) }] };
234
+ });
235
+ server.tool("generate_password", "Generate a secure random password.", {
236
+ length: zod_1.z.number().optional().describe("Password length (default 20)"),
237
+ include_special: zod_1.z.boolean().optional().describe("Include special characters"),
238
+ }, async ({ length, include_special }) => {
239
+ const params = {};
240
+ if (length)
241
+ params.length = String(length);
242
+ if (include_special !== undefined)
243
+ params.special = String(include_special);
244
+ const result = await apiCall("devtools", "generate/password", params);
245
+ return { content: [{ type: "text", text: fmt(result) }] };
246
+ });
247
+ server.tool("hash_text", "Hash text using various algorithms (md5, sha1, sha256, sha512).", {
248
+ text: zod_1.z.string().describe("Text to hash"),
249
+ algorithm: zod_1.z.enum(["md5", "sha1", "sha256", "sha512"]).optional().describe("Hash algorithm (default sha256)"),
250
+ }, async ({ text, algorithm }) => {
251
+ const algo = algorithm || "sha256";
252
+ const result = await apiCall("devtools", `hash/${algo}`, { text });
253
+ return { content: [{ type: "text", text: fmt(result) }] };
254
+ });
255
+ server.tool("encode_base64", "Encode text to base64.", {
256
+ text: zod_1.z.string().describe("Text to encode"),
257
+ }, async ({ text }) => {
258
+ const result = await apiCall("devtools", "encode/base64", { text });
259
+ return { content: [{ type: "text", text: fmt(result) }] };
260
+ });
261
+ server.tool("decode_base64", "Decode base64 text.", {
262
+ text: zod_1.z.string().describe("Base64 text to decode"),
263
+ }, async ({ text }) => {
264
+ const result = await apiCall("devtools", "decode/base64", { text });
265
+ return { content: [{ type: "text", text: fmt(result) }] };
266
+ });
267
+ server.tool("format_json", "Format/pretty-print JSON text.", {
268
+ json: zod_1.z.string().describe("JSON string to format"),
269
+ }, async ({ json }) => {
270
+ const result = await apiCall("devtools", "json/format", { json });
271
+ return { content: [{ type: "text", text: fmt(result) }] };
272
+ });
273
+ // ============== IMAGE GENERATION ==============
274
+ server.tool("generate_placeholder_image", "Generate a placeholder image with custom dimensions, colors, and text.", {
275
+ width: zod_1.z.number().describe("Image width in pixels"),
276
+ height: zod_1.z.number().describe("Image height in pixels"),
277
+ bg_color: zod_1.z.string().optional().describe("Background color hex (e.g., 'cccccc')"),
278
+ text: zod_1.z.string().optional().describe("Text to display on image"),
279
+ text_color: zod_1.z.string().optional().describe("Text color hex"),
280
+ }, async ({ width, height, bg_color, text, text_color }) => {
281
+ const params = {};
282
+ if (bg_color)
283
+ params.bg = bg_color;
284
+ if (text)
285
+ params.text = text;
286
+ if (text_color)
287
+ params.color = text_color;
288
+ const result = await apiCall("image", `placeholder/${width}x${height}`, params);
289
+ if (result.binary && result.base64) {
290
+ return { content: [{ type: "image", data: result.base64, mimeType: result.contentType }] };
291
+ }
292
+ return { content: [{ type: "text", text: fmt(result) }] };
293
+ });
294
+ server.tool("generate_social_card", "Generate a social media card / Open Graph image with title and description.", {
295
+ title: zod_1.z.string().describe("Card title"),
296
+ description: zod_1.z.string().optional().describe("Card description"),
297
+ theme: zod_1.z.string().optional().describe("Color theme"),
298
+ }, async ({ title, description, theme }) => {
299
+ const params = { title };
300
+ if (description)
301
+ params.description = description;
302
+ if (theme)
303
+ params.theme = theme;
304
+ const result = await apiCall("image", "social-card", params);
305
+ if (result.binary && result.base64) {
306
+ return { content: [{ type: "image", data: result.base64, mimeType: result.contentType }] };
307
+ }
308
+ return { content: [{ type: "text", text: fmt(result) }] };
309
+ });
310
+ server.tool("generate_avatar", "Generate a unique avatar/identicon from a name or email.", {
311
+ name: zod_1.z.string().describe("Name or email to generate avatar from"),
312
+ size: zod_1.z.number().optional().describe("Image size in pixels"),
313
+ }, async ({ name, size }) => {
314
+ const params = { name };
315
+ if (size)
316
+ params.size = String(size);
317
+ const result = await apiCall("image", "avatar", params);
318
+ if (result.binary && result.base64) {
319
+ return { content: [{ type: "image", data: result.base64, mimeType: result.contentType }] };
320
+ }
321
+ return { content: [{ type: "text", text: fmt(result) }] };
322
+ });
323
+ // ============== INVOICE GENERATION ==============
324
+ server.tool("generate_invoice", "Generate a professional PDF invoice.", {
325
+ from_name: zod_1.z.string().describe("Sender/company name"),
326
+ to_name: zod_1.z.string().describe("Recipient/client name"),
327
+ items: zod_1.z.array(zod_1.z.object({
328
+ description: zod_1.z.string(),
329
+ quantity: zod_1.z.number(),
330
+ unit_price: zod_1.z.number(),
331
+ })).describe("Invoice line items"),
332
+ invoice_number: zod_1.z.string().optional().describe("Invoice number"),
333
+ currency: zod_1.z.string().optional().describe("Currency code (default USD)"),
334
+ notes: zod_1.z.string().optional().describe("Additional notes"),
335
+ }, async ({ from_name, to_name, items, invoice_number, currency, notes }) => {
336
+ const body = { from_name, to_name, items };
337
+ if (invoice_number)
338
+ body.invoice_number = invoice_number;
339
+ if (currency)
340
+ body.currency = currency;
341
+ if (notes)
342
+ body.notes = notes;
343
+ const result = await apiCall("invoice", "generate", {}, "POST", body);
344
+ if (result.binary) {
345
+ return { content: [{ type: "text", text: `Invoice PDF generated: ${result.size} bytes. Content type: ${result.contentType}` }] };
346
+ }
347
+ return { content: [{ type: "text", text: fmt(result) }] };
348
+ });
349
+ // ============== URL TOOLS ==============
350
+ server.tool("extract_url_metadata", "Extract metadata (title, description, Open Graph, favicon) from a URL.", {
351
+ url: zod_1.z.string().url().describe("URL to extract metadata from"),
352
+ }, async ({ url }) => {
353
+ const result = await apiCall("url", "metadata", { url });
354
+ return { content: [{ type: "text", text: fmt(result) }] };
355
+ });
356
+ server.tool("expand_short_url", "Expand a shortened URL to reveal its final destination.", {
357
+ url: zod_1.z.string().url().describe("Short URL to expand"),
358
+ }, async ({ url }) => {
359
+ const result = await apiCall("url", "expand", { url });
360
+ return { content: [{ type: "text", text: fmt(result) }] };
361
+ });
362
+ // ============== STARTUP ==============
363
+ async function main() {
364
+ const transport = new stdio_js_1.StdioServerTransport();
365
+ await server.connect(transport);
366
+ }
367
+ main().catch((err) => {
368
+ console.error("Fatal error:", err);
369
+ process.exit(1);
370
+ });
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "devtools-mcp-server",
3
+ "version": "1.0.1",
4
+ "description": "MCP server providing 70+ developer tools - QR codes, PDFs, screenshots, crypto prices, email validation, AI text processing, and more. Use with Claude Code, Cursor, Windsurf, and other AI coding assistants.",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "devtools-mcp-server": "dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "start": "node dist/index.js",
12
+ "dev": "ts-node src/index.ts"
13
+ },
14
+ "keywords": [
15
+ "mcp",
16
+ "mcp-server",
17
+ "developer-tools",
18
+ "ai-tools",
19
+ "claude",
20
+ "cursor",
21
+ "qr-code",
22
+ "pdf",
23
+ "screenshot",
24
+ "crypto",
25
+ "email-validation",
26
+ "text-to-speech",
27
+ "currency-exchange",
28
+ "ip-geolocation"
29
+ ],
30
+ "author": "Ketan",
31
+ "license": "MIT",
32
+ "dependencies": {
33
+ "@modelcontextprotocol/sdk": "^1.0.0",
34
+ "zod": "^4.3.6"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^20.0.0",
38
+ "typescript": "^5.3.0"
39
+ },
40
+ "engines": {
41
+ "node": ">=18.0.0"
42
+ },
43
+ "files": [
44
+ "dist",
45
+ "README.md"
46
+ ]
47
+ }