ssh-mcp-pro 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/AGENTS.md +127 -0
- package/ARCHITECTURE.md +145 -0
- package/LICENSE +21 -0
- package/LICENSES/MIT.txt +21 -0
- package/MIGRATION.md +14 -0
- package/README.md +175 -0
- package/REGISTRY_SUBMISSION.md +38 -0
- package/SECURITY.md +40 -0
- package/SECURITY_DECISIONS.md +59 -0
- package/dist/agent-bin.d.ts +3 -0
- package/dist/agent-bin.d.ts.map +1 -0
- package/dist/agent-bin.js +8 -0
- package/dist/agent-bin.js.map +1 -0
- package/dist/audit.d.ts +25 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +50 -0
- package/dist/audit.js.map +1 -0
- package/dist/auth.d.ts +4 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +33 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli.d.ts +16 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +99 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +103 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +490 -0
- package/dist/config.js.map +1 -0
- package/dist/connector-credentials.d.ts +8 -0
- package/dist/connector-credentials.d.ts.map +1 -0
- package/dist/connector-credentials.js +132 -0
- package/dist/connector-credentials.js.map +1 -0
- package/dist/connector-profile.d.ts +17 -0
- package/dist/connector-profile.d.ts.map +1 -0
- package/dist/connector-profile.js +81 -0
- package/dist/connector-profile.js.map +1 -0
- package/dist/container.d.ts +18 -0
- package/dist/container.d.ts.map +1 -0
- package/dist/container.js +52 -0
- package/dist/container.js.map +1 -0
- package/dist/detect.d.ts +7 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +271 -0
- package/dist/detect.js.map +1 -0
- package/dist/ensure.d.ts +17 -0
- package/dist/ensure.d.ts.map +1 -0
- package/dist/ensure.js +531 -0
- package/dist/ensure.js.map +1 -0
- package/dist/errors.d.ts +54 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +84 -0
- package/dist/errors.js.map +1 -0
- package/dist/fs-tools.d.ts +26 -0
- package/dist/fs-tools.d.ts.map +1 -0
- package/dist/fs-tools.js +599 -0
- package/dist/fs-tools.js.map +1 -0
- package/dist/http-rate-limit.d.ts +9 -0
- package/dist/http-rate-limit.d.ts.map +1 -0
- package/dist/http-rate-limit.js +41 -0
- package/dist/http-rate-limit.js.map +1 -0
- package/dist/http-security.d.ts +22 -0
- package/dist/http-security.d.ts.map +1 -0
- package/dist/http-security.js +88 -0
- package/dist/http-security.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +201 -0
- package/dist/index.js.map +1 -0
- package/dist/logging.d.ts +52 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +180 -0
- package/dist/logging.js.map +1 -0
- package/dist/mcp.d.ts +16 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +159 -0
- package/dist/mcp.js.map +1 -0
- package/dist/metrics.d.ts +95 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +204 -0
- package/dist/metrics.js.map +1 -0
- package/dist/oauth.d.ts +14 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +105 -0
- package/dist/oauth.js.map +1 -0
- package/dist/policy.d.ts +64 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +368 -0
- package/dist/policy.js.map +1 -0
- package/dist/process.d.ts +24 -0
- package/dist/process.d.ts.map +1 -0
- package/dist/process.js +212 -0
- package/dist/process.js.map +1 -0
- package/dist/prompts.d.ts +49 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +191 -0
- package/dist/prompts.js.map +1 -0
- package/dist/rate-limiter.d.ts +57 -0
- package/dist/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limiter.js +141 -0
- package/dist/rate-limiter.js.map +1 -0
- package/dist/remote/agent-cli.d.ts +2 -0
- package/dist/remote/agent-cli.d.ts.map +1 -0
- package/dist/remote/agent-cli.js +270 -0
- package/dist/remote/agent-cli.js.map +1 -0
- package/dist/remote/agent-executor.d.ts +26 -0
- package/dist/remote/agent-executor.d.ts.map +1 -0
- package/dist/remote/agent-executor.js +400 -0
- package/dist/remote/agent-executor.js.map +1 -0
- package/dist/remote/config.d.ts +3 -0
- package/dist/remote/config.d.ts.map +1 -0
- package/dist/remote/config.js +52 -0
- package/dist/remote/config.js.map +1 -0
- package/dist/remote/control-plane.d.ts +57 -0
- package/dist/remote/control-plane.d.ts.map +1 -0
- package/dist/remote/control-plane.js +1248 -0
- package/dist/remote/control-plane.js.map +1 -0
- package/dist/remote/crypto.d.ts +38 -0
- package/dist/remote/crypto.d.ts.map +1 -0
- package/dist/remote/crypto.js +143 -0
- package/dist/remote/crypto.js.map +1 -0
- package/dist/remote/mcp-tools.d.ts +10 -0
- package/dist/remote/mcp-tools.d.ts.map +1 -0
- package/dist/remote/mcp-tools.js +201 -0
- package/dist/remote/mcp-tools.js.map +1 -0
- package/dist/remote/policy.d.ts +11 -0
- package/dist/remote/policy.d.ts.map +1 -0
- package/dist/remote/policy.js +94 -0
- package/dist/remote/policy.js.map +1 -0
- package/dist/remote/schemas.d.ts +298 -0
- package/dist/remote/schemas.d.ts.map +1 -0
- package/dist/remote/schemas.js +111 -0
- package/dist/remote/schemas.js.map +1 -0
- package/dist/remote/scopes.d.ts +6 -0
- package/dist/remote/scopes.d.ts.map +1 -0
- package/dist/remote/scopes.js +24 -0
- package/dist/remote/scopes.js.map +1 -0
- package/dist/remote/store.d.ts +45 -0
- package/dist/remote/store.d.ts.map +1 -0
- package/dist/remote/store.js +355 -0
- package/dist/remote/store.js.map +1 -0
- package/dist/remote/types.d.ts +183 -0
- package/dist/remote/types.d.ts.map +1 -0
- package/dist/remote/types.js +103 -0
- package/dist/remote/types.js.map +1 -0
- package/dist/remote/util.d.ts +6 -0
- package/dist/remote/util.d.ts.map +1 -0
- package/dist/remote/util.js +45 -0
- package/dist/remote/util.js.map +1 -0
- package/dist/remote/websocket.d.ts +26 -0
- package/dist/remote/websocket.d.ts.map +1 -0
- package/dist/remote/websocket.js +167 -0
- package/dist/remote/websocket.js.map +1 -0
- package/dist/render-http.d.ts +2 -0
- package/dist/render-http.d.ts.map +1 -0
- package/dist/render-http.js +14 -0
- package/dist/render-http.js.map +1 -0
- package/dist/resources.d.ts +19 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +96 -0
- package/dist/resources.js.map +1 -0
- package/dist/retry.d.ts +45 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +120 -0
- package/dist/retry.js.map +1 -0
- package/dist/safety.d.ts +31 -0
- package/dist/safety.d.ts.map +1 -0
- package/dist/safety.js +174 -0
- package/dist/safety.js.map +1 -0
- package/dist/server-http.d.ts +2 -0
- package/dist/server-http.d.ts.map +1 -0
- package/dist/server-http.js +432 -0
- package/dist/server-http.js.map +1 -0
- package/dist/session.d.ts +116 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +666 -0
- package/dist/session.js.map +1 -0
- package/dist/shell.d.ts +10 -0
- package/dist/shell.d.ts.map +1 -0
- package/dist/shell.js +83 -0
- package/dist/shell.js.map +1 -0
- package/dist/ssh-config.d.ts +94 -0
- package/dist/ssh-config.d.ts.map +1 -0
- package/dist/ssh-config.js +234 -0
- package/dist/ssh-config.js.map +1 -0
- package/dist/streaming.d.ts +36 -0
- package/dist/streaming.d.ts.map +1 -0
- package/dist/streaming.js +140 -0
- package/dist/streaming.js.map +1 -0
- package/dist/telemetry.d.ts +17 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +101 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/tools/connector.provider.d.ts +28 -0
- package/dist/tools/connector.provider.d.ts.map +1 -0
- package/dist/tools/connector.provider.js +360 -0
- package/dist/tools/connector.provider.js.map +1 -0
- package/dist/tools/ensure.provider.d.ts +18 -0
- package/dist/tools/ensure.provider.d.ts.map +1 -0
- package/dist/tools/ensure.provider.js +173 -0
- package/dist/tools/ensure.provider.js.map +1 -0
- package/dist/tools/fs.provider.d.ts +21 -0
- package/dist/tools/fs.provider.d.ts.map +1 -0
- package/dist/tools/fs.provider.js +259 -0
- package/dist/tools/fs.provider.js.map +1 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +68 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/metadata.d.ts +11 -0
- package/dist/tools/metadata.d.ts.map +1 -0
- package/dist/tools/metadata.js +10 -0
- package/dist/tools/metadata.js.map +1 -0
- package/dist/tools/output-schemas.d.ts +217 -0
- package/dist/tools/output-schemas.d.ts.map +1 -0
- package/dist/tools/output-schemas.js +300 -0
- package/dist/tools/output-schemas.js.map +1 -0
- package/dist/tools/process.provider.d.ts +22 -0
- package/dist/tools/process.provider.d.ts.map +1 -0
- package/dist/tools/process.provider.js +146 -0
- package/dist/tools/process.provider.js.map +1 -0
- package/dist/tools/registry.d.ts +12 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +163 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/results.d.ts +4 -0
- package/dist/tools/results.d.ts.map +1 -0
- package/dist/tools/results.js +5 -0
- package/dist/tools/results.js.map +1 -0
- package/dist/tools/session.provider.d.ts +23 -0
- package/dist/tools/session.provider.d.ts.map +1 -0
- package/dist/tools/session.provider.js +299 -0
- package/dist/tools/session.provider.js.map +1 -0
- package/dist/tools/system.provider.d.ts +18 -0
- package/dist/tools/system.provider.d.ts.map +1 -0
- package/dist/tools/system.provider.js +81 -0
- package/dist/tools/system.provider.js.map +1 -0
- package/dist/tools/transfer.provider.d.ts +16 -0
- package/dist/tools/transfer.provider.d.ts.map +1 -0
- package/dist/tools/transfer.provider.js +85 -0
- package/dist/tools/transfer.provider.js.map +1 -0
- package/dist/tools/tunnel.provider.d.ts +18 -0
- package/dist/tools/tunnel.provider.d.ts.map +1 -0
- package/dist/tools/tunnel.provider.js +142 -0
- package/dist/tools/tunnel.provider.js.map +1 -0
- package/dist/tools/types.d.ts +16 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/transfer.d.ts +40 -0
- package/dist/transfer.d.ts.map +1 -0
- package/dist/transfer.js +363 -0
- package/dist/transfer.js.map +1 -0
- package/dist/tunnel.d.ts +37 -0
- package/dist/tunnel.d.ts.map +1 -0
- package/dist/tunnel.js +234 -0
- package/dist/tunnel.js.map +1 -0
- package/dist/types.d.ts +341 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +184 -0
- package/dist/types.js.map +1 -0
- package/docs/docker.md +22 -0
- package/examples/README.md +77 -0
- package/mcp.json +21 -0
- package/package.json +147 -0
- package/registry/ssh-mcp-pro/mcp.json +21 -0
- package/server.json +76 -0
package/dist/safety.js
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safety utilities for SSH command execution
|
|
3
|
+
*
|
|
4
|
+
* Provides warnings for potentially dangerous commands without blocking them.
|
|
5
|
+
* Users are free to execute any command - this is just informational.
|
|
6
|
+
*/
|
|
7
|
+
import { logger } from "./logging.js";
|
|
8
|
+
/**
|
|
9
|
+
* Patterns for potentially dangerous commands
|
|
10
|
+
*/
|
|
11
|
+
const RECURSIVE_RM_OPTIONS = String.raw `(?=(?:[^\s]+\s+)*?(?:-[A-Za-z]*r[A-Za-z]*|--recursive))(?:-[A-Za-z]+|--[A-Za-z-]+)(?:\s+(?:-[A-Za-z]+|--[A-Za-z-]+))*`;
|
|
12
|
+
const SHELL_ARG = String.raw `(?:"[^"]*"|'[^']*'|\S+)`;
|
|
13
|
+
const SHELL_ARG_END = String.raw `(?:[\s;&|]|$)`;
|
|
14
|
+
function recursiveRmTargetPattern(targetPattern) {
|
|
15
|
+
return new RegExp(String.raw `rm\s+${RECURSIVE_RM_OPTIONS}(?:\s+${SHELL_ARG})*\s+${targetPattern}${SHELL_ARG_END}`, "i");
|
|
16
|
+
}
|
|
17
|
+
const DANGEROUS_PATTERNS = [
|
|
18
|
+
// Critical: System destruction
|
|
19
|
+
{
|
|
20
|
+
pattern: recursiveRmTargetPattern(String.raw `(?:"/"|'/'|/)`),
|
|
21
|
+
riskLevel: "critical",
|
|
22
|
+
warning: "This command will delete the entire root filesystem!",
|
|
23
|
+
suggestion: "Double-check the path before executing",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
pattern: recursiveRmTargetPattern(String.raw `(?:"/\*"|'/\*'|/\*)`),
|
|
27
|
+
riskLevel: "critical",
|
|
28
|
+
warning: "This command will delete all files in the root directory!",
|
|
29
|
+
suggestion: "Double-check the path before executing",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
pattern: /mkfs\./i,
|
|
33
|
+
riskLevel: "critical",
|
|
34
|
+
warning: "This command will format a filesystem, causing data loss!",
|
|
35
|
+
suggestion: "Verify the target device carefully",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
pattern: /dd\s+.*of=\/dev\/(sd|hd|nvme|vd)/i,
|
|
39
|
+
riskLevel: "critical",
|
|
40
|
+
warning: "This command writes directly to a disk device!",
|
|
41
|
+
suggestion: "Verify input and output devices before executing",
|
|
42
|
+
},
|
|
43
|
+
// High: System configuration changes
|
|
44
|
+
{
|
|
45
|
+
pattern: /chmod\s+(-R\s+)?777\s+\//i,
|
|
46
|
+
riskLevel: "high",
|
|
47
|
+
warning: "Setting 777 permissions on root is a security risk!",
|
|
48
|
+
suggestion: "Use more restrictive permissions",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
pattern: /chown\s+-R\s+.*\s+\/\s*$/i,
|
|
52
|
+
riskLevel: "high",
|
|
53
|
+
warning: "Changing ownership of root directory recursively!",
|
|
54
|
+
suggestion: "Verify the target path",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
pattern: /:\(\)\{\s*:\|:&\s*\};\s*:/i,
|
|
58
|
+
riskLevel: "critical",
|
|
59
|
+
warning: "Fork bomb detected! This will crash the system!",
|
|
60
|
+
suggestion: "Do not execute this command",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
pattern: />\s*\/dev\/sd[a-z]$/i,
|
|
64
|
+
riskLevel: "critical",
|
|
65
|
+
warning: "Writing directly to disk device!",
|
|
66
|
+
suggestion: "Verify the target device",
|
|
67
|
+
},
|
|
68
|
+
// Medium: Service disruption
|
|
69
|
+
{
|
|
70
|
+
pattern: /shutdown|reboot|init\s+[0-6]|poweroff/i,
|
|
71
|
+
riskLevel: "medium",
|
|
72
|
+
warning: "This command will shutdown or reboot the system",
|
|
73
|
+
suggestion: "Ensure you have physical or out-of-band access",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
pattern: /systemctl\s+(stop|disable)\s+(sshd|ssh|networking|network)/i,
|
|
77
|
+
riskLevel: "high",
|
|
78
|
+
warning: "Stopping this service may disconnect your SSH session!",
|
|
79
|
+
suggestion: "Have alternative access method ready",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
pattern: /iptables\s+-F/i,
|
|
83
|
+
riskLevel: "medium",
|
|
84
|
+
warning: "Flushing firewall rules may expose the system",
|
|
85
|
+
suggestion: "Have a backup of current rules",
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
pattern: /ufw\s+disable/i,
|
|
89
|
+
riskLevel: "medium",
|
|
90
|
+
warning: "Disabling firewall will expose all ports",
|
|
91
|
+
suggestion: "Consider using specific allow rules instead",
|
|
92
|
+
},
|
|
93
|
+
// Low: Common mistakes
|
|
94
|
+
{
|
|
95
|
+
pattern: recursiveRmTargetPattern(String.raw `(?:"\."|'\.'|\.)`),
|
|
96
|
+
riskLevel: "low",
|
|
97
|
+
warning: "This will delete the current directory recursively",
|
|
98
|
+
suggestion: "Verify you are in the correct directory",
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
pattern: />\s*\/etc\/(passwd|shadow|sudoers)/i,
|
|
102
|
+
riskLevel: "high",
|
|
103
|
+
warning: "Overwriting critical system file!",
|
|
104
|
+
suggestion: "Use proper editing tools like visudo",
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
pattern: /curl\s+.*\|\s*(sudo\s+)?(bash|sh)/i,
|
|
108
|
+
riskLevel: "medium",
|
|
109
|
+
warning: "Piping remote script directly to shell",
|
|
110
|
+
suggestion: "Review the script before executing",
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
pattern: /wget\s+.*\|\s*(sudo\s+)?(bash|sh)/i,
|
|
114
|
+
riskLevel: "medium",
|
|
115
|
+
warning: "Piping remote script directly to shell",
|
|
116
|
+
suggestion: "Review the script before executing",
|
|
117
|
+
},
|
|
118
|
+
];
|
|
119
|
+
/**
|
|
120
|
+
* Checks if a command is potentially dangerous
|
|
121
|
+
* This NEVER blocks commands - only provides warnings
|
|
122
|
+
*/
|
|
123
|
+
export function checkCommandSafety(command) {
|
|
124
|
+
if (!command) {
|
|
125
|
+
return { safe: true };
|
|
126
|
+
}
|
|
127
|
+
const normalizedCommand = command.trim();
|
|
128
|
+
for (const { pattern, riskLevel, warning, suggestion } of DANGEROUS_PATTERNS) {
|
|
129
|
+
if (pattern.test(normalizedCommand)) {
|
|
130
|
+
logger.debug("Safety warning triggered", {
|
|
131
|
+
command: normalizedCommand.substring(0, 50),
|
|
132
|
+
riskLevel,
|
|
133
|
+
});
|
|
134
|
+
return {
|
|
135
|
+
safe: false,
|
|
136
|
+
warning,
|
|
137
|
+
riskLevel,
|
|
138
|
+
...(suggestion ? { suggestion } : {}),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { safe: true };
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Formats a safety warning for inclusion in command output
|
|
146
|
+
*/
|
|
147
|
+
export function formatSafetyWarning(result) {
|
|
148
|
+
if (result.safe) {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
const label = {
|
|
152
|
+
low: "LOW",
|
|
153
|
+
medium: "MEDIUM",
|
|
154
|
+
high: "HIGH",
|
|
155
|
+
critical: "CRITICAL",
|
|
156
|
+
};
|
|
157
|
+
let message = `[${label[result.riskLevel ?? "medium"]}] WARNING: ${result.warning}`;
|
|
158
|
+
if (result.suggestion) {
|
|
159
|
+
message += `\nSuggestion: ${result.suggestion}`;
|
|
160
|
+
}
|
|
161
|
+
return message;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Enhances command result with safety warning if applicable
|
|
165
|
+
*/
|
|
166
|
+
export function addSafetyWarningToResult(command, result) {
|
|
167
|
+
const safetyCheck = checkCommandSafety(command);
|
|
168
|
+
const warning = formatSafetyWarning(safetyCheck);
|
|
169
|
+
if (warning) {
|
|
170
|
+
return { ...result, safetyWarning: warning };
|
|
171
|
+
}
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=safety.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safety.js","sourceRoot":"","sources":["../src/safety.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-http.d.ts","sourceRoot":"","sources":["../src/server-http.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { URL } from "node:url";
|
|
5
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
6
|
+
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
7
|
+
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
+
import { isBearerAuthorizationValid } from "./auth.js";
|
|
9
|
+
import { createContainer } from "./container.js";
|
|
10
|
+
import { SERVER_VERSION, SSHMCPServer } from "./mcp.js";
|
|
11
|
+
import { logger } from "./logging.js";
|
|
12
|
+
import { isOAuthAuthorizationValid } from "./oauth.js";
|
|
13
|
+
import { initTelemetry, shutdownTelemetry, withSpan } from "./telemetry.js";
|
|
14
|
+
import { corsHeaders, isLoopbackHost, isOriginAllowed, oauthProtectedResourceMetadataUrl, oauthWwwAuthenticateHeader, validateHttpStartupConfig, } from "./http-security.js";
|
|
15
|
+
import { attachRateLimitHeaders, buildRateLimitHeaders } from "./http-rate-limit.js";
|
|
16
|
+
import { createRemoteControlPlane } from "./remote/control-plane.js";
|
|
17
|
+
import { loadRemoteConfig } from "./remote/config.js";
|
|
18
|
+
import { userSafeError } from "./remote/util.js";
|
|
19
|
+
const endpoint = "/mcp";
|
|
20
|
+
const legacySseEndpoint = "/sse";
|
|
21
|
+
const legacyMessageEndpoint = "/messages";
|
|
22
|
+
const healthEndpoint = "/healthz";
|
|
23
|
+
const oauthProtectedResourceEndpoint = "/.well-known/oauth-protected-resource";
|
|
24
|
+
const container = createContainer();
|
|
25
|
+
const httpConfig = container.config.get("http");
|
|
26
|
+
const authConfig = container.config.get("auth");
|
|
27
|
+
const connectorConfig = container.config.get("connector");
|
|
28
|
+
const policyConfig = container.config.get("policy");
|
|
29
|
+
const remoteConfig = loadRemoteConfig();
|
|
30
|
+
const remoteControlPlanePromise = remoteConfig.enabled ? createRemoteControlPlane() : undefined;
|
|
31
|
+
const sessions = new Map();
|
|
32
|
+
const bearerToken = httpConfig.bearerTokenFile
|
|
33
|
+
? readFileSync(httpConfig.bearerTokenFile, "utf8").trim()
|
|
34
|
+
: undefined;
|
|
35
|
+
initTelemetry({ serviceVersion: SERVER_VERSION });
|
|
36
|
+
class RequestBodyTooLargeError extends Error {
|
|
37
|
+
constructor() {
|
|
38
|
+
super("Request body is too large");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function sendJson(req, res, statusCode, payload, extraHeaders = {}) {
|
|
42
|
+
res.writeHead(statusCode, {
|
|
43
|
+
"Content-Type": "application/json",
|
|
44
|
+
...corsHeaders(req.headers.origin, httpConfig.allowedOrigins),
|
|
45
|
+
...extraHeaders,
|
|
46
|
+
});
|
|
47
|
+
res.end(JSON.stringify(payload, null, 2));
|
|
48
|
+
}
|
|
49
|
+
function configuredPublicMcpUrl() {
|
|
50
|
+
if (!httpConfig.publicUrl) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
const url = new URL(httpConfig.publicUrl);
|
|
54
|
+
if (url.pathname === "" || url.pathname === "/") {
|
|
55
|
+
url.pathname = endpoint;
|
|
56
|
+
}
|
|
57
|
+
else if (!url.pathname.endsWith(endpoint)) {
|
|
58
|
+
url.pathname = `${url.pathname.replace(/\/$/u, "")}${endpoint}`;
|
|
59
|
+
}
|
|
60
|
+
return url.toString();
|
|
61
|
+
}
|
|
62
|
+
function buildPublicMcpUrl(req) {
|
|
63
|
+
const configured = configuredPublicMcpUrl();
|
|
64
|
+
if (configured) {
|
|
65
|
+
return configured;
|
|
66
|
+
}
|
|
67
|
+
const forwardedProto = req.headers["x-forwarded-proto"];
|
|
68
|
+
const rawProtocol = Array.isArray(forwardedProto) ? forwardedProto[0] : forwardedProto;
|
|
69
|
+
const protocol = httpConfig.trustProxy && (rawProtocol === "http" || rawProtocol === "https")
|
|
70
|
+
? rawProtocol
|
|
71
|
+
: isLoopbackHost(httpConfig.host)
|
|
72
|
+
? "http"
|
|
73
|
+
: "https";
|
|
74
|
+
return `${protocol}://${req.headers.host ?? `localhost:${httpConfig.port}`}${endpoint}`;
|
|
75
|
+
}
|
|
76
|
+
function isHttpSessionExpired(session, now = Date.now()) {
|
|
77
|
+
return now - session.lastSeenAt > httpConfig.sessionIdleTtlMs;
|
|
78
|
+
}
|
|
79
|
+
function removeHttpSession(sessionId, reason) {
|
|
80
|
+
if (sessions.delete(sessionId)) {
|
|
81
|
+
logger.info("HTTP MCP session removed", { sessionId, reason });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function closeHttpSession(sessionId, reason) {
|
|
85
|
+
const session = sessions.get(sessionId);
|
|
86
|
+
if (!session) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
removeHttpSession(sessionId, reason);
|
|
90
|
+
void session.transport.close().catch((error) => {
|
|
91
|
+
logger.warn("Failed to close HTTP MCP transport cleanly", { sessionId, error });
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function cleanupExpiredHttpSessions() {
|
|
95
|
+
const now = Date.now();
|
|
96
|
+
for (const [sessionId, session] of sessions) {
|
|
97
|
+
if (isHttpSessionExpired(session, now)) {
|
|
98
|
+
closeHttpSession(sessionId, "idle-timeout");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function getHttpSession(sessionId) {
|
|
103
|
+
if (!sessionId) {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
const session = sessions.get(sessionId);
|
|
107
|
+
if (!session) {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
if (isHttpSessionExpired(session)) {
|
|
111
|
+
closeHttpSession(sessionId, "idle-timeout");
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
session.lastSeenAt = Date.now();
|
|
115
|
+
return session;
|
|
116
|
+
}
|
|
117
|
+
function canOpenHttpSession(req, res) {
|
|
118
|
+
cleanupExpiredHttpSessions();
|
|
119
|
+
if (sessions.size < httpConfig.maxSessions) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
sendJson(req, res, 503, {
|
|
123
|
+
error: "HTTP MCP session limit reached",
|
|
124
|
+
maxSessions: httpConfig.maxSessions,
|
|
125
|
+
});
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
const httpSessionCleanupInterval = setInterval(cleanupExpiredHttpSessions, Math.max(1000, Math.min(httpConfig.sessionIdleTtlMs, 60_000)));
|
|
129
|
+
httpSessionCleanupInterval.unref?.();
|
|
130
|
+
function protectedResourceMetadata(req) {
|
|
131
|
+
return {
|
|
132
|
+
resource: authConfig.oauthResource ?? buildPublicMcpUrl(req),
|
|
133
|
+
resource_name: "ssh-mcp-pro",
|
|
134
|
+
bearer_methods_supported: ["header"],
|
|
135
|
+
scopes_supported: authConfig.oauthRequiredScopes,
|
|
136
|
+
authorization_servers: authConfig.oauthIssuer ? [authConfig.oauthIssuer] : [],
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function attachCurrentRateLimitHeaders(res) {
|
|
140
|
+
attachRateLimitHeaders(res, () => buildRateLimitHeaders(container.rateLimiter, container.config.get("rateLimit")));
|
|
141
|
+
}
|
|
142
|
+
function oauthChallengeHeader(req) {
|
|
143
|
+
return oauthWwwAuthenticateHeader(oauthProtectedResourceMetadataUrl(buildPublicMcpUrl(req)), authConfig.oauthRequiredScopes, req.headers.authorization !== undefined);
|
|
144
|
+
}
|
|
145
|
+
async function rejectIfUnauthorized(req, res) {
|
|
146
|
+
const origin = req.headers.origin;
|
|
147
|
+
if (!isOriginAllowed(origin, httpConfig.allowedOrigins)) {
|
|
148
|
+
sendJson(req, res, 403, { error: "Origin is not allowed" });
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
if (authConfig.mode === "oauth") {
|
|
152
|
+
const verificationConfig = {
|
|
153
|
+
audience: authConfig.oauthAudience ?? authConfig.oauthResource ?? buildPublicMcpUrl(req),
|
|
154
|
+
requiredScopes: authConfig.oauthRequiredScopes,
|
|
155
|
+
};
|
|
156
|
+
if (authConfig.oauthIssuer) {
|
|
157
|
+
verificationConfig.issuer = authConfig.oauthIssuer;
|
|
158
|
+
}
|
|
159
|
+
if (authConfig.oauthJwksUrl) {
|
|
160
|
+
verificationConfig.jwksUrl = authConfig.oauthJwksUrl;
|
|
161
|
+
}
|
|
162
|
+
const valid = await isOAuthAuthorizationValid(req.headers.authorization, verificationConfig);
|
|
163
|
+
if (!valid) {
|
|
164
|
+
sendJson(req, res, 401, { error: "Missing or invalid OAuth bearer token" }, { "WWW-Authenticate": oauthChallengeHeader(req) });
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
if (!bearerToken) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
if (!isBearerAuthorizationValid(req.headers.authorization, bearerToken)) {
|
|
173
|
+
sendJson(req, res, 401, { error: "Missing or invalid bearer token" });
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
async function readJsonBody(req) {
|
|
179
|
+
const chunks = [];
|
|
180
|
+
let size = 0;
|
|
181
|
+
for await (const chunk of req) {
|
|
182
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
183
|
+
size += buffer.byteLength;
|
|
184
|
+
if (size > httpConfig.maxRequestBodyBytes) {
|
|
185
|
+
throw new RequestBodyTooLargeError();
|
|
186
|
+
}
|
|
187
|
+
chunks.push(buffer);
|
|
188
|
+
}
|
|
189
|
+
if (chunks.length === 0) {
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
const raw = Buffer.concat(chunks).toString("utf8");
|
|
193
|
+
return raw ? JSON.parse(raw) : undefined;
|
|
194
|
+
}
|
|
195
|
+
async function handleStreamableRequest(req, res, parsedBody) {
|
|
196
|
+
await withSpan("http.streamable.request", async (span) => {
|
|
197
|
+
const sessionHeader = req.headers["mcp-session-id"];
|
|
198
|
+
const sessionId = Array.isArray(sessionHeader) ? sessionHeader[0] : sessionHeader;
|
|
199
|
+
cleanupExpiredHttpSessions();
|
|
200
|
+
let session = getHttpSession(sessionId);
|
|
201
|
+
span.setAttribute("http.route", endpoint);
|
|
202
|
+
span.setAttribute("http.method", req.method ?? "UNKNOWN");
|
|
203
|
+
if (sessionId) {
|
|
204
|
+
span.setAttribute("mcp.session.id", sessionId);
|
|
205
|
+
}
|
|
206
|
+
if (!session && req.method === "POST" && isInitializeRequest(parsedBody)) {
|
|
207
|
+
if (!canOpenHttpSession(req, res)) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const transport = new StreamableHTTPServerTransport({
|
|
211
|
+
sessionIdGenerator: () => randomUUID(),
|
|
212
|
+
onsessioninitialized: (newSessionId) => {
|
|
213
|
+
sessions.set(newSessionId, { server, transport, lastSeenAt: Date.now() });
|
|
214
|
+
logger.info("Streamable HTTP MCP session initialized", { sessionId: newSessionId });
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
const server = new SSHMCPServer(container);
|
|
218
|
+
transport.onclose = () => {
|
|
219
|
+
const closedSessionId = transport.sessionId;
|
|
220
|
+
if (closedSessionId) {
|
|
221
|
+
removeHttpSession(closedSessionId, "transport-closed");
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
transport.onerror = (error) => {
|
|
225
|
+
logger.error("Streamable HTTP MCP transport error", { error: error.message });
|
|
226
|
+
};
|
|
227
|
+
await server.connect(transport);
|
|
228
|
+
session = { server, transport, lastSeenAt: Date.now() };
|
|
229
|
+
}
|
|
230
|
+
if (!session) {
|
|
231
|
+
sendJson(req, res, 400, {
|
|
232
|
+
jsonrpc: "2.0",
|
|
233
|
+
error: {
|
|
234
|
+
code: -32000,
|
|
235
|
+
message: "Bad Request: initialize with POST /mcp or provide a valid MCP-Session-Id",
|
|
236
|
+
},
|
|
237
|
+
id: null,
|
|
238
|
+
});
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (!(session.transport instanceof StreamableHTTPServerTransport)) {
|
|
242
|
+
sendJson(req, res, 400, {
|
|
243
|
+
error: "Session exists but uses a different transport protocol",
|
|
244
|
+
});
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
await session.transport.handleRequest(req, res, parsedBody);
|
|
248
|
+
}, {
|
|
249
|
+
attributes: {
|
|
250
|
+
"http.route": endpoint,
|
|
251
|
+
"http.method": req.method ?? "UNKNOWN",
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
async function handleLegacySseConnection(req, res) {
|
|
256
|
+
if (!canOpenHttpSession(req, res)) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const transport = new SSEServerTransport(legacyMessageEndpoint, res);
|
|
260
|
+
const sessionId = transport.sessionId;
|
|
261
|
+
const server = new SSHMCPServer(container);
|
|
262
|
+
transport.onclose = () => {
|
|
263
|
+
removeHttpSession(sessionId, "legacy-transport-closed");
|
|
264
|
+
};
|
|
265
|
+
sessions.set(sessionId, { server, transport, lastSeenAt: Date.now() });
|
|
266
|
+
await server.connect(transport);
|
|
267
|
+
logger.warn("Legacy HTTP/SSE MCP session established", { sessionId });
|
|
268
|
+
}
|
|
269
|
+
async function handleLegacyMessage(req, res) {
|
|
270
|
+
const baseUrl = `http://${req.headers.host ?? "localhost"}`;
|
|
271
|
+
const requestUrl = new URL(req.url ?? legacyMessageEndpoint, baseUrl);
|
|
272
|
+
const sessionId = requestUrl.searchParams.get("sessionId");
|
|
273
|
+
if (!sessionId) {
|
|
274
|
+
sendJson(req, res, 400, { error: "Missing sessionId query parameter" });
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const session = getHttpSession(sessionId);
|
|
278
|
+
if (!session || !(session.transport instanceof SSEServerTransport)) {
|
|
279
|
+
sendJson(req, res, 404, { error: "Legacy SSE session not found" });
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
await session.transport.handlePostMessage(req, res);
|
|
283
|
+
}
|
|
284
|
+
if (!remoteConfig.enabled) {
|
|
285
|
+
validateHttpStartupConfig(httpConfig, bearerToken, {
|
|
286
|
+
toolProfile: connectorConfig.toolProfile,
|
|
287
|
+
allowedHosts: policyConfig.allowedHosts,
|
|
288
|
+
hostKeyPolicy: container.config.get("security").hostKeyPolicy,
|
|
289
|
+
authMode: authConfig.mode,
|
|
290
|
+
oauthConfigured: Boolean(authConfig.oauthIssuer && authConfig.oauthJwksUrl),
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
const httpServer = createServer((req, res) => {
|
|
294
|
+
void (async () => {
|
|
295
|
+
try {
|
|
296
|
+
const requestUrl = new URL(req.url ?? endpoint, "http://localhost");
|
|
297
|
+
attachCurrentRateLimitHeaders(res);
|
|
298
|
+
if (remoteControlPlanePromise) {
|
|
299
|
+
const remoteControlPlane = await remoteControlPlanePromise;
|
|
300
|
+
const handled = await remoteControlPlane.handleHttp(req, res, requestUrl.pathname);
|
|
301
|
+
if (handled) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (requestUrl.pathname === oauthProtectedResourceEndpoint && req.method === "GET") {
|
|
306
|
+
sendJson(req, res, 200, protectedResourceMetadata(req));
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (requestUrl.pathname === healthEndpoint && req.method === "GET") {
|
|
310
|
+
sendJson(req, res, 200, {
|
|
311
|
+
ok: true,
|
|
312
|
+
service: "ssh-mcp-pro",
|
|
313
|
+
transport: "streamable-http",
|
|
314
|
+
});
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
if (requestUrl.pathname === endpoint && req.method === "OPTIONS") {
|
|
318
|
+
if (!isOriginAllowed(req.headers.origin, httpConfig.allowedOrigins)) {
|
|
319
|
+
sendJson(req, res, 403, { error: "Origin is not allowed" });
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
res.writeHead(204, corsHeaders(req.headers.origin, httpConfig.allowedOrigins));
|
|
323
|
+
res.end();
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (await rejectIfUnauthorized(req, res)) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
if (requestUrl.pathname === endpoint) {
|
|
330
|
+
if (req.method !== "GET" && req.method !== "POST" && req.method !== "DELETE") {
|
|
331
|
+
sendJson(req, res, 405, { error: "Method not allowed" });
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
const parsedBody = req.method === "POST" ? await readJsonBody(req) : undefined;
|
|
335
|
+
await handleStreamableRequest(req, res, parsedBody);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (httpConfig.enableLegacySse && requestUrl.pathname === legacySseEndpoint) {
|
|
339
|
+
if (req.method !== "GET") {
|
|
340
|
+
sendJson(req, res, 405, { error: "Method not allowed" });
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
await handleLegacySseConnection(req, res);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
if (httpConfig.enableLegacySse && requestUrl.pathname === legacyMessageEndpoint) {
|
|
347
|
+
if (req.method !== "POST") {
|
|
348
|
+
sendJson(req, res, 405, { error: "Method not allowed" });
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
await handleLegacyMessage(req, res);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
sendJson(req, res, 404, { error: "Not found" });
|
|
355
|
+
}
|
|
356
|
+
catch (error) {
|
|
357
|
+
logger.error("HTTP MCP request failed", {
|
|
358
|
+
error: userSafeError(error),
|
|
359
|
+
});
|
|
360
|
+
if (!res.headersSent) {
|
|
361
|
+
if (error && typeof error === "object" && "status" in error && "message" in error) {
|
|
362
|
+
const status = Number(error.status);
|
|
363
|
+
const message = String(error.message);
|
|
364
|
+
const code = "code" in error ? String(error.code) : undefined;
|
|
365
|
+
sendJson(req, res, Number.isFinite(status) ? status : 500, { error: message, code });
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
const statusCode = error instanceof RequestBodyTooLargeError ? 413 : 500;
|
|
369
|
+
const message = error instanceof RequestBodyTooLargeError
|
|
370
|
+
? "Request body is too large"
|
|
371
|
+
: "Internal server error";
|
|
372
|
+
sendJson(req, res, statusCode, { error: message });
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
})();
|
|
377
|
+
});
|
|
378
|
+
httpServer.on("upgrade", (req, socket, head) => {
|
|
379
|
+
void (async () => {
|
|
380
|
+
try {
|
|
381
|
+
const requestUrl = new URL(req.url ?? "/", "http://localhost");
|
|
382
|
+
if (remoteControlPlanePromise) {
|
|
383
|
+
const remoteControlPlane = await remoteControlPlanePromise;
|
|
384
|
+
if (remoteControlPlane.handleUpgrade(req, socket, head, requestUrl.pathname)) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
socket.destroy();
|
|
389
|
+
}
|
|
390
|
+
catch {
|
|
391
|
+
socket.destroy();
|
|
392
|
+
}
|
|
393
|
+
})();
|
|
394
|
+
});
|
|
395
|
+
let shuttingDown = false;
|
|
396
|
+
async function shutdown(signal) {
|
|
397
|
+
if (shuttingDown) {
|
|
398
|
+
process.exit(0);
|
|
399
|
+
}
|
|
400
|
+
shuttingDown = true;
|
|
401
|
+
logger.info(`Received ${signal}, shutting down HTTP MCP server...`);
|
|
402
|
+
httpServer.close();
|
|
403
|
+
clearInterval(httpSessionCleanupInterval);
|
|
404
|
+
await Promise.all(Array.from(sessions.entries()).map(async ([sessionId, session]) => {
|
|
405
|
+
try {
|
|
406
|
+
await session.transport.close();
|
|
407
|
+
}
|
|
408
|
+
catch (error) {
|
|
409
|
+
logger.warn("Failed to close HTTP MCP transport cleanly", { sessionId, error });
|
|
410
|
+
}
|
|
411
|
+
}));
|
|
412
|
+
sessions.clear();
|
|
413
|
+
container.rateLimiter.destroy();
|
|
414
|
+
await container.sessionManager.destroy();
|
|
415
|
+
if (remoteControlPlanePromise) {
|
|
416
|
+
const remoteControlPlane = await remoteControlPlanePromise;
|
|
417
|
+
remoteControlPlane.close();
|
|
418
|
+
}
|
|
419
|
+
await shutdownTelemetry();
|
|
420
|
+
process.exit(0);
|
|
421
|
+
}
|
|
422
|
+
httpServer.listen(httpConfig.port, httpConfig.host, () => {
|
|
423
|
+
logger.info("Streamable HTTP MCP server listening", {
|
|
424
|
+
host: httpConfig.host,
|
|
425
|
+
port: httpConfig.port,
|
|
426
|
+
endpoint,
|
|
427
|
+
legacySse: httpConfig.enableLegacySse,
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
process.on("SIGINT", () => void shutdown("SIGINT"));
|
|
431
|
+
process.on("SIGTERM", () => void shutdown("SIGTERM"));
|
|
432
|
+
//# sourceMappingURL=server-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-http.js","sourceRoot":"","sources":["../src/server-http.ts"],"names":[],"mappings":"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"}
|