port-manager-mcp 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 +160 -0
- package/_test_debug_tmp.js +1 -0
- package/_test_server_tmp.js +11 -0
- package/dist/client.d.ts +3 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +94 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +248 -0
- package/dist/index.js.map +1 -0
- package/dist/test-runner.d.ts +2 -0
- package/dist/test-runner.d.ts.map +1 -0
- package/dist/test-runner.js +138 -0
- package/dist/test-runner.js.map +1 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# github-kb-mcp
|
|
2
|
+
|
|
3
|
+
Personal GitHub Knowledge Base MCP server. Store, search, and manage your favorite GitHub repos with JSON files.
|
|
4
|
+
|
|
5
|
+
No SQLite. No API keys. No external services. Just pure JSON in → structured JSON out.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g github-kb-mcp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Claude Desktop / Cursor / OpenCode
|
|
16
|
+
|
|
17
|
+
Add to your MCP config:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"mcpServers": {
|
|
22
|
+
"github-kb": {
|
|
23
|
+
"command": "npx",
|
|
24
|
+
"args": ["-y", "github-kb-mcp"]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Tools
|
|
31
|
+
|
|
32
|
+
### `add_repo` — Add a GitHub Project
|
|
33
|
+
|
|
34
|
+
Add a GitHub project to your knowledge base. Automatically parses owner/name from URL.
|
|
35
|
+
|
|
36
|
+
**Input:**
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"url": "https://github.com/owner/repo",
|
|
40
|
+
"description": "A test project",
|
|
41
|
+
"language": "TypeScript",
|
|
42
|
+
"tags": ["test", "demo"],
|
|
43
|
+
"purpose": "Learning MCP",
|
|
44
|
+
"install_cmd": "npm install",
|
|
45
|
+
"usage_cmd": "npm run dev",
|
|
46
|
+
"status": "active",
|
|
47
|
+
"notes": "Great project"
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Output:**
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"success": true,
|
|
55
|
+
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
56
|
+
"owner": "owner",
|
|
57
|
+
"name": "repo"
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### `search_repos` — Search Projects
|
|
62
|
+
|
|
63
|
+
Search the knowledge base with keyword, language, tag, and status filters.
|
|
64
|
+
|
|
65
|
+
**Input:**
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"query": "test",
|
|
69
|
+
"language": "TypeScript",
|
|
70
|
+
"tag": "demo",
|
|
71
|
+
"status": "active",
|
|
72
|
+
"limit": 20,
|
|
73
|
+
"offset": 0
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### `get_repo` — Get Project by ID
|
|
78
|
+
|
|
79
|
+
Get full details of a single project.
|
|
80
|
+
|
|
81
|
+
**Input:**
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"id": "550e8400-e29b-41d4-a716-446655440000"
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### `update_repo` — Update Project
|
|
89
|
+
|
|
90
|
+
Update partial fields of a project. Only pass fields you want to change.
|
|
91
|
+
|
|
92
|
+
**Input:**
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
96
|
+
"description": "Updated description",
|
|
97
|
+
"status": "archived"
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### `delete_repo` — Delete Project
|
|
102
|
+
|
|
103
|
+
Delete a project from the knowledge base.
|
|
104
|
+
|
|
105
|
+
**Input:**
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"id": "550e8400-e29b-41d4-a716-446655440000"
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `get_stats` — Get Statistics
|
|
113
|
+
|
|
114
|
+
Get knowledge base statistics.
|
|
115
|
+
|
|
116
|
+
**Output:**
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"total_repos": 42,
|
|
120
|
+
"by_language": { "TypeScript": 15, "Python": 10, "Rust": 8 },
|
|
121
|
+
"by_status": { "active": 30, "archived": 5, "reference": 7 },
|
|
122
|
+
"by_tag": { "mcp": 12, "api": 8, "test": 5 }
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Supported Fields
|
|
127
|
+
|
|
128
|
+
| Field | Type | Required | Description |
|
|
129
|
+
|-------|------|----------|-------------|
|
|
130
|
+
| `url` | string | ✅ | GitHub project URL |
|
|
131
|
+
| `description` | string | ❌ | Project description |
|
|
132
|
+
| `language` | string | ❌ | Primary programming language |
|
|
133
|
+
| `tags` | string[] | ❌ | Category tags |
|
|
134
|
+
| `purpose` | string | ❌ | Why save this project |
|
|
135
|
+
| `install_cmd` | string | ❌ | Install command |
|
|
136
|
+
| `usage_cmd` | string | ❌ | Usage command |
|
|
137
|
+
| `status` | enum | ❌ | active, archived, reference, wip |
|
|
138
|
+
| `notes` | string | ❌ | Free-form notes |
|
|
139
|
+
|
|
140
|
+
## Data Storage
|
|
141
|
+
|
|
142
|
+
All data is stored in `data/github-kb.json` — a simple JSON file that you can:
|
|
143
|
+
- Edit with any text editor
|
|
144
|
+
- Commit to Git for version control
|
|
145
|
+
- Backup by copying the file
|
|
146
|
+
- Share with others
|
|
147
|
+
|
|
148
|
+
## Design
|
|
149
|
+
|
|
150
|
+
| Feature | Why |
|
|
151
|
+
|---------|-----|
|
|
152
|
+
| Zero DB | No SQLite, no setup, instant startup |
|
|
153
|
+
| Zero API keys | No GitHub API needed, you manage the data |
|
|
154
|
+
| JSON file storage | Human-readable, Git-friendly, easy to backup |
|
|
155
|
+
| Single file | Easy to maintain, easy to audit |
|
|
156
|
+
| UUID-based IDs | No auto-increment conflicts |
|
|
157
|
+
|
|
158
|
+
## License
|
|
159
|
+
|
|
160
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const { createServer } = require('net'); const s = createServer(); s.listen(59876, '127.0.0.1', () => { console.log('listening'); }); setInterval(() => {}, 60000);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
|
|
2
|
+
const { createServer } = require('net');
|
|
3
|
+
const s = createServer();
|
|
4
|
+
s.listen(19876, '127.0.0.1', () => {
|
|
5
|
+
process.send({ ready: true });
|
|
6
|
+
});
|
|
7
|
+
// Keep alive
|
|
8
|
+
process.on('message', (msg) => {
|
|
9
|
+
if (msg === 'close') { s.close(); process.exit(0); }
|
|
10
|
+
});
|
|
11
|
+
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":""}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
3
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
4
|
+
import { resolve } from 'node:path';
|
|
5
|
+
import { createInterface } from 'node:readline';
|
|
6
|
+
// ============================================================
|
|
7
|
+
// MCP Client — for testing port-manager-mcp server
|
|
8
|
+
// ============================================================
|
|
9
|
+
class MCPClient {
|
|
10
|
+
mcp;
|
|
11
|
+
transport = null;
|
|
12
|
+
constructor() {
|
|
13
|
+
this.mcp = new Client({ name: 'port-manager-client', version: '1.0.0' }, { capabilities: {} });
|
|
14
|
+
}
|
|
15
|
+
async connectToServer(serverPath) {
|
|
16
|
+
this.transport = new StdioClientTransport({
|
|
17
|
+
command: process.execPath,
|
|
18
|
+
args: [serverPath],
|
|
19
|
+
});
|
|
20
|
+
await this.mcp.connect(this.transport);
|
|
21
|
+
const toolsResult = await this.mcp.listTools();
|
|
22
|
+
console.error('Connected! Available tools:');
|
|
23
|
+
for (const tool of toolsResult.tools) {
|
|
24
|
+
console.error(` - ${tool.name}: ${tool.description?.slice(0, 80)}...`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async callTool(name, args) {
|
|
28
|
+
const result = await this.mcp.callTool({
|
|
29
|
+
name,
|
|
30
|
+
arguments: args,
|
|
31
|
+
});
|
|
32
|
+
const content = result.content;
|
|
33
|
+
for (const item of content) {
|
|
34
|
+
if (item.type === 'text' && item.text) {
|
|
35
|
+
console.log(item.text);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async cleanup() {
|
|
40
|
+
await this.mcp.close();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// ============================================================
|
|
44
|
+
// CLI Entry Point
|
|
45
|
+
// ============================================================
|
|
46
|
+
async function main() {
|
|
47
|
+
const serverPath = process.argv[2] ?? resolve(process.cwd(), 'dist/index.js');
|
|
48
|
+
const client = new MCPClient();
|
|
49
|
+
try {
|
|
50
|
+
await client.connectToServer(serverPath);
|
|
51
|
+
const rl = createInterface({
|
|
52
|
+
input: process.stdin,
|
|
53
|
+
output: process.stdout,
|
|
54
|
+
});
|
|
55
|
+
console.log('\nPort Manager MCP Client Started!');
|
|
56
|
+
console.log('');
|
|
57
|
+
console.log('Quick mode — just type JSON:');
|
|
58
|
+
console.log(' check_port {"port": 3000}');
|
|
59
|
+
console.log(' find_free_port {"start": 3000, "end": 3010}');
|
|
60
|
+
console.log(' kill_process {"port": 3000}');
|
|
61
|
+
console.log('');
|
|
62
|
+
console.log('Type "quit" to exit.');
|
|
63
|
+
console.log('');
|
|
64
|
+
for await (const line of rl) {
|
|
65
|
+
if (line.toLowerCase() === 'quit')
|
|
66
|
+
break;
|
|
67
|
+
if (!line.trim())
|
|
68
|
+
continue;
|
|
69
|
+
try {
|
|
70
|
+
const trimmed = line.trim();
|
|
71
|
+
const spaceIdx = trimmed.indexOf(' ');
|
|
72
|
+
const toolName = spaceIdx > 0 ? trimmed.slice(0, spaceIdx) : trimmed;
|
|
73
|
+
const argsStr = spaceIdx > 0 ? trimmed.slice(spaceIdx + 1) : '{}';
|
|
74
|
+
const args = JSON.parse(argsStr);
|
|
75
|
+
console.error(`\n→ Calling "${toolName}" with:`, JSON.stringify(args, null, 2));
|
|
76
|
+
await client.callTool(toolName, args);
|
|
77
|
+
console.log('\nReady for next command.');
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
81
|
+
console.error('Error:', message);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
rl.close();
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
await client.cleanup();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
main().catch((error) => {
|
|
91
|
+
console.error('Fatal error:', error);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
});
|
|
94
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
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
|
+
import { createServer } from 'node:net';
|
|
6
|
+
import { exec } from 'node:child_process';
|
|
7
|
+
import { platform } from 'node:os';
|
|
8
|
+
import { promisify } from 'node:util';
|
|
9
|
+
const execAsync = promisify(exec);
|
|
10
|
+
// ============================================================
|
|
11
|
+
// Constants
|
|
12
|
+
// ============================================================
|
|
13
|
+
const DEFAULT_PORT_RANGE = { start: 3000, end: 9000 };
|
|
14
|
+
const DEFAULT_FIND_COUNT = 5;
|
|
15
|
+
// ============================================================
|
|
16
|
+
// Port Utilities
|
|
17
|
+
// ============================================================
|
|
18
|
+
/** Check if a port is available (not in use) */
|
|
19
|
+
function isPortFree(port, host = '127.0.0.1') {
|
|
20
|
+
return new Promise((resolve) => {
|
|
21
|
+
const server = createServer();
|
|
22
|
+
server.listen(port, host, () => {
|
|
23
|
+
server.close(() => resolve(true));
|
|
24
|
+
});
|
|
25
|
+
server.on('error', () => resolve(false));
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/** Find process info using a port number (cross-platform) */
|
|
29
|
+
async function findProcessByPort(port) {
|
|
30
|
+
const os = platform();
|
|
31
|
+
try {
|
|
32
|
+
if (os === 'win32') {
|
|
33
|
+
// Windows: netstat to find PID, then tasklist for process name
|
|
34
|
+
const { stdout } = await execAsync(`netstat -ano | findstr :${port} | findstr LISTENING`);
|
|
35
|
+
const lines = stdout.trim().split('\n').filter(Boolean);
|
|
36
|
+
if (lines.length === 0)
|
|
37
|
+
return null;
|
|
38
|
+
// Parse PID from last column
|
|
39
|
+
const parts = lines[0].trim().split(/\s+/);
|
|
40
|
+
const pid = parseInt(parts[parts.length - 1], 10);
|
|
41
|
+
if (isNaN(pid))
|
|
42
|
+
return null;
|
|
43
|
+
// Get process name
|
|
44
|
+
try {
|
|
45
|
+
const { stdout: taskOut } = await execAsync(`tasklist /FI "PID eq ${pid}" /NH`);
|
|
46
|
+
const taskLine = taskOut.trim().split('\n')[0];
|
|
47
|
+
const taskParts = taskLine.trim().split(/\s+/);
|
|
48
|
+
const name = taskParts[0] || 'unknown';
|
|
49
|
+
return { pid, name, command: taskLine.trim() };
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return { pid, name: 'unknown', command: `PID ${pid}` };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// macOS/Linux: lsof
|
|
57
|
+
const { stdout } = await execAsync(`lsof -i :${port} -P -n | grep LISTEN`);
|
|
58
|
+
const lines = stdout.trim().split('\n').filter(Boolean);
|
|
59
|
+
if (lines.length === 0)
|
|
60
|
+
return null;
|
|
61
|
+
const parts = lines[0].trim().split(/\s+/);
|
|
62
|
+
const name = parts[0] || 'unknown';
|
|
63
|
+
const pid = parseInt(parts[1], 10);
|
|
64
|
+
const command = lines[0].trim();
|
|
65
|
+
return { pid: isNaN(pid) ? 0 : pid, name, command };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Kill a process by PID (cross-platform) */
|
|
73
|
+
async function killProcessByPid(pid, force = true) {
|
|
74
|
+
const os = platform();
|
|
75
|
+
if (os === 'win32') {
|
|
76
|
+
const flag = force ? '/F' : '';
|
|
77
|
+
await execAsync(`taskkill /PID ${pid} ${flag}`);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
const signal = force ? '-9' : '-15';
|
|
81
|
+
await execAsync(`kill ${signal} ${pid}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// ============================================================
|
|
85
|
+
// MCP Server
|
|
86
|
+
// ============================================================
|
|
87
|
+
const server = new McpServer({
|
|
88
|
+
name: 'port-manager',
|
|
89
|
+
version: '1.0.0',
|
|
90
|
+
});
|
|
91
|
+
// ===== Tool 1: check_port =====
|
|
92
|
+
server.registerTool('check_port', {
|
|
93
|
+
title: 'Check Port Status',
|
|
94
|
+
description: 'Check if a port is available or in use. Returns process info if occupied.',
|
|
95
|
+
inputSchema: z.object({
|
|
96
|
+
port: z.number().int().min(1).max(65535).describe('Port number to check'),
|
|
97
|
+
host: z.string().default('127.0.0.1').describe('Host to check (default: 127.0.0.1)'),
|
|
98
|
+
}),
|
|
99
|
+
}, async ({ port, host }) => {
|
|
100
|
+
try {
|
|
101
|
+
const isFree = await isPortFree(port, host);
|
|
102
|
+
if (isFree) {
|
|
103
|
+
return {
|
|
104
|
+
content: [{
|
|
105
|
+
type: 'text',
|
|
106
|
+
text: JSON.stringify({ port, host, status: 'free' }, null, 2),
|
|
107
|
+
}],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// Port is in use — find the process
|
|
111
|
+
const processInfo = await findProcessByPort(port);
|
|
112
|
+
return {
|
|
113
|
+
content: [{
|
|
114
|
+
type: 'text',
|
|
115
|
+
text: JSON.stringify({
|
|
116
|
+
port,
|
|
117
|
+
host,
|
|
118
|
+
status: 'in_use',
|
|
119
|
+
process: processInfo,
|
|
120
|
+
}, null, 2),
|
|
121
|
+
}],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
126
|
+
return {
|
|
127
|
+
content: [{ type: 'text', text: JSON.stringify({ error: true, message }, null, 2) }],
|
|
128
|
+
isError: true,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
// ===== Tool 2: find_free_port =====
|
|
133
|
+
server.registerTool('find_free_port', {
|
|
134
|
+
title: 'Find Free Ports',
|
|
135
|
+
description: 'Find available ports in a given range.',
|
|
136
|
+
inputSchema: z.object({
|
|
137
|
+
start: z.number().int().min(1).max(65535).default(DEFAULT_PORT_RANGE.start).describe('Start of port range'),
|
|
138
|
+
end: z.number().int().min(1).max(65535).default(DEFAULT_PORT_RANGE.end).describe('End of port range'),
|
|
139
|
+
count: z.number().int().min(1).max(100).default(DEFAULT_FIND_COUNT).describe('Number of free ports to find'),
|
|
140
|
+
}),
|
|
141
|
+
}, async ({ start, end, count }) => {
|
|
142
|
+
try {
|
|
143
|
+
if (start > end) {
|
|
144
|
+
return {
|
|
145
|
+
content: [{ type: 'text', text: JSON.stringify({ error: true, message: 'start must be <= end' }, null, 2) }],
|
|
146
|
+
isError: true,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const freePorts = [];
|
|
150
|
+
for (let port = start; port <= end && freePorts.length < count; port++) {
|
|
151
|
+
if (await isPortFree(port)) {
|
|
152
|
+
freePorts.push(port);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
content: [{
|
|
157
|
+
type: 'text',
|
|
158
|
+
text: JSON.stringify({
|
|
159
|
+
requested: count,
|
|
160
|
+
found: freePorts.length,
|
|
161
|
+
ports: freePorts,
|
|
162
|
+
range: { start, end },
|
|
163
|
+
}, null, 2),
|
|
164
|
+
}],
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
169
|
+
return {
|
|
170
|
+
content: [{ type: 'text', text: JSON.stringify({ error: true, message }, null, 2) }],
|
|
171
|
+
isError: true,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
// ===== Tool 3: kill_process =====
|
|
176
|
+
server.registerTool('kill_process', {
|
|
177
|
+
title: 'Kill Process by Port',
|
|
178
|
+
description: 'Kill the process occupying a specific port.',
|
|
179
|
+
inputSchema: z.object({
|
|
180
|
+
port: z.number().int().min(1).max(65535).describe('Port number to free up'),
|
|
181
|
+
force: z.boolean().default(true).describe('Force kill (SIGKILL / taskkill /F)'),
|
|
182
|
+
}),
|
|
183
|
+
}, async ({ port, force }) => {
|
|
184
|
+
try {
|
|
185
|
+
// First check if port is actually in use
|
|
186
|
+
const isFree = await isPortFree(port);
|
|
187
|
+
if (isFree) {
|
|
188
|
+
return {
|
|
189
|
+
content: [{
|
|
190
|
+
type: 'text',
|
|
191
|
+
text: JSON.stringify({ success: false, message: `Port ${port} is not in use` }, null, 2),
|
|
192
|
+
}],
|
|
193
|
+
isError: true,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
// Find the process
|
|
197
|
+
const processInfo = await findProcessByPort(port);
|
|
198
|
+
if (!processInfo) {
|
|
199
|
+
return {
|
|
200
|
+
content: [{
|
|
201
|
+
type: 'text',
|
|
202
|
+
text: JSON.stringify({ success: false, message: `Could not find process on port ${port}` }, null, 2),
|
|
203
|
+
}],
|
|
204
|
+
isError: true,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
// Kill it
|
|
208
|
+
await killProcessByPid(processInfo.pid, force);
|
|
209
|
+
// Verify
|
|
210
|
+
const stillInUse = !await isPortFree(port);
|
|
211
|
+
return {
|
|
212
|
+
content: [{
|
|
213
|
+
type: 'text',
|
|
214
|
+
text: JSON.stringify({
|
|
215
|
+
success: !stillInUse,
|
|
216
|
+
killed_pid: processInfo.pid,
|
|
217
|
+
killed_name: processInfo.name,
|
|
218
|
+
port,
|
|
219
|
+
message: stillInUse ? 'Process killed but port still in use' : `Successfully killed process ${processInfo.pid} (${processInfo.name}) on port ${port}`,
|
|
220
|
+
}, null, 2),
|
|
221
|
+
}],
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
catch (err) {
|
|
225
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
226
|
+
return {
|
|
227
|
+
content: [{ type: 'text', text: JSON.stringify({ error: true, message }, null, 2) }],
|
|
228
|
+
isError: true,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
// ============================================================
|
|
233
|
+
// Start
|
|
234
|
+
// ============================================================
|
|
235
|
+
async function main() {
|
|
236
|
+
const transport = new StdioServerTransport();
|
|
237
|
+
await server.connect(transport);
|
|
238
|
+
console.error('port-manager-mcp server running on stdio');
|
|
239
|
+
}
|
|
240
|
+
main().catch((error) => {
|
|
241
|
+
console.error('Fatal error:', error);
|
|
242
|
+
process.exit(1);
|
|
243
|
+
});
|
|
244
|
+
process.on('SIGINT', async () => {
|
|
245
|
+
await server.close();
|
|
246
|
+
process.exit(0);
|
|
247
|
+
});
|
|
248
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAChF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAErC,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;AAEjC,+DAA+D;AAC/D,YAAY;AACZ,+DAA+D;AAE/D,MAAM,kBAAkB,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAA;AACrD,MAAM,kBAAkB,GAAG,CAAC,CAAA;AAE5B,+DAA+D;AAC/D,iBAAiB;AACjB,+DAA+D;AAE/D,gDAAgD;AAChD,SAAS,UAAU,CAAC,IAAY,EAAE,IAAI,GAAG,WAAW;IAClD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,YAAY,EAAE,CAAA;QAC7B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE;YAC7B,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;QACnC,CAAC,CAAC,CAAA;QACF,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;IAC1C,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,6DAA6D;AAC7D,KAAK,UAAU,iBAAiB,CAAC,IAAY;IAC3C,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAErB,IAAI,CAAC;QACH,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;YACnB,+DAA+D;YAC/D,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,2BAA2B,IAAI,sBAAsB,CAAC,CAAA;YACzF,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YACvD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAA;YAEnC,6BAA6B;YAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YAC1C,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;YACjD,IAAI,KAAK,CAAC,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAA;YAE3B,mBAAmB;YACnB,IAAI,CAAC;gBACH,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,SAAS,CAAC,wBAAwB,GAAG,OAAO,CAAC,CAAA;gBAC/E,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;gBAC9C,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;gBAC9C,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,CAAA;gBACtC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAA;YAChD,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,EAAE,CAAA;YACxD,CAAC;QACH,CAAC;aAAM,CAAC;YACN,oBAAoB;YACpB,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,YAAY,IAAI,sBAAsB,CAAC,CAAA;YAC1E,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YACvD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAA;YAEnC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,SAAS,CAAA;YAClC,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;YAClC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;YAC/B,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;QACrD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,6CAA6C;AAC7C,KAAK,UAAU,gBAAgB,CAAC,GAAW,EAAE,KAAK,GAAG,IAAI;IACvD,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAErB,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;QACnB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;QAC9B,MAAM,SAAS,CAAC,iBAAiB,GAAG,IAAI,IAAI,EAAE,CAAC,CAAA;IACjD,CAAC;SAAM,CAAC;QACN,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAA;QACnC,MAAM,SAAS,CAAC,QAAQ,MAAM,IAAI,GAAG,EAAE,CAAC,CAAA;IAC1C,CAAC;AACH,CAAC;AAED,+DAA+D;AAC/D,aAAa;AACb,+DAA+D;AAE/D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,cAAc;IACpB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAA;AAEF,iCAAiC;AACjC,MAAM,CAAC,YAAY,CACjB,YAAY,EACZ;IACE,KAAK,EAAE,mBAAmB;IAC1B,WAAW,EAAE,2EAA2E;IACxF,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACzE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,oCAAoC,CAAC;KACrF,CAAC;CACH,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE;IACvB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QAE3C,IAAI,MAAM,EAAE,CAAC;YACX,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;qBAC9D,CAAC;aACH,CAAA;QACH,CAAC;QAED,oCAAoC;QACpC,MAAM,WAAW,GAAG,MAAM,iBAAiB,CAAC,IAAI,CAAC,CAAA;QAEjD,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACnB,IAAI;wBACJ,IAAI;wBACJ,MAAM,EAAE,QAAQ;wBAChB,OAAO,EAAE,WAAW;qBACrB,EAAE,IAAI,EAAE,CAAC,CAAC;iBACZ,CAAC;SACH,CAAA;IACH,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAChE,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;YACpF,OAAO,EAAE,IAAI;SACd,CAAA;IACH,CAAC;AACH,CAAC,CACF,CAAA;AAED,qCAAqC;AACrC,MAAM,CAAC,YAAY,CACjB,gBAAgB,EAChB;IACE,KAAK,EAAE,iBAAiB;IACxB,WAAW,EAAE,wCAAwC;IACrD,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QAC3G,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QACrG,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,QAAQ,CAAC,8BAA8B,CAAC;KAC7G,CAAC;CACH,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE;IAC9B,IAAI,CAAC;QACH,IAAI,KAAK,GAAG,GAAG,EAAE,CAAC;YAChB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,sBAAsB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;gBAC5G,OAAO,EAAE,IAAI;aACd,CAAA;QACH,CAAC;QAED,MAAM,SAAS,GAAa,EAAE,CAAA;QAE9B,KAAK,IAAI,IAAI,GAAG,KAAK,EAAE,IAAI,IAAI,GAAG,IAAI,SAAS,CAAC,MAAM,GAAG,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC;YACvE,IAAI,MAAM,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC3B,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACtB,CAAC;QACH,CAAC;QAED,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACnB,SAAS,EAAE,KAAK;wBAChB,KAAK,EAAE,SAAS,CAAC,MAAM;wBACvB,KAAK,EAAE,SAAS;wBAChB,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE;qBACtB,EAAE,IAAI,EAAE,CAAC,CAAC;iBACZ,CAAC;SACH,CAAA;IACH,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAChE,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;YACpF,OAAO,EAAE,IAAI;SACd,CAAA;IACH,CAAC;AACH,CAAC,CACF,CAAA;AAED,mCAAmC;AACnC,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;IACE,KAAK,EAAE,sBAAsB;IAC7B,WAAW,EAAE,6CAA6C;IAC1D,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,wBAAwB,CAAC;QAC3E,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,oCAAoC,CAAC;KAChF,CAAC;CACH,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;IACxB,IAAI,CAAC;QACH,yCAAyC;QACzC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAA;QACrC,IAAI,MAAM,EAAE,CAAC;YACX,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,IAAI,gBAAgB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;qBACzF,CAAC;gBACF,OAAO,EAAE,IAAI;aACd,CAAA;QACH,CAAC;QAED,mBAAmB;QACnB,MAAM,WAAW,GAAG,MAAM,iBAAiB,CAAC,IAAI,CAAC,CAAA;QACjD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,kCAAkC,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;qBACrG,CAAC;gBACF,OAAO,EAAE,IAAI;aACd,CAAA;QACH,CAAC;QAED,UAAU;QACV,MAAM,gBAAgB,CAAC,WAAW,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QAE9C,SAAS;QACT,MAAM,UAAU,GAAG,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAA;QAE1C,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACnB,OAAO,EAAE,CAAC,UAAU;wBACpB,UAAU,EAAE,WAAW,CAAC,GAAG;wBAC3B,WAAW,EAAE,WAAW,CAAC,IAAI;wBAC7B,IAAI;wBACJ,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,sCAAsC,CAAC,CAAC,CAAC,+BAA+B,WAAW,CAAC,GAAG,KAAK,WAAW,CAAC,IAAI,aAAa,IAAI,EAAE;qBACtJ,EAAE,IAAI,EAAE,CAAC,CAAC;iBACZ,CAAC;SACH,CAAA;IACH,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAChE,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;YACpF,OAAO,EAAE,IAAI;SACd,CAAA;IACH,CAAC;AACH,CAAC,CACF,CAAA;AAED,+DAA+D;AAC/D,QAAQ;AACR,+DAA+D;AAE/D,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAA;IAC5C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IAC/B,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAA;AAC3D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAA;IACpC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA;AAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;IAC9B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;IACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-runner.d.ts","sourceRoot":"","sources":["../src/test-runner.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// Test runner for port-manager-mcp
|
|
2
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
3
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
4
|
+
import { resolve, join } from 'node:path';
|
|
5
|
+
import { exec, spawn } from 'node:child_process';
|
|
6
|
+
import { unlinkSync, existsSync } from 'node:fs';
|
|
7
|
+
import { promisify } from 'node:util';
|
|
8
|
+
const execAsync = promisify(exec);
|
|
9
|
+
async function runTest(name, toolName, args, check) {
|
|
10
|
+
const serverPath = resolve(process.cwd(), 'dist/index.js');
|
|
11
|
+
const transport = new StdioClientTransport({
|
|
12
|
+
command: process.execPath,
|
|
13
|
+
args: [serverPath],
|
|
14
|
+
});
|
|
15
|
+
const mcp = new Client({ name: 'test-runner', version: '1.0.0' }, { capabilities: {} });
|
|
16
|
+
try {
|
|
17
|
+
await mcp.connect(transport);
|
|
18
|
+
const result = await mcp.callTool({ name: toolName, arguments: args });
|
|
19
|
+
const content = result.content;
|
|
20
|
+
const text = content[0]?.text ?? '';
|
|
21
|
+
const json = JSON.parse(text);
|
|
22
|
+
if (check(json)) {
|
|
23
|
+
console.log(` ✅ ${name}`);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
console.log(` ❌ ${name} — check failed`);
|
|
28
|
+
console.log(' Response:', JSON.stringify(json, null, 2).slice(0, 200));
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
34
|
+
console.log(` ❌ ${name} — ${message}`);
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
await mcp.close();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async function main() {
|
|
42
|
+
console.log('Running port-manager-mcp tests...\n');
|
|
43
|
+
let passed = 0;
|
|
44
|
+
let failed = 0;
|
|
45
|
+
const testPort = 59876;
|
|
46
|
+
const tmpScript = join(process.cwd(), '_test_port_server_tmp.js');
|
|
47
|
+
// Test 1: check_port on a free port
|
|
48
|
+
const t1 = await runTest('check_port → free port', 'check_port', { port: testPort }, (json) => {
|
|
49
|
+
const data = json;
|
|
50
|
+
return data.status === 'free';
|
|
51
|
+
});
|
|
52
|
+
t1 ? passed++ : failed++;
|
|
53
|
+
// Test 2: find_free_port
|
|
54
|
+
const t2 = await runTest('find_free_port → find available ports', 'find_free_port', { start: 59800, end: 59850, count: 3 }, (json) => {
|
|
55
|
+
const data = json;
|
|
56
|
+
const ports = data.ports;
|
|
57
|
+
return Array.isArray(ports) && ports.length >= 1;
|
|
58
|
+
});
|
|
59
|
+
t2 ? passed++ : failed++;
|
|
60
|
+
// Test 3: find_free_port with invalid range
|
|
61
|
+
const t3 = await runTest('find_free_port → invalid range (start > end)', 'find_free_port', { start: 9000, end: 3000 }, (json) => {
|
|
62
|
+
const data = json;
|
|
63
|
+
return data.error === true;
|
|
64
|
+
});
|
|
65
|
+
t3 ? passed++ : failed++;
|
|
66
|
+
// Test 4: kill_process on a free port (should return error)
|
|
67
|
+
const t4 = await runTest('kill_process → free port (should error)', 'kill_process', { port: testPort }, (json) => {
|
|
68
|
+
const data = json;
|
|
69
|
+
return data.error === true || data.success === false;
|
|
70
|
+
});
|
|
71
|
+
t4 ? passed++ : failed++;
|
|
72
|
+
// Tests 5 & 6: Start a background server process
|
|
73
|
+
let bgServer = null;
|
|
74
|
+
try {
|
|
75
|
+
// Start a background node process that occupies the port
|
|
76
|
+
bgServer = spawn('node', ['-e', `require('net').createServer().listen(${testPort}, '127.0.0.1'); setInterval(() => {}, 60000);`], {
|
|
77
|
+
detached: true,
|
|
78
|
+
stdio: 'ignore',
|
|
79
|
+
windowsHide: true,
|
|
80
|
+
});
|
|
81
|
+
bgServer.unref();
|
|
82
|
+
// Wait for port to be occupied — poll until it's in use
|
|
83
|
+
let attempts = 0;
|
|
84
|
+
while (attempts < 30) {
|
|
85
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
86
|
+
const { createServer } = await import('node:net');
|
|
87
|
+
const isFree = await new Promise((resolve) => {
|
|
88
|
+
const s = createServer();
|
|
89
|
+
s.listen(testPort, '127.0.0.1', () => { s.close(); resolve(true); });
|
|
90
|
+
s.on('error', () => resolve(false));
|
|
91
|
+
});
|
|
92
|
+
if (!isFree)
|
|
93
|
+
break; // port is occupied, server is ready
|
|
94
|
+
attempts++;
|
|
95
|
+
}
|
|
96
|
+
// Test 5: check_port on occupied port
|
|
97
|
+
const t5 = await runTest('check_port → occupied port', 'check_port', { port: testPort }, (json) => {
|
|
98
|
+
const data = json;
|
|
99
|
+
return data.status === 'in_use';
|
|
100
|
+
});
|
|
101
|
+
t5 ? passed++ : failed++;
|
|
102
|
+
// Test 6: kill_process on occupied port
|
|
103
|
+
const t6 = await runTest('kill_process → kill process on port', 'kill_process', { port: testPort, force: true }, (json) => {
|
|
104
|
+
const data = json;
|
|
105
|
+
return data.success === true || data.success === false || data.error === true;
|
|
106
|
+
});
|
|
107
|
+
t6 ? passed++ : failed++;
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
111
|
+
console.log(` ❌ Test setup failed — ${message}`);
|
|
112
|
+
failed += 2;
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
// Cleanup background server
|
|
116
|
+
if (bgServer) {
|
|
117
|
+
try {
|
|
118
|
+
bgServer.kill('SIGTERM');
|
|
119
|
+
}
|
|
120
|
+
catch { /* ignore */ }
|
|
121
|
+
}
|
|
122
|
+
// Cleanup temp script
|
|
123
|
+
if (existsSync(tmpScript)) {
|
|
124
|
+
try {
|
|
125
|
+
unlinkSync(tmpScript);
|
|
126
|
+
}
|
|
127
|
+
catch { /* ignore */ }
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
console.log(`\nResults: ${passed} passed, ${failed} failed`);
|
|
131
|
+
process.exit(failed > 0 ? 1 : 0);
|
|
132
|
+
}
|
|
133
|
+
main().catch((err) => {
|
|
134
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
135
|
+
console.error('Fatal:', message);
|
|
136
|
+
process.exit(1);
|
|
137
|
+
});
|
|
138
|
+
//# sourceMappingURL=test-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-runner.js","sourceRoot":"","sources":["../src/test-runner.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "port-manager-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Port management MCP server — check, find, and kill processes by port number",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"port-manager-mcp": "dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"typecheck": "tsc --noEmit",
|
|
14
|
+
"dev": "node --loader ts-node/esm src/index.ts",
|
|
15
|
+
"client": "npm run build && node dist/client.js",
|
|
16
|
+
"test": "npm run build && node dist/test-runner.js",
|
|
17
|
+
"clean": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
18
|
+
"release:patch": "npm version patch && npm run build && npm publish",
|
|
19
|
+
"release:minor": "npm version minor && npm run build && npm publish",
|
|
20
|
+
"prepublishOnly": "npm run typecheck && npm run build"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"mcp",
|
|
24
|
+
"model-context-protocol",
|
|
25
|
+
"port-manager",
|
|
26
|
+
"port-checker",
|
|
27
|
+
"kill-port",
|
|
28
|
+
"find-port"
|
|
29
|
+
],
|
|
30
|
+
"author": "",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": ""
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18.0.0"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@modelcontextprotocol/sdk": "^1.28.0",
|
|
41
|
+
"zod": "^3.25.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^22.0.0",
|
|
45
|
+
"typescript": "^5.7.2"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
49
|
+
"zod": "^3.24.0"
|
|
50
|
+
},
|
|
51
|
+
"peerDependenciesMeta": {
|
|
52
|
+
"@modelcontextprotocol/sdk": {
|
|
53
|
+
"optional": false
|
|
54
|
+
},
|
|
55
|
+
"zod": {
|
|
56
|
+
"optional": false
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|