@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 +75 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +239 -0
- package/package.json +40 -0
- package/smithery.yaml +13 -0
- package/src/index.ts +280 -0
- package/tsconfig.json +16 -0
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
|
package/dist/index.d.ts
ADDED
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
|
+
}
|