@lionad/port-key-mcp 0.2.0 → 0.4.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 +137 -85
- package/dist/config/index.d.ts +26 -0
- package/dist/config/index.js +24 -0
- package/dist/config/index.js.map +1 -0
- package/dist/logger.d.ts +7 -0
- package/dist/logger.js +48 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp-cli.js +84 -12
- package/dist/mcp-cli.js.map +1 -1
- package/dist/mcp-server.d.ts +16 -2
- package/dist/mcp-server.js +250 -92
- package/dist/mcp-server.js.map +1 -1
- package/dist/resources/index.d.ts +13 -0
- package/dist/resources/index.js +5 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/port-mapping-config.d.ts +13 -0
- package/dist/resources/port-mapping-config.js +22 -0
- package/dist/resources/port-mapping-config.js.map +1 -0
- package/dist/resources/project-port-history.d.ts +15 -0
- package/dist/resources/project-port-history.js +30 -0
- package/dist/resources/project-port-history.js.map +1 -0
- package/dist/session-manager.d.ts +35 -0
- package/dist/session-manager.js +66 -0
- package/dist/session-manager.js.map +1 -0
- package/dist/tools/check-port-availability.d.ts +25 -0
- package/dist/tools/check-port-availability.js +65 -0
- package/dist/tools/check-port-availability.js.map +1 -0
- package/dist/tools/get-design-philosophy.d.ts +24 -0
- package/dist/tools/get-design-philosophy.js +52 -0
- package/dist/tools/get-design-philosophy.js.map +1 -0
- package/dist/tools/get-port-occupancy.d.ts +25 -0
- package/dist/tools/get-port-occupancy.js +69 -0
- package/dist/tools/get-port-occupancy.js.map +1 -0
- package/dist/tools/index.d.ts +94 -0
- package/dist/tools/index.js +11 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/map-project-name-to-port.d.ts +27 -0
- package/dist/tools/map-project-name-to-port.js +51 -0
- package/dist/tools/map-project-name-to-port.js.map +1 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.js +55 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/session-manager.d.ts +35 -0
- package/dist/utils/session-manager.js +66 -0
- package/dist/utils/session-manager.js.map +1 -0
- package/locales/ar.json +1 -1
- package/locales/cn.json +1 -1
- package/locales/de.json +1 -1
- package/locales/es.json +1 -1
- package/locales/fr.json +1 -1
- package/locales/it.json +1 -1
- package/locales/ja.json +1 -1
- package/locales/ko.json +1 -1
- package/locales/pt.json +1 -1
- package/locales/ru.json +1 -1
- package/package.json +11 -5
package/README.md
CHANGED
|
@@ -1,84 +1,139 @@
|
|
|
1
|
-
# PortKey
|
|
1
|
+
# PortKey MCP Server
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
<img width="200" src="/public/logo.png" />
|
|
5
|
-
</p>
|
|
3
|
+
## Description
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
<strong>PortKey:A Simple, Practical Port Naming Strategy</strong>
|
|
9
|
-
</p>
|
|
5
|
+
[Model Context Protocol](https://modelcontextprotocol.io) (MCP) server for PortKey. It provides tools to map project names to port numbers using keyboard-based letter-to-number mapping, check port availability, and access PortKey configuration.
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
<!-- LANGUAGES=("cn" "es" "fr" "de" "ja" "ko" "ru" "ar" "pt" "it") -->
|
|
13
|
-
<a href="./docs/README.cn.md">中文</a> | <a href="./docs/README.es.md">Español</a> | <a href="./docs/README.fr.md">Français</a> | <a href="./docs/README.de.md">Deutsch</a> | <a href="./docs/README.ja.md">日本語</a> | <a href="./docs/README.ko.md">한국어</a> | <a href="./docs/README.ru.md">Русский</a> | <a href="./docs/README.ar.md">العربية</a> | <a href="./docs/README.pt.md">Português</a> | <a href="./docs/README.it.md">Italiano</a>
|
|
14
|
-
</p>
|
|
7
|
+
## Usage
|
|
15
8
|
|
|
16
|
-
|
|
9
|
+
### Running the Server
|
|
17
10
|
|
|
18
|
-
|
|
11
|
+
The PortKey MCP server supports both Stdio and Streamable HTTP transport modes.
|
|
19
12
|
|
|
20
|
-
|
|
13
|
+
#### Stdio Mode (Default)
|
|
21
14
|
|
|
22
|
-
|
|
23
|
-
- If you want to keep browser tabs (or bookmarks) stable, a project’s port shouldn’t keep changing.
|
|
15
|
+
Designed to be run by an IDE-based MCP client like [Visual Studio Code's Copilot](https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode).
|
|
24
16
|
|
|
25
|
-
|
|
17
|
+
```shell
|
|
18
|
+
npx @lionad/port-key-mcp
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
#### HTTP Mode (Streamable)
|
|
22
|
+
|
|
23
|
+
Runs an HTTP server implementing the Streamable HTTP transport. This mode is suitable for remote connections or when stdio is not available.
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
```shell
|
|
26
|
+
# Run on default port 10945
|
|
27
|
+
npx @lionad/port-key-mcp --streamable
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
# Run on specific port
|
|
30
|
+
npx @lionad/port-key-mcp --streamable --port 8080
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
# Reuse the already-running server on the same port (default: true)
|
|
33
|
+
npx @lionad/port-key-mcp --streamable --port 8080 --reuse
|
|
32
34
|
|
|
33
|
-
|
|
35
|
+
# Force starting a new process (will fail if the port is already in use by another service)
|
|
36
|
+
npx @lionad/port-key-mcp --streamable --port 8080 --reuse false
|
|
37
|
+
```
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
Environment variables are also supported:
|
|
40
|
+
```shell
|
|
41
|
+
PORT=8080 LOG_LEVEL=debug npx @lionad/port-key-mcp --streamable
|
|
42
|
+
```
|
|
36
43
|
|
|
37
|
-
|
|
44
|
+
##### Single-instance reuse (Streamable)
|
|
38
45
|
|
|
39
|
-
`
|
|
46
|
+
When you run `npx @lionad/port-key-mcp --streamable` from multiple terminals using the same port, the CLI will detect an existing PortKey MCP server (via `GET /health`) and exit successfully without starting a new server process. This keeps “one port = one MCP server instance” while allowing repeated invocations.
|
|
40
47
|
|
|
41
|
-
|
|
48
|
+
##### Endpoints (Streamable)
|
|
42
49
|
|
|
43
|
-
|
|
50
|
+
- `GET /health` returns a JSON health payload.
|
|
51
|
+
- `POST /mcp`, `GET /mcp`, `DELETE /mcp` implement MCP Streamable HTTP transport (stateful sessions).
|
|
44
52
|
|
|
45
|
-
|
|
46
|
-
- For `"cfetch"`, take `3435` as the base
|
|
47
|
-
- Frontend (`fe`, i.e. `43`) → `34354`
|
|
48
|
-
- Backend (`server`) → `34352`
|
|
49
|
-
- Database (`mongo`) → `34357`
|
|
50
|
-
- …and so on
|
|
53
|
+
### Available Tools
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
- For `"cfetch"`, take `3435` as the base
|
|
54
|
-
- Web → `34351`
|
|
55
|
-
- Backend → `34352`
|
|
56
|
-
- Database → `34353`
|
|
57
|
-
- …and so on
|
|
55
|
+
The MCP server provides the following tools:
|
|
58
56
|
|
|
59
|
-
|
|
57
|
+
- **map-project-name-to-port**: Map a project name to a port number using keyboard-based letter-to-number mapping
|
|
58
|
+
- **get-design-philosophy**: Get design philosophy and background of PortKey
|
|
59
|
+
- **check-port-availability**: Check if a specific port is available or occupied
|
|
60
|
+
- **get-port-occupancy**: Get information about processes occupying specific ports
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
- **System Ports (0-1023)**: Assigned by IETF. Strictly blocked.
|
|
63
|
-
- **User Ports (1024-49151)**: Assigned by IANA. Use with caution as they might conflict with registered services.
|
|
64
|
-
- **Dynamic/Private Ports (49152-65535)**: Not assigned. Safest for private or dynamic use.
|
|
62
|
+
#### map-project-name-to-port
|
|
65
63
|
|
|
66
|
-
|
|
64
|
+
##### Tool Parameters
|
|
67
65
|
|
|
68
|
-
|
|
66
|
+
- `projectName` (string, required): The project name to map to a port number
|
|
67
|
+
- `map` (string, optional): Custom mapping in JSON format (e.g., `{ "1": "qaz", "2": "wsx", ... }`)
|
|
68
|
+
- `preferDigitCount` (number, optional): Preferred digit count for port (2-5, default: 4)
|
|
69
|
+
- `minPort` (number, optional): Minimum port number (0-65535, default: 0)
|
|
70
|
+
- `maxPort` (number, optional): Maximum port number (0-65535, default: 65535)
|
|
71
|
+
- `blockedPorts` (array of numbers, optional): List of blocked port numbers to avoid
|
|
69
72
|
|
|
70
|
-
|
|
73
|
+
##### Example Tool Call
|
|
71
74
|
|
|
72
|
-
```
|
|
73
|
-
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"name": "map-project-name-to-port",
|
|
78
|
+
"arguments": {
|
|
79
|
+
"projectName": "cfetch",
|
|
80
|
+
"preferDigitCount": 4
|
|
81
|
+
}
|
|
82
|
+
}
|
|
74
83
|
```
|
|
75
84
|
|
|
76
|
-
|
|
85
|
+
##### Example Response
|
|
77
86
|
|
|
78
|
-
```
|
|
79
|
-
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"digits": "343536",
|
|
90
|
+
"port": 3435,
|
|
91
|
+
"rejectedCandidates": []
|
|
92
|
+
}
|
|
80
93
|
```
|
|
81
94
|
|
|
95
|
+
#### get-design-philosophy
|
|
96
|
+
|
|
97
|
+
##### Tool Parameters
|
|
98
|
+
|
|
99
|
+
- `lang` (string, optional): Language code for design philosophy content. Supported languages: `"cn"`, `"es"`, `"fr"`, `"de"`, `"ja"`, `"ko"`, `"ru"`, `"ar"`, `"pt"`, `"it"`. Default: `"cn"`.
|
|
100
|
+
|
|
101
|
+
#### check-port-availability
|
|
102
|
+
|
|
103
|
+
##### Tool Parameters
|
|
104
|
+
|
|
105
|
+
- `port` (number, required): The port number to check (0-65535)
|
|
106
|
+
|
|
107
|
+
#### get-port-occupancy
|
|
108
|
+
|
|
109
|
+
##### Tool Parameters
|
|
110
|
+
|
|
111
|
+
- `ports` (array of numbers, optional): List of port numbers to filter results
|
|
112
|
+
|
|
113
|
+
### Available Resources
|
|
114
|
+
|
|
115
|
+
- **config://port-mapping**: Get default port mapping configuration and blocked ports
|
|
116
|
+
- **projects://{projectName}/port-history**: Get history of port assignments for a project
|
|
117
|
+
|
|
118
|
+
### Supported Languages (for design philosophy)
|
|
119
|
+
|
|
120
|
+
| Code | Language |
|
|
121
|
+
|-------|------------|
|
|
122
|
+
| cn | 中文 |
|
|
123
|
+
| es | Español |
|
|
124
|
+
| fr | Français |
|
|
125
|
+
| de | Deutsch |
|
|
126
|
+
| ja | 日本語 |
|
|
127
|
+
| ko | 한국어 |
|
|
128
|
+
| ru | Русский |
|
|
129
|
+
| ar | العربية |
|
|
130
|
+
| pt | Português |
|
|
131
|
+
| it | Italiano |
|
|
132
|
+
|
|
133
|
+
## Configuration
|
|
134
|
+
|
|
135
|
+
You can configure MCP server in your MCP client's configuration file (e.g., for VS Code Copilot, configure in your `.copilot/settings.json`):
|
|
136
|
+
|
|
82
137
|
```json
|
|
83
138
|
{
|
|
84
139
|
"mcpServers": {
|
|
@@ -90,52 +145,49 @@ npx -y @lionad/port-key-mcp
|
|
|
90
145
|
}
|
|
91
146
|
```
|
|
92
147
|
|
|
148
|
+
For HTTP mode configuration in clients that support it:
|
|
93
149
|
|
|
94
|
-
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"mcpServers": {
|
|
153
|
+
"port-key": {
|
|
154
|
+
"command": "npx",
|
|
155
|
+
"args": ["@lionad/port-key-mcp", "--streamable"]
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
95
160
|
|
|
96
|
-
|
|
97
|
-
- `--lang <code>`: output language (currently only `en` and `cn`, default: `cn`)
|
|
98
|
-
- `-d, --digits <count>`: preferred digit count for port (4 or 5, default: 4)
|
|
99
|
-
- `-h, --help`: show help
|
|
161
|
+
## Logs
|
|
100
162
|
|
|
101
|
-
|
|
163
|
+
In Streamable HTTP mode, logs are written under `~/.port-key/logs`.
|
|
102
164
|
|
|
103
|
-
|
|
104
|
-
npx @lionad/port-key cfetch # -> 3435
|
|
105
|
-
npx @lionad/port-key cfetch --digits 4 # -> 3435 (4-digit port)
|
|
106
|
-
npx @lionad/port-key cfetch --digits 5 # -> 34353 (5-digit port)
|
|
107
|
-
```
|
|
165
|
+
## Development
|
|
108
166
|
|
|
109
|
-
|
|
110
|
-
- Default log language is `cn`. Use `--lang en` to show English messages.
|
|
111
|
-
- Use `-h` or `--help` to show help.
|
|
167
|
+
Build locales (generates from docs/ directory):
|
|
112
168
|
|
|
113
|
-
|
|
169
|
+
```shell
|
|
170
|
+
pnpm run build:locales
|
|
171
|
+
```
|
|
114
172
|
|
|
115
|
-
|
|
173
|
+
Run tests:
|
|
116
174
|
|
|
117
|
-
|
|
175
|
+
```shell
|
|
176
|
+
pnpm test
|
|
177
|
+
```
|
|
118
178
|
|
|
119
|
-
|
|
179
|
+
Run tests in watch mode:
|
|
120
180
|
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
// Preferred digit count for port (4 or 5)
|
|
124
|
-
"preferDigitCount": 5,
|
|
125
|
-
// Custom letter-to-digit mapping
|
|
126
|
-
"blockedPorts": [3000, 3001, 3002, 6666],
|
|
127
|
-
// Port range limits (inclusive)
|
|
128
|
-
"minPort": 1024,
|
|
129
|
-
"maxPort": 49151
|
|
130
|
-
}
|
|
181
|
+
```shell
|
|
182
|
+
pnpm run test:watch
|
|
131
183
|
```
|
|
132
184
|
|
|
133
|
-
|
|
185
|
+
E2E tests live under `tests/e2e/` and are included in `pnpm test`.
|
|
134
186
|
|
|
135
|
-
##
|
|
187
|
+
## Thanks
|
|
136
188
|
|
|
137
|
-
|
|
189
|
+
- **[Template-Nodejs-MCP-Server](https://github.com/HarveyYifanLi/Template-Nodejs-MCP-Server)** by HarveyYifanLi
|
|
190
|
+
- Provided excellent examples of stateful session management and modular tool/resource architecture.
|
|
138
191
|
|
|
139
|
-
-
|
|
140
|
-
-
|
|
141
|
-
- 运行测试:`pnpm -C packages/core test` 或 `pnpm -C packages/core test:watch`。
|
|
192
|
+
- **[mcp-restaurant-booking](https://github.com/modelcontextprotocol/typescript-sdk/tree/main/servers/restaurant)** by Model Context Protocol
|
|
193
|
+
- Provided reference for production-grade TypeScript project configuration and logging systems.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
interface LoggingConfig {
|
|
2
|
+
level: string;
|
|
3
|
+
}
|
|
4
|
+
interface ServerConfig {
|
|
5
|
+
port: number;
|
|
6
|
+
streamable: boolean;
|
|
7
|
+
}
|
|
8
|
+
interface SessionConfig {
|
|
9
|
+
ttl: number;
|
|
10
|
+
timeout: number;
|
|
11
|
+
}
|
|
12
|
+
interface HealthConfig {
|
|
13
|
+
enableDiskCheck: boolean;
|
|
14
|
+
enableMemoryCheck: boolean;
|
|
15
|
+
enableSessionCheck: boolean;
|
|
16
|
+
diskThreshold: number;
|
|
17
|
+
memoryThreshold: number;
|
|
18
|
+
}
|
|
19
|
+
interface Config {
|
|
20
|
+
logging: LoggingConfig;
|
|
21
|
+
server: ServerConfig;
|
|
22
|
+
session: SessionConfig;
|
|
23
|
+
health: HealthConfig;
|
|
24
|
+
}
|
|
25
|
+
declare const config: Config;
|
|
26
|
+
export default config;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import dotenv from 'dotenv';
|
|
2
|
+
dotenv.config();
|
|
3
|
+
const config = {
|
|
4
|
+
logging: {
|
|
5
|
+
level: process.env.LOG_LEVEL || 'info',
|
|
6
|
+
},
|
|
7
|
+
server: {
|
|
8
|
+
port: process.env.PORT ? parseInt(process.env.PORT, 10) : 10945,
|
|
9
|
+
streamable: process.env.STREAMABLE === 'true' || process.env.STREAMABLE === '1',
|
|
10
|
+
},
|
|
11
|
+
session: {
|
|
12
|
+
ttl: parseInt(process.env.SESSION_TTL || '3600', 10),
|
|
13
|
+
timeout: parseInt(process.env.SESSION_TIMEOUT || '300000', 10),
|
|
14
|
+
},
|
|
15
|
+
health: {
|
|
16
|
+
enableDiskCheck: process.env.ENABLE_DISK_CHECK !== 'false',
|
|
17
|
+
enableMemoryCheck: process.env.ENABLE_MEMORY_CHECK !== 'false',
|
|
18
|
+
enableSessionCheck: process.env.ENABLE_SESSION_CHECK !== 'false',
|
|
19
|
+
diskThreshold: parseInt(process.env.DISK_THRESHOLD || '1024', 10),
|
|
20
|
+
memoryThreshold: parseInt(process.env.MEMORY_THRESHOLD || '512', 10),
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
export default config;
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,CAAC,MAAM,EAAE,CAAC;AA+BhB,MAAM,MAAM,GAAW;IACrB,OAAO,EAAE;QACP,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM;KACvC;IACD,MAAM,EAAE;QACN,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK;QAC/D,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,KAAK,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,KAAK,GAAG;KAChF;IACD,OAAO,EAAE;QACP,GAAG,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,MAAM,EAAE,EAAE,CAAC;QACpD,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,QAAQ,EAAE,EAAE,CAAC;KAC/D;IACD,MAAM,EAAE;QACN,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,OAAO;QAC1D,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,KAAK,OAAO;QAC9D,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,OAAO;QAChE,aAAa,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,MAAM,EAAE,EAAE,CAAC;QACjE,eAAe,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,KAAK,EAAE,EAAE,CAAC;KACrE;CACF,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/logger.d.ts
ADDED
package/dist/logger.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import winston from 'winston';
|
|
2
|
+
import DailyRotateFile from 'winston-daily-rotate-file';
|
|
3
|
+
import config from './config/index.js';
|
|
4
|
+
const logger = winston.createLogger({
|
|
5
|
+
level: config.logging.level,
|
|
6
|
+
format: winston.format.combine(winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.json()),
|
|
7
|
+
transports: [
|
|
8
|
+
new DailyRotateFile({
|
|
9
|
+
filename: 'logs/error-%DATE%.log',
|
|
10
|
+
datePattern: 'YYYY-MM-DD',
|
|
11
|
+
zippedArchive: true,
|
|
12
|
+
maxSize: '10m',
|
|
13
|
+
maxFiles: '14d',
|
|
14
|
+
level: 'error',
|
|
15
|
+
}),
|
|
16
|
+
new DailyRotateFile({
|
|
17
|
+
filename: 'logs/combined-%DATE%.log',
|
|
18
|
+
datePattern: 'YYYY-MM-DD',
|
|
19
|
+
zippedArchive: true,
|
|
20
|
+
maxSize: '1',
|
|
21
|
+
maxFiles: '14d',
|
|
22
|
+
}),
|
|
23
|
+
],
|
|
24
|
+
});
|
|
25
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
26
|
+
logger.add(new winston.transports.Console({
|
|
27
|
+
format: winston.format.combine(winston.format.colorize(), winston.format.printf(({ timestamp, level, message, ...rest }) => {
|
|
28
|
+
let args = '';
|
|
29
|
+
if (typeof message === 'object') {
|
|
30
|
+
args = JSON.stringify(message, null, 2);
|
|
31
|
+
message = '';
|
|
32
|
+
}
|
|
33
|
+
const extraArgs = Object.keys(rest).length
|
|
34
|
+
? JSON.stringify(rest, null, 2)
|
|
35
|
+
: '';
|
|
36
|
+
return `${timestamp} ${level}: ${message} ${args} ${extraArgs}`.trim();
|
|
37
|
+
})),
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
logger.getLevel = () => logger.level;
|
|
41
|
+
logger.setLevel = (level) => {
|
|
42
|
+
logger.level = level;
|
|
43
|
+
logger.transports.forEach((transport) => {
|
|
44
|
+
transport.level = level;
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
export default logger;
|
|
48
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,eAAe,MAAM,2BAA2B,CAAC;AACxD,OAAO,MAAM,MAAM,mBAAmB,CAAC;AAOvC,MAAM,MAAM,GAAiB,OAAO,CAAC,YAAY,CAAC;IAChD,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK;IAC3B,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAC5B,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,EAC1B,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACtC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CACtB;IACD,UAAU,EAAE;QACV,IAAI,eAAe,CAAC;YAClB,QAAQ,EAAE,uBAAuB;YACjC,WAAW,EAAE,YAAY;YACzB,aAAa,EAAE,IAAI;YACnB,OAAO,EAAE,KAAK;YACd,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE,OAAO;SACf,CAAC;QACF,IAAI,eAAe,CAAC;YAClB,QAAQ,EAAE,0BAA0B;YACpC,WAAW,EAAE,YAAY;YACzB,aAAa,EAAE,IAAI;YACnB,OAAO,EAAE,GAAG;YACZ,QAAQ,EAAE,KAAK;SAChB,CAAC;KACH;CACF,CAAiB,CAAC;AAEnB,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;IAC1C,MAAM,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC;QACxC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAC5B,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,EACzB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE;YAC/D,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAChC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;gBACxC,OAAO,GAAG,EAAE,CAAC;YACf,CAAC;YACD,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM;gBACxC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC/B,CAAC,CAAC,EAAE,CAAC;YACP,OAAO,GAAG,SAAS,IAAI,KAAK,KAAK,OAAO,IAAI,IAAI,IAAI,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC;QACzE,CAAC,CAAC,CACH;KACF,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,CAAC,QAAQ,GAAG,GAAW,EAAE,CAAC,MAAM,CAAC,KAAe,CAAC;AACvD,MAAM,CAAC,QAAQ,GAAG,CAAC,KAAa,EAAQ,EAAE;IACxC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE;QACtC,SAAS,CAAC,KAAK,GAAG,KAAK,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/mcp-cli.js
CHANGED
|
@@ -1,13 +1,85 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import { mcpServerApp } from "./mcp-server.js";
|
|
2
|
+
import config from "./config/index.js";
|
|
3
|
+
// Parse command line arguments
|
|
4
|
+
const args = process.argv.slice(2);
|
|
5
|
+
const options = {};
|
|
6
|
+
function printHelp() {
|
|
7
|
+
console.log(`
|
|
8
|
+
Usage: port-key-mcp [options]
|
|
9
|
+
|
|
10
|
+
Options:
|
|
11
|
+
-s, --streamable Run in streamable mode (HTTP)
|
|
12
|
+
-p, --port <number> Specify port number (default: 10945)
|
|
13
|
+
-l, --local [boolean] Enable/disable local tools (default: true)
|
|
14
|
+
--reuse [boolean] Reuse existing streamable server on same port (default: true)
|
|
15
|
+
-h, --help Show this help message
|
|
16
|
+
|
|
17
|
+
Examples:
|
|
18
|
+
port-key-mcp --streamable --port 8080
|
|
19
|
+
port-key-mcp --local false
|
|
20
|
+
`);
|
|
21
|
+
}
|
|
22
|
+
for (let i = 0; i < args.length; i++) {
|
|
23
|
+
const arg = args[i];
|
|
24
|
+
if (arg === "--help" || arg === "-h") {
|
|
25
|
+
printHelp();
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
else if (arg === "--streamable" || arg === "-s") {
|
|
29
|
+
options.streamable = true;
|
|
30
|
+
}
|
|
31
|
+
else if (arg === "--port" || arg === "-p") {
|
|
32
|
+
const port = parseInt(args[i + 1], 10);
|
|
33
|
+
if (!isNaN(port)) {
|
|
34
|
+
options.port = port;
|
|
35
|
+
i++; // Skip next argument
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else if (arg === "--local" || arg === "-l") {
|
|
39
|
+
options.local = args[i + 1] !== 'false';
|
|
40
|
+
if (args[i + 1] === 'true' || args[i + 1] === 'false') {
|
|
41
|
+
i++; // Skip next argument if it's a boolean value
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else if (arg === "--reuse") {
|
|
45
|
+
options.reuse = args[i + 1] !== "false";
|
|
46
|
+
if (args[i + 1] === "true" || args[i + 1] === "false") {
|
|
47
|
+
i++;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function resolvePort() {
|
|
52
|
+
if (typeof options.port === "number")
|
|
53
|
+
return options.port;
|
|
54
|
+
const envPort = process.env.PORT ? parseInt(process.env.PORT, 10) : NaN;
|
|
55
|
+
if (!Number.isNaN(envPort))
|
|
56
|
+
return envPort;
|
|
57
|
+
return config.server.port;
|
|
58
|
+
}
|
|
59
|
+
async function isPortKeyMcpServerRunning(port) {
|
|
60
|
+
try {
|
|
61
|
+
const res = await fetch(`http://127.0.0.1:${port}/health`, {
|
|
62
|
+
signal: AbortSignal.timeout(1000),
|
|
63
|
+
headers: { Accept: "application/json" },
|
|
64
|
+
});
|
|
65
|
+
if (!res.ok)
|
|
66
|
+
return false;
|
|
67
|
+
const body = await res.json().catch(() => null);
|
|
68
|
+
return Boolean(body && typeof body === "object" && body.status === "ok");
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const shouldRunStreamable = options.streamable || config.server.streamable;
|
|
75
|
+
const reuseEnabled = options.reuse !== false;
|
|
76
|
+
if (shouldRunStreamable && reuseEnabled) {
|
|
77
|
+
const port = resolvePort();
|
|
78
|
+
const running = await isPortKeyMcpServerRunning(port);
|
|
79
|
+
if (running) {
|
|
80
|
+
console.log(`PortKey MCP Server already running at http://127.0.0.1:${port}`);
|
|
81
|
+
process.exit(0);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
await mcpServerApp.run(options);
|
|
13
85
|
//# sourceMappingURL=mcp-cli.js.map
|
package/dist/mcp-cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-cli.js","sourceRoot":"","sources":["../src/mcp-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"mcp-cli.js","sourceRoot":"","sources":["../src/mcp-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,MAAM,MAAM,mBAAmB,CAAC;AAEvC,+BAA+B;AAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,OAAO,GAA8E,EAAE,CAAC;AAE9F,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;CAab,CAAC,CAAC;AACH,CAAC;AAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACrC,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;SAAM,IAAI,GAAG,KAAK,cAAc,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAClD,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAC5B,CAAC;SAAM,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;YACpB,CAAC,EAAE,CAAC,CAAC,qBAAqB;QAC5B,CAAC;IACH,CAAC;SAAM,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC7C,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,OAAO,CAAC;QACxC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,OAAO,EAAE,CAAC;YACpD,CAAC,EAAE,CAAC,CAAC,6CAA6C;QACtD,CAAC;IACH,CAAC;SAAM,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,OAAO,CAAC;QACxC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,OAAO,EAAE,CAAC;YACtD,CAAC,EAAE,CAAC;QACN,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,WAAW;IAClB,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC,IAAI,CAAC;IAC1D,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACxE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IAC3C,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;AAC5B,CAAC;AAED,KAAK,UAAU,yBAAyB,CAAC,IAAY;IACnD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,oBAAoB,IAAI,SAAS,EAAE;YACzD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;YACjC,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;SACxC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,KAAK,CAAC;QAC1B,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAChD,OAAO,OAAO,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAK,IAAY,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC;IACpF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,mBAAmB,GAAG,OAAO,CAAC,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC;AAC3E,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,KAAK,KAAK,CAAC;AAE7C,IAAI,mBAAmB,IAAI,YAAY,EAAE,CAAC;IACxC,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,MAAM,yBAAyB,CAAC,IAAI,CAAC,CAAC;IACtD,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,0DAA0D,IAAI,EAAE,CAAC,CAAC;QAC9E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC"}
|
package/dist/mcp-server.d.ts
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
declare
|
|
3
|
-
|
|
2
|
+
export declare class MCPServerApp {
|
|
3
|
+
private server;
|
|
4
|
+
constructor();
|
|
5
|
+
private createServer;
|
|
6
|
+
private registerTools;
|
|
7
|
+
private registerResources;
|
|
8
|
+
getMcpServer(): McpServer;
|
|
9
|
+
runStdio(): Promise<void>;
|
|
10
|
+
runHttp(port?: number): Promise<void>;
|
|
11
|
+
run(options?: {
|
|
12
|
+
streamable?: boolean;
|
|
13
|
+
port?: number;
|
|
14
|
+
local?: boolean;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
export declare const mcpServerApp: MCPServerApp;
|