mcp-server-kubernetes 3.1.1 → 3.2.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/dist/utils/auth.d.ts +19 -0
- package/dist/utils/auth.js +53 -0
- package/dist/utils/sse.js +10 -4
- package/dist/utils/streamable-http.js +9 -3
- package/package.json +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
/**
|
|
3
|
+
* Authentication middleware for MCP HTTP transports.
|
|
4
|
+
*
|
|
5
|
+
* When the MCP_AUTH_TOKEN environment variable is set, this middleware
|
|
6
|
+
* requires all requests to include a matching X-MCP-AUTH header.
|
|
7
|
+
*
|
|
8
|
+
* This provides a simple authentication mechanism for securing MCP endpoints
|
|
9
|
+
* in cluster environments where full OAuth may be overkill.
|
|
10
|
+
*
|
|
11
|
+
* Example usage:
|
|
12
|
+
* Server: MCP_AUTH_TOKEN=my-secret-token
|
|
13
|
+
* Client: X-MCP-AUTH: my-secret-token
|
|
14
|
+
*/
|
|
15
|
+
export declare function createAuthMiddleware(): (req: Request, res: Response, next: NextFunction) => void;
|
|
16
|
+
/**
|
|
17
|
+
* Returns whether authentication is enabled (MCP_AUTH_TOKEN is set)
|
|
18
|
+
*/
|
|
19
|
+
export declare function isAuthEnabled(): boolean;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication middleware for MCP HTTP transports.
|
|
3
|
+
*
|
|
4
|
+
* When the MCP_AUTH_TOKEN environment variable is set, this middleware
|
|
5
|
+
* requires all requests to include a matching X-MCP-AUTH header.
|
|
6
|
+
*
|
|
7
|
+
* This provides a simple authentication mechanism for securing MCP endpoints
|
|
8
|
+
* in cluster environments where full OAuth may be overkill.
|
|
9
|
+
*
|
|
10
|
+
* Example usage:
|
|
11
|
+
* Server: MCP_AUTH_TOKEN=my-secret-token
|
|
12
|
+
* Client: X-MCP-AUTH: my-secret-token
|
|
13
|
+
*/
|
|
14
|
+
export function createAuthMiddleware() {
|
|
15
|
+
const authToken = process.env.MCP_AUTH_TOKEN;
|
|
16
|
+
return (req, res, next) => {
|
|
17
|
+
// If no auth token is configured, allow all requests
|
|
18
|
+
if (!authToken) {
|
|
19
|
+
next();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const providedToken = req.headers["x-mcp-auth"];
|
|
23
|
+
if (!providedToken) {
|
|
24
|
+
res.status(401).json({
|
|
25
|
+
jsonrpc: "2.0",
|
|
26
|
+
error: {
|
|
27
|
+
code: -32001,
|
|
28
|
+
message: "Unauthorized: X-MCP-AUTH header is required",
|
|
29
|
+
},
|
|
30
|
+
id: null,
|
|
31
|
+
});
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (providedToken !== authToken) {
|
|
35
|
+
res.status(403).json({
|
|
36
|
+
jsonrpc: "2.0",
|
|
37
|
+
error: {
|
|
38
|
+
code: -32002,
|
|
39
|
+
message: "Forbidden: Invalid authentication token",
|
|
40
|
+
},
|
|
41
|
+
id: null,
|
|
42
|
+
});
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
next();
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Returns whether authentication is enabled (MCP_AUTH_TOKEN is set)
|
|
50
|
+
*/
|
|
51
|
+
export function isAuthEnabled() {
|
|
52
|
+
return !!process.env.MCP_AUTH_TOKEN;
|
|
53
|
+
}
|
package/dist/utils/sse.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import express from "express";
|
|
2
2
|
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
3
|
+
import { createAuthMiddleware, isAuthEnabled } from "./auth.js";
|
|
3
4
|
export function startSSEServer(server) {
|
|
4
5
|
const app = express();
|
|
6
|
+
// Create auth middleware - when MCP_AUTH_TOKEN is set, requires X-MCP-AUTH header
|
|
7
|
+
const authMiddleware = createAuthMiddleware();
|
|
5
8
|
// Currently just copying from docs & allowing for multiple transport connections: https://modelcontextprotocol.io/docs/concepts/transports#server-sent-events-sse
|
|
6
|
-
//
|
|
9
|
+
// Note: When MCP_AUTH_TOKEN is set, requests require X-MCP-AUTH header for authentication
|
|
7
10
|
let transports = [];
|
|
8
|
-
app.get("/sse", async (req, res) => {
|
|
11
|
+
app.get("/sse", authMiddleware, async (req, res) => {
|
|
9
12
|
const transport = new SSEServerTransport("/messages", res);
|
|
10
13
|
transports.push(transport);
|
|
11
14
|
await server.connect(transport);
|
|
12
15
|
});
|
|
13
|
-
app.post("/messages", (req, res) => {
|
|
16
|
+
app.post("/messages", authMiddleware, (req, res) => {
|
|
14
17
|
const transport = transports.find((t) => t.sessionId === req.query.sessionId);
|
|
15
18
|
if (transport) {
|
|
16
19
|
transport.handlePostMessage(req, res);
|
|
@@ -51,6 +54,9 @@ export function startSSEServer(server) {
|
|
|
51
54
|
}
|
|
52
55
|
const host = process.env.HOST || "localhost";
|
|
53
56
|
app.listen(port, host, () => {
|
|
54
|
-
console.log(`mcp-kubernetes-server is listening on port ${port}\nUse the following url to connect to the server:\
|
|
57
|
+
console.log(`mcp-kubernetes-server is listening on port ${port}\nUse the following url to connect to the server:\nhttp://${host}:${port}/sse`);
|
|
58
|
+
if (isAuthEnabled()) {
|
|
59
|
+
console.log("Authentication enabled: X-MCP-AUTH header required for all MCP requests");
|
|
60
|
+
}
|
|
55
61
|
});
|
|
56
62
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import express from "express";
|
|
2
2
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
3
|
+
import { createAuthMiddleware, isAuthEnabled } from "./auth.js";
|
|
3
4
|
export function startStreamableHTTPServer(server) {
|
|
4
5
|
const app = express();
|
|
5
6
|
app.use(express.json());
|
|
6
|
-
|
|
7
|
+
// Create auth middleware - when MCP_AUTH_TOKEN is set, requires X-MCP-AUTH header
|
|
8
|
+
const authMiddleware = createAuthMiddleware();
|
|
9
|
+
app.post("/mcp", authMiddleware, async (req, res) => {
|
|
7
10
|
// In stateless mode, create a new instance of transport and server for each request
|
|
8
11
|
// to ensure complete isolation. A single instance would cause request ID collisions
|
|
9
12
|
// when multiple clients connect concurrently.
|
|
@@ -44,7 +47,7 @@ export function startStreamableHTTPServer(server) {
|
|
|
44
47
|
}
|
|
45
48
|
});
|
|
46
49
|
// SSE notifications not supported in stateless mode
|
|
47
|
-
app.get("/mcp", async (req, res) => {
|
|
50
|
+
app.get("/mcp", authMiddleware, async (req, res) => {
|
|
48
51
|
console.log("Received GET MCP request");
|
|
49
52
|
res.writeHead(405).end(JSON.stringify({
|
|
50
53
|
jsonrpc: "2.0",
|
|
@@ -56,7 +59,7 @@ export function startStreamableHTTPServer(server) {
|
|
|
56
59
|
}));
|
|
57
60
|
});
|
|
58
61
|
// Session termination not needed in stateless mode
|
|
59
|
-
app.delete("/mcp", async (req, res) => {
|
|
62
|
+
app.delete("/mcp", authMiddleware, async (req, res) => {
|
|
60
63
|
console.log("Received DELETE MCP request");
|
|
61
64
|
res.writeHead(405).end(JSON.stringify({
|
|
62
65
|
jsonrpc: "2.0",
|
|
@@ -98,6 +101,9 @@ export function startStreamableHTTPServer(server) {
|
|
|
98
101
|
const host = process.env.HOST || "localhost";
|
|
99
102
|
const httpServer = app.listen(port, host, () => {
|
|
100
103
|
console.log(`mcp-kubernetes-server is listening on port ${port}\nUse the following url to connect to the server:\nhttp://${host}:${port}/mcp`);
|
|
104
|
+
if (isAuthEnabled()) {
|
|
105
|
+
console.log("Authentication enabled: X-MCP-AUTH header required for all MCP requests");
|
|
106
|
+
}
|
|
101
107
|
});
|
|
102
108
|
return httpServer;
|
|
103
109
|
}
|