@thenextgennexus/developer-tools-mcp-server 1.0.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,75 @@
1
+ # Developer Tools MCP Server
2
+
3
+ Access GitHub repos, npm/PyPI packages, Stack Overflow, arXiv, and Google Scholar — powered by [nexgendata](https://apify.com/nexgendata) on Apify.
4
+
5
+ ## Quick Start
6
+
7
+ ### Using npx (recommended)
8
+
9
+ ```bash
10
+ npx @nexgendata/developer-tools-mcp-server
11
+ ```
12
+
13
+ ### Install globally
14
+
15
+ ```bash
16
+ npm install -g @nexgendata/developer-tools-mcp-server
17
+ ```
18
+
19
+ ## Configure with Claude Desktop
20
+
21
+ Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
22
+
23
+ ```json
24
+ {
25
+ "mcpServers": {
26
+ "developer-tools-mcp-server": {
27
+ "command": "npx",
28
+ "args": [
29
+ "-y",
30
+ "@nexgendata/developer-tools-mcp-server"
31
+ ],
32
+ "env": {
33
+ "APIFY_TOKEN": "your-apify-token-optional"
34
+ }
35
+ }
36
+ }
37
+ }
38
+ ```
39
+
40
+ ## Configure with Cline
41
+
42
+ Add the same configuration to your Cline MCP settings.
43
+
44
+ ## Available Tools
45
+
46
+ | Tool | Description |
47
+ |------|-------------|
48
+ | `get_github_repo` | Get detailed information about a GitHub repository |
49
+ | `search_github` | Search GitHub repositories by keyword |
50
+ | `get_npm_package` | Get npm package details and stats |
51
+ | `get_pypi_package` | Get PyPI package details and stats |
52
+ | `search_stackoverflow` | Search Stack Overflow questions |
53
+ | `search_arxiv_papers` | Search arXiv for research papers |
54
+ | `search_scholar` | Search Google Scholar for academic papers |
55
+
56
+
57
+ ## Environment Variables
58
+
59
+ | Variable | Required | Description |
60
+ |----------|----------|-------------|
61
+ | `APIFY_TOKEN` | No | Your Apify API token for authenticated access. Without it, the server uses the public endpoint (rate-limited). |
62
+
63
+ ## How It Works
64
+
65
+ This MCP server acts as a local stdio bridge to the [nexgendata Apify MCP endpoint](https://nexgendata--developer-tools-mcp-server.apify.actor/mcp). When you call a tool, it forwards the request to Apify and returns the results.
66
+
67
+ ## Links
68
+
69
+ - [Apify Store](https://apify.com/nexgendata/developer-tools-mcp-server)
70
+ - [GitHub Repository](https://github.com/TheNextGenNexus/web-intelligence-mcp-servers)
71
+ - [nexgendata Blog](https://thenextgennexus.com)
72
+
73
+ ## License
74
+
75
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+ const APIFY_ENDPOINT = "https://nexgendata--developer-tools-mcp-server.apify.actor/mcp";
6
+ const APIFY_TOKEN = process.env.APIFY_TOKEN || "";
7
+ async function callApifyTool(toolName, args) {
8
+ const url = new URL(APIFY_ENDPOINT);
9
+ if (APIFY_TOKEN) {
10
+ url.searchParams.set("token", APIFY_TOKEN);
11
+ }
12
+ const body = {
13
+ jsonrpc: "2.0",
14
+ id: 1,
15
+ method: "tools/call",
16
+ params: {
17
+ name: toolName,
18
+ arguments: args
19
+ }
20
+ };
21
+ const response = await fetch(url.toString(), {
22
+ method: "POST",
23
+ headers: { "Content-Type": "application/json" },
24
+ body: JSON.stringify(body)
25
+ });
26
+ if (!response.ok) {
27
+ const errorText = await response.text();
28
+ throw new Error(`Apify API error (${response.status}): ${errorText}`);
29
+ }
30
+ const data = await response.json();
31
+ if (data.error) {
32
+ throw new Error(`Tool error: ${JSON.stringify(data.error)}`);
33
+ }
34
+ // Extract text content from MCP response
35
+ const result = data.result;
36
+ if (result?.content && Array.isArray(result.content)) {
37
+ return result.content
38
+ .filter((c) => c.type === "text")
39
+ .map((c) => c.text)
40
+ .join("\n");
41
+ }
42
+ return JSON.stringify(data.result, null, 2);
43
+ }
44
+ const server = new McpServer({
45
+ name: "developer-tools-mcp-server",
46
+ version: "1.0.0"
47
+ });
48
+ server.registerTool("get_github_repo", {
49
+ title: "Get Github Repo",
50
+ description: "Get GitHub repository details",
51
+ inputSchema: {
52
+ repoUrl: z.string().describe('GitHub repository URL')
53
+ },
54
+ annotations: {
55
+ readOnlyHint: true,
56
+ destructiveHint: false,
57
+ openWorldHint: true
58
+ }
59
+ }, async (args) => {
60
+ try {
61
+ const result = await callApifyTool("get_github_repo", args);
62
+ return {
63
+ content: [{ type: "text", text: result }]
64
+ };
65
+ }
66
+ catch (error) {
67
+ const message = error instanceof Error ? error.message : String(error);
68
+ return {
69
+ content: [{ type: "text", text: `Error: ${message}` }],
70
+ isError: true
71
+ };
72
+ }
73
+ });
74
+ server.registerTool("search_github", {
75
+ title: "Search Github",
76
+ description: "Search GitHub repositories",
77
+ inputSchema: {
78
+ query: z.string().describe('Search query'),
79
+ maxItems: z.number().default(10).describe('Maximum results')
80
+ },
81
+ annotations: {
82
+ readOnlyHint: true,
83
+ destructiveHint: false,
84
+ openWorldHint: true
85
+ }
86
+ }, async (args) => {
87
+ try {
88
+ const result = await callApifyTool("search_github", args);
89
+ return {
90
+ content: [{ type: "text", text: result }]
91
+ };
92
+ }
93
+ catch (error) {
94
+ const message = error instanceof Error ? error.message : String(error);
95
+ return {
96
+ content: [{ type: "text", text: `Error: ${message}` }],
97
+ isError: true
98
+ };
99
+ }
100
+ });
101
+ server.registerTool("get_npm_package", {
102
+ title: "Get Npm Package",
103
+ description: "Get npm package details",
104
+ inputSchema: {
105
+ packageName: z.string().describe('npm package name')
106
+ },
107
+ annotations: {
108
+ readOnlyHint: true,
109
+ destructiveHint: false,
110
+ openWorldHint: true
111
+ }
112
+ }, async (args) => {
113
+ try {
114
+ const result = await callApifyTool("get_npm_package", args);
115
+ return {
116
+ content: [{ type: "text", text: result }]
117
+ };
118
+ }
119
+ catch (error) {
120
+ const message = error instanceof Error ? error.message : String(error);
121
+ return {
122
+ content: [{ type: "text", text: `Error: ${message}` }],
123
+ isError: true
124
+ };
125
+ }
126
+ });
127
+ server.registerTool("get_pypi_package", {
128
+ title: "Get Pypi Package",
129
+ description: "Get PyPI package details",
130
+ inputSchema: {
131
+ packageName: z.string().describe('PyPI package name')
132
+ },
133
+ annotations: {
134
+ readOnlyHint: true,
135
+ destructiveHint: false,
136
+ openWorldHint: true
137
+ }
138
+ }, async (args) => {
139
+ try {
140
+ const result = await callApifyTool("get_pypi_package", args);
141
+ return {
142
+ content: [{ type: "text", text: result }]
143
+ };
144
+ }
145
+ catch (error) {
146
+ const message = error instanceof Error ? error.message : String(error);
147
+ return {
148
+ content: [{ type: "text", text: `Error: ${message}` }],
149
+ isError: true
150
+ };
151
+ }
152
+ });
153
+ server.registerTool("search_stackoverflow", {
154
+ title: "Search Stackoverflow",
155
+ description: "Search Stack Overflow",
156
+ inputSchema: {
157
+ query: z.string().describe('Search query'),
158
+ maxItems: z.number().default(10).describe('Maximum results')
159
+ },
160
+ annotations: {
161
+ readOnlyHint: true,
162
+ destructiveHint: false,
163
+ openWorldHint: true
164
+ }
165
+ }, async (args) => {
166
+ try {
167
+ const result = await callApifyTool("search_stackoverflow", args);
168
+ return {
169
+ content: [{ type: "text", text: result }]
170
+ };
171
+ }
172
+ catch (error) {
173
+ const message = error instanceof Error ? error.message : String(error);
174
+ return {
175
+ content: [{ type: "text", text: `Error: ${message}` }],
176
+ isError: true
177
+ };
178
+ }
179
+ });
180
+ server.registerTool("search_arxiv_papers", {
181
+ title: "Search Arxiv Papers",
182
+ description: "Search arXiv papers",
183
+ inputSchema: {
184
+ query: z.string().describe('Search query'),
185
+ maxItems: z.number().default(10).describe('Maximum results')
186
+ },
187
+ annotations: {
188
+ readOnlyHint: true,
189
+ destructiveHint: false,
190
+ openWorldHint: true
191
+ }
192
+ }, async (args) => {
193
+ try {
194
+ const result = await callApifyTool("search_arxiv_papers", args);
195
+ return {
196
+ content: [{ type: "text", text: result }]
197
+ };
198
+ }
199
+ catch (error) {
200
+ const message = error instanceof Error ? error.message : String(error);
201
+ return {
202
+ content: [{ type: "text", text: `Error: ${message}` }],
203
+ isError: true
204
+ };
205
+ }
206
+ });
207
+ server.registerTool("search_scholar", {
208
+ title: "Search Scholar",
209
+ description: "Search Google Scholar",
210
+ inputSchema: {
211
+ query: z.string().describe('Search query'),
212
+ maxItems: z.number().default(10).describe('Maximum results')
213
+ },
214
+ annotations: {
215
+ readOnlyHint: true,
216
+ destructiveHint: false,
217
+ openWorldHint: true
218
+ }
219
+ }, async (args) => {
220
+ try {
221
+ const result = await callApifyTool("search_scholar", args);
222
+ return {
223
+ content: [{ type: "text", text: result }]
224
+ };
225
+ }
226
+ catch (error) {
227
+ const message = error instanceof Error ? error.message : String(error);
228
+ return {
229
+ content: [{ type: "text", text: `Error: ${message}` }],
230
+ isError: true
231
+ };
232
+ }
233
+ });
234
+ async function main() {
235
+ const transport = new StdioServerTransport();
236
+ await server.connect(transport);
237
+ console.error("Developer Tools MCP Server running on stdio");
238
+ }
239
+ main().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@thenextgennexus/developer-tools-mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "Access GitHub repos, npm/PyPI packages, Stack Overflow, arXiv, and Google Scholar",
5
+ "type": "module",
6
+ "bin": {
7
+ "developer-tools-mcp-server": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "start": "node dist/index.js",
12
+ "dev": "tsx src/index.ts"
13
+ },
14
+ "dependencies": {
15
+ "@modelcontextprotocol/sdk": "^1.0.0",
16
+ "zod": "^3.22.0"
17
+ },
18
+ "devDependencies": {
19
+ "typescript": "^5.3.0",
20
+ "tsx": "^4.7.0",
21
+ "@types/node": "^20.11.0"
22
+ },
23
+ "engines": {
24
+ "node": ">=18.0.0"
25
+ },
26
+ "keywords": [
27
+ "mcp",
28
+ "model-context-protocol",
29
+ "ai",
30
+ "apify",
31
+ "nexgendata"
32
+ ],
33
+ "author": "nexgendata",
34
+ "license": "MIT",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/TheNextGenNexus/web-intelligence-mcp-servers"
38
+ },
39
+ "mcpName": "io.github.thenextgennexus/developer-tools-mcp-server"
40
+ }
package/smithery.yaml ADDED
@@ -0,0 +1,13 @@
1
+ startCommand:
2
+ type: stdio
3
+ configSchema:
4
+ type: object
5
+ required:
6
+ - apifyToken
7
+ properties:
8
+ apifyToken:
9
+ type: string
10
+ description: Your Apify API token. Get one free at https://apify.com
11
+ commandFunction:
12
+ |-
13
+ (config) => ({{ command: 'npx', args: ['tsx', 'src/index.ts'], env: {{ APIFY_TOKEN: config.apifyToken }} }})
package/src/index.ts ADDED
@@ -0,0 +1,280 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+
6
+ const APIFY_ENDPOINT = "https://nexgendata--developer-tools-mcp-server.apify.actor/mcp";
7
+ const APIFY_TOKEN = process.env.APIFY_TOKEN || "";
8
+
9
+ async function callApifyTool(toolName: string, args: Record<string, unknown>): Promise<string> {
10
+ const url = new URL(APIFY_ENDPOINT);
11
+ if (APIFY_TOKEN) {
12
+ url.searchParams.set("token", APIFY_TOKEN);
13
+ }
14
+
15
+ const body = {
16
+ jsonrpc: "2.0",
17
+ id: 1,
18
+ method: "tools/call",
19
+ params: {
20
+ name: toolName,
21
+ arguments: args
22
+ }
23
+ };
24
+
25
+ const response = await fetch(url.toString(), {
26
+ method: "POST",
27
+ headers: { "Content-Type": "application/json" },
28
+ body: JSON.stringify(body)
29
+ });
30
+
31
+ if (!response.ok) {
32
+ const errorText = await response.text();
33
+ throw new Error(`Apify API error (${response.status}): ${errorText}`);
34
+ }
35
+
36
+ const data = await response.json();
37
+
38
+ if (data.error) {
39
+ throw new Error(`Tool error: ${JSON.stringify(data.error)}`);
40
+ }
41
+
42
+ // Extract text content from MCP response
43
+ const result = data.result;
44
+ if (result?.content && Array.isArray(result.content)) {
45
+ return result.content
46
+ .filter((c: { type: string }) => c.type === "text")
47
+ .map((c: { text: string }) => c.text)
48
+ .join("\n");
49
+ }
50
+
51
+ return JSON.stringify(data.result, null, 2);
52
+ }
53
+
54
+ const server = new McpServer({
55
+ name: "developer-tools-mcp-server",
56
+ version: "1.0.0"
57
+ });
58
+
59
+ server.registerTool(
60
+ "get_github_repo",
61
+ {
62
+ title: "Get Github Repo",
63
+ description: "Get GitHub repository details",
64
+ inputSchema: {
65
+ repoUrl: z.string().describe('GitHub repository URL')
66
+ },
67
+ annotations: {
68
+ readOnlyHint: true,
69
+ destructiveHint: false,
70
+ openWorldHint: true
71
+ }
72
+ },
73
+ async (args) => {
74
+ try {
75
+ const result = await callApifyTool("get_github_repo", args);
76
+ return {
77
+ content: [{ type: "text", text: result }]
78
+ };
79
+ } catch (error) {
80
+ const message = error instanceof Error ? error.message : String(error);
81
+ return {
82
+ content: [{ type: "text", text: `Error: ${message}` }],
83
+ isError: true
84
+ };
85
+ }
86
+ }
87
+ );
88
+
89
+ server.registerTool(
90
+ "search_github",
91
+ {
92
+ title: "Search Github",
93
+ description: "Search GitHub repositories",
94
+ inputSchema: {
95
+ query: z.string().describe('Search query'),
96
+ maxItems: z.number().default(10).describe('Maximum results')
97
+ },
98
+ annotations: {
99
+ readOnlyHint: true,
100
+ destructiveHint: false,
101
+ openWorldHint: true
102
+ }
103
+ },
104
+ async (args) => {
105
+ try {
106
+ const result = await callApifyTool("search_github", args);
107
+ return {
108
+ content: [{ type: "text", text: result }]
109
+ };
110
+ } catch (error) {
111
+ const message = error instanceof Error ? error.message : String(error);
112
+ return {
113
+ content: [{ type: "text", text: `Error: ${message}` }],
114
+ isError: true
115
+ };
116
+ }
117
+ }
118
+ );
119
+
120
+ server.registerTool(
121
+ "get_npm_package",
122
+ {
123
+ title: "Get Npm Package",
124
+ description: "Get npm package details",
125
+ inputSchema: {
126
+ packageName: z.string().describe('npm package name')
127
+ },
128
+ annotations: {
129
+ readOnlyHint: true,
130
+ destructiveHint: false,
131
+ openWorldHint: true
132
+ }
133
+ },
134
+ async (args) => {
135
+ try {
136
+ const result = await callApifyTool("get_npm_package", args);
137
+ return {
138
+ content: [{ type: "text", text: result }]
139
+ };
140
+ } catch (error) {
141
+ const message = error instanceof Error ? error.message : String(error);
142
+ return {
143
+ content: [{ type: "text", text: `Error: ${message}` }],
144
+ isError: true
145
+ };
146
+ }
147
+ }
148
+ );
149
+
150
+ server.registerTool(
151
+ "get_pypi_package",
152
+ {
153
+ title: "Get Pypi Package",
154
+ description: "Get PyPI package details",
155
+ inputSchema: {
156
+ packageName: z.string().describe('PyPI package name')
157
+ },
158
+ annotations: {
159
+ readOnlyHint: true,
160
+ destructiveHint: false,
161
+ openWorldHint: true
162
+ }
163
+ },
164
+ async (args) => {
165
+ try {
166
+ const result = await callApifyTool("get_pypi_package", args);
167
+ return {
168
+ content: [{ type: "text", text: result }]
169
+ };
170
+ } catch (error) {
171
+ const message = error instanceof Error ? error.message : String(error);
172
+ return {
173
+ content: [{ type: "text", text: `Error: ${message}` }],
174
+ isError: true
175
+ };
176
+ }
177
+ }
178
+ );
179
+
180
+ server.registerTool(
181
+ "search_stackoverflow",
182
+ {
183
+ title: "Search Stackoverflow",
184
+ description: "Search Stack Overflow",
185
+ inputSchema: {
186
+ query: z.string().describe('Search query'),
187
+ maxItems: z.number().default(10).describe('Maximum results')
188
+ },
189
+ annotations: {
190
+ readOnlyHint: true,
191
+ destructiveHint: false,
192
+ openWorldHint: true
193
+ }
194
+ },
195
+ async (args) => {
196
+ try {
197
+ const result = await callApifyTool("search_stackoverflow", args);
198
+ return {
199
+ content: [{ type: "text", text: result }]
200
+ };
201
+ } catch (error) {
202
+ const message = error instanceof Error ? error.message : String(error);
203
+ return {
204
+ content: [{ type: "text", text: `Error: ${message}` }],
205
+ isError: true
206
+ };
207
+ }
208
+ }
209
+ );
210
+
211
+ server.registerTool(
212
+ "search_arxiv_papers",
213
+ {
214
+ title: "Search Arxiv Papers",
215
+ description: "Search arXiv papers",
216
+ inputSchema: {
217
+ query: z.string().describe('Search query'),
218
+ maxItems: z.number().default(10).describe('Maximum results')
219
+ },
220
+ annotations: {
221
+ readOnlyHint: true,
222
+ destructiveHint: false,
223
+ openWorldHint: true
224
+ }
225
+ },
226
+ async (args) => {
227
+ try {
228
+ const result = await callApifyTool("search_arxiv_papers", args);
229
+ return {
230
+ content: [{ type: "text", text: result }]
231
+ };
232
+ } catch (error) {
233
+ const message = error instanceof Error ? error.message : String(error);
234
+ return {
235
+ content: [{ type: "text", text: `Error: ${message}` }],
236
+ isError: true
237
+ };
238
+ }
239
+ }
240
+ );
241
+
242
+ server.registerTool(
243
+ "search_scholar",
244
+ {
245
+ title: "Search Scholar",
246
+ description: "Search Google Scholar",
247
+ inputSchema: {
248
+ query: z.string().describe('Search query'),
249
+ maxItems: z.number().default(10).describe('Maximum results')
250
+ },
251
+ annotations: {
252
+ readOnlyHint: true,
253
+ destructiveHint: false,
254
+ openWorldHint: true
255
+ }
256
+ },
257
+ async (args) => {
258
+ try {
259
+ const result = await callApifyTool("search_scholar", args);
260
+ return {
261
+ content: [{ type: "text", text: result }]
262
+ };
263
+ } catch (error) {
264
+ const message = error instanceof Error ? error.message : String(error);
265
+ return {
266
+ content: [{ type: "text", text: `Error: ${message}` }],
267
+ isError: true
268
+ };
269
+ }
270
+ }
271
+ );
272
+
273
+
274
+ async function main() {
275
+ const transport = new StdioServerTransport();
276
+ await server.connect(transport);
277
+ console.error("Developer Tools MCP Server running on stdio");
278
+ }
279
+
280
+ main().catch(console.error);
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "declaration": true
12
+ },
13
+ "include": [
14
+ "src/**/*"
15
+ ]
16
+ }