@mcp-abap-adt/core 4.5.2 → 4.6.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.
@@ -0,0 +1,771 @@
1
+ # HTTPS Server Support Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Add TLS/HTTPS support to MCP server transports (HTTP and SSE) so clients can connect securely with a provided certificate.
6
+
7
+ **Architecture:** Protocol is determined automatically by the presence of `tls.cert` + `tls.key` options. TLS config is per-transport (http/sse sections) to allow mixed setups. In standalone mode, `https.createServer(tlsOpts, app)` replaces `app.listen()`. Embedded mode ignores TLS (external app's responsibility).
8
+
9
+ **Tech Stack:** Node.js `node:https`, `node:fs`, Express 5, existing YAML config + CLI argument infrastructure.
10
+
11
+ ---
12
+
13
+ ## File Map
14
+
15
+ | File | Action | Responsibility |
16
+ |------|--------|---------------|
17
+ | `src/lib/config/IServerConfig.ts` | Modify | Add `TlsConfig` interface and tls fields |
18
+ | `src/lib/config/ArgumentsParser.ts` | Modify | Parse `--tls-cert`, `--tls-key`, `--tls-ca` CLI args + env vars |
19
+ | `src/lib/config/yamlConfig.ts` | Modify | Add `tls` section to `YamlConfig`, validation, template, apply-to-args |
20
+ | `src/lib/config/ServerConfigManager.ts` | Modify | Wire TLS fields from parsed args to `IServerConfig` |
21
+ | `src/server/tlsUtils.ts` | Create | `createServerListener()` helper — shared by both transports |
22
+ | `src/server/StreamableHttpServer.ts` | Modify | Use `createServerListener()` in `start()`, update log protocol |
23
+ | `src/server/SseServer.ts` | Modify | Use `createServerListener()` in `start()`, update log protocol |
24
+ | `src/server/launcher.ts` | Modify | Pass TLS config to server constructors, update help text |
25
+ | `src/__tests__/unit/tlsServer.test.ts` | Create | Unit tests for TLS server creation |
26
+
27
+ ---
28
+
29
+ ### Task 1: Add TlsConfig to IServerConfig
30
+
31
+ **Files:**
32
+ - Modify: `src/lib/config/IServerConfig.ts`
33
+
34
+ - [ ] **Step 1: Add TlsConfig interface and fields**
35
+
36
+ In `src/lib/config/IServerConfig.ts`, add:
37
+
38
+ ```typescript
39
+ /** TLS configuration for HTTPS server */
40
+ export interface TlsConfig {
41
+ /** Path to TLS certificate file (PEM) */
42
+ cert: string;
43
+ /** Path to TLS private key file (PEM) */
44
+ key: string;
45
+ /** Path to CA certificate file (PEM), optional */
46
+ ca?: string;
47
+ }
48
+ ```
49
+
50
+ Add to `IServerConfig` in the `HTTP/SSE SPECIFIC` section:
51
+
52
+ ```typescript
53
+ /** TLS configuration for HTTPS (cert + key enables HTTPS automatically) */
54
+ tls?: TlsConfig;
55
+ ```
56
+
57
+ - [ ] **Step 2: Commit**
58
+
59
+ ```bash
60
+ git add src/lib/config/IServerConfig.ts
61
+ git commit -m "feat: add TlsConfig interface to IServerConfig"
62
+ ```
63
+
64
+ ---
65
+
66
+ ### Task 2: Parse TLS CLI arguments
67
+
68
+ **Files:**
69
+ - Modify: `src/lib/config/ArgumentsParser.ts`
70
+
71
+ - [ ] **Step 1: Add TLS fields to ParsedArguments**
72
+
73
+ Add to `ParsedArguments` interface:
74
+
75
+ ```typescript
76
+ /** TLS certificate file path */
77
+ tlsCert?: string;
78
+ /** TLS private key file path */
79
+ tlsKey?: string;
80
+ /** TLS CA certificate file path */
81
+ tlsCa?: string;
82
+ ```
83
+
84
+ - [ ] **Step 2: Add TLS parsing logic**
85
+
86
+ In `ArgumentsParser.parse()`, after the SSE options block (after line ~257), add:
87
+
88
+ ```typescript
89
+ // Parse TLS options
90
+ result.tlsCert = getArgValue('--tls-cert') || process.env.MCP_TLS_CERT;
91
+ result.tlsKey = getArgValue('--tls-key') || process.env.MCP_TLS_KEY;
92
+ result.tlsCa = getArgValue('--tls-ca') || process.env.MCP_TLS_CA;
93
+ ```
94
+
95
+ - [ ] **Step 3: Commit**
96
+
97
+ ```bash
98
+ git add src/lib/config/ArgumentsParser.ts
99
+ git commit -m "feat: parse --tls-cert, --tls-key, --tls-ca CLI args"
100
+ ```
101
+
102
+ ---
103
+
104
+ ### Task 3: Add TLS to YAML config
105
+
106
+ **Files:**
107
+ - Modify: `src/lib/config/yamlConfig.ts`
108
+
109
+ - [ ] **Step 1: Add tls to YamlConfig interface**
110
+
111
+ Add `tls` section inside both `http` and `sse` objects in `YamlConfig`:
112
+
113
+ ```typescript
114
+ export interface YamlConfig {
115
+ // ... existing fields ...
116
+ http?: {
117
+ // ... existing fields ...
118
+ tls?: {
119
+ cert?: string;
120
+ key?: string;
121
+ ca?: string;
122
+ };
123
+ };
124
+ sse?: {
125
+ // ... existing fields ...
126
+ tls?: {
127
+ cert?: string;
128
+ key?: string;
129
+ ca?: string;
130
+ };
131
+ };
132
+ }
133
+ ```
134
+
135
+ - [ ] **Step 2: Add TLS validation to validateYamlConfig**
136
+
137
+ After existing SSE validation (before the `return` statement), add:
138
+
139
+ ```typescript
140
+ // Validate TLS configuration (http)
141
+ if (config.http?.tls) {
142
+ const tls = config.http.tls;
143
+ if (tls.cert && !tls.key) {
144
+ errors.push('HTTP TLS: cert requires key to be specified');
145
+ }
146
+ if (tls.key && !tls.cert) {
147
+ errors.push('HTTP TLS: key requires cert to be specified');
148
+ }
149
+ }
150
+
151
+ // Validate TLS configuration (sse)
152
+ if (config.sse?.tls) {
153
+ const tls = config.sse.tls;
154
+ if (tls.cert && !tls.key) {
155
+ errors.push('SSE TLS: cert requires key to be specified');
156
+ }
157
+ if (tls.key && !tls.cert) {
158
+ errors.push('SSE TLS: key requires cert to be specified');
159
+ }
160
+ }
161
+ ```
162
+
163
+ - [ ] **Step 3: Add TLS to applyYamlConfigToArgs**
164
+
165
+ Inside the `// Apply HTTP options` block, add:
166
+
167
+ ```typescript
168
+ if (config.http.tls?.cert && !hasArg('--tls-cert')) {
169
+ addArg('--tls-cert', config.http.tls.cert);
170
+ }
171
+ if (config.http.tls?.key && !hasArg('--tls-key')) {
172
+ addArg('--tls-key', config.http.tls.key);
173
+ }
174
+ if (config.http.tls?.ca && !hasArg('--tls-ca')) {
175
+ addArg('--tls-ca', config.http.tls.ca);
176
+ }
177
+ ```
178
+
179
+ Also inside the `// Apply SSE options` block, add the same (SSE YAML tls applies to same CLI args — both transports share the same tls cert/key/ca since only one transport runs at a time):
180
+
181
+ ```typescript
182
+ if (config.sse.tls?.cert && !hasArg('--tls-cert')) {
183
+ addArg('--tls-cert', config.sse.tls.cert);
184
+ }
185
+ if (config.sse.tls?.key && !hasArg('--tls-key')) {
186
+ addArg('--tls-key', config.sse.tls.key);
187
+ }
188
+ if (config.sse.tls?.ca && !hasArg('--tls-ca')) {
189
+ addArg('--tls-ca', config.sse.tls.ca);
190
+ }
191
+ ```
192
+
193
+ - [ ] **Step 4: Add TLS to YAML template**
194
+
195
+ In `generateYamlConfigTemplate()`, add to both `http:` and `sse:` sections:
196
+
197
+ ```yaml
198
+ # TLS configuration for HTTPS (both cert and key required)
199
+ # When configured, server starts in HTTPS mode automatically
200
+ # Note: only the active transport's TLS config is used
201
+ # tls:
202
+ # cert: /path/to/server.crt
203
+ # key: /path/to/server.key
204
+ # ca: /path/to/ca.crt # optional, for custom CA
205
+ ```
206
+
207
+ - [ ] **Step 5: Commit**
208
+
209
+ ```bash
210
+ git add src/lib/config/yamlConfig.ts
211
+ git commit -m "feat: add TLS section to YAML config with validation"
212
+ ```
213
+
214
+ ---
215
+
216
+ ### Task 4: Wire TLS config through ServerConfigManager
217
+
218
+ **Files:**
219
+ - Modify: `src/lib/config/ServerConfigManager.ts`
220
+
221
+ - [ ] **Step 1: Add TLS to parseCommandLine**
222
+
223
+ In `parseCommandLine()`, after the existing fields in the return object, add:
224
+
225
+ ```typescript
226
+ tls:
227
+ parsed.tlsCert && parsed.tlsKey
228
+ ? {
229
+ cert: parsed.tlsCert,
230
+ key: parsed.tlsKey,
231
+ ca: parsed.tlsCa,
232
+ }
233
+ : undefined,
234
+ ```
235
+
236
+ - [ ] **Step 2: Add TLS to help text**
237
+
238
+ In `generateHelp()`, add a TLS section to the OPTIONS area. In the help string, after `HTTP OPTIONS:` section, add:
239
+
240
+ ```
241
+ TLS/HTTPS:
242
+ --tls-cert=<path> Path to TLS certificate file (PEM)
243
+ --tls-key=<path> Path to TLS private key file (PEM)
244
+ --tls-ca=<path> Path to CA certificate file (PEM, optional)
245
+ When cert and key are provided, server starts in HTTPS mode
246
+ ```
247
+
248
+ - [ ] **Step 3: Commit**
249
+
250
+ ```bash
251
+ git add src/lib/config/ServerConfigManager.ts
252
+ git commit -m "feat: wire TLS config from parsed args to IServerConfig"
253
+ ```
254
+
255
+ ---
256
+
257
+ ### Task 5: Create TLS server helper
258
+
259
+ **Files:**
260
+ - Create: `src/server/tlsUtils.ts`
261
+
262
+ - [ ] **Step 1: Write the failing test**
263
+
264
+ Create `src/__tests__/unit/tlsServer.test.ts`:
265
+
266
+ ```typescript
267
+ import * as fs from 'node:fs';
268
+ import * as https from 'node:https';
269
+ import type { AddressInfo } from 'node:net';
270
+ import express from 'express';
271
+ import { createSelfSignedCert } from './helpers/selfSignedCert';
272
+ import { createServerListener, getProtocol } from '../../server/tlsUtils';
273
+
274
+ let certDir: string;
275
+ let certPath: string;
276
+ let keyPath: string;
277
+
278
+ beforeAll(() => {
279
+ const { cert, key, dir } = createSelfSignedCert();
280
+ certDir = dir;
281
+ certPath = cert;
282
+ keyPath = key;
283
+ });
284
+
285
+ afterAll(() => {
286
+ fs.rmSync(certDir, { recursive: true, force: true });
287
+ });
288
+
289
+ describe('createServerListener', () => {
290
+ it('creates HTTPS server when tls config is provided', async () => {
291
+ const app = express();
292
+ app.get('/test', (_req, res) => res.json({ ok: true }));
293
+
294
+ const server = createServerListener(app, {
295
+ cert: certPath,
296
+ key: keyPath,
297
+ });
298
+
299
+ await new Promise<void>((resolve) => {
300
+ server.listen(0, '127.0.0.1', () => resolve());
301
+ });
302
+
303
+ const { port } = server.address() as AddressInfo;
304
+
305
+ // Use node:https to make request with rejectUnauthorized: false
306
+ const body = await new Promise<string>((resolve, reject) => {
307
+ https.get(
308
+ `https://127.0.0.1:${port}/test`,
309
+ { rejectUnauthorized: false },
310
+ (res) => {
311
+ let data = '';
312
+ res.on('data', (chunk) => (data += chunk));
313
+ res.on('end', () => resolve(data));
314
+ },
315
+ ).on('error', reject);
316
+ });
317
+
318
+ expect(JSON.parse(body)).toEqual({ ok: true });
319
+
320
+ await new Promise<void>((resolve) => server.close(() => resolve()));
321
+ });
322
+
323
+ it('creates HTTP server when no tls config is provided', async () => {
324
+ const app = express();
325
+ app.get('/test', (_req, res) => res.json({ ok: true }));
326
+
327
+ const server = createServerListener(app);
328
+
329
+ await new Promise<void>((resolve) => {
330
+ server.listen(0, '127.0.0.1', () => resolve());
331
+ });
332
+
333
+ const { port } = server.address() as AddressInfo;
334
+ const res = await fetch(`http://127.0.0.1:${port}/test`);
335
+ expect(res.status).toBe(200);
336
+
337
+ const json = await res.json();
338
+ expect(json.ok).toBe(true);
339
+
340
+ await new Promise<void>((resolve) => server.close(() => resolve()));
341
+ });
342
+
343
+ it('throws when cert file does not exist', () => {
344
+ const app = express();
345
+ expect(() =>
346
+ createServerListener(app, {
347
+ cert: '/nonexistent/cert.pem',
348
+ key: keyPath,
349
+ }),
350
+ ).toThrow(/cert/i);
351
+ });
352
+
353
+ it('throws when key file does not exist', () => {
354
+ const app = express();
355
+ expect(() =>
356
+ createServerListener(app, {
357
+ cert: certPath,
358
+ key: '/nonexistent/key.pem',
359
+ }),
360
+ ).toThrow(/key/i);
361
+ });
362
+ });
363
+
364
+ describe('getProtocol', () => {
365
+ it('returns https when tls config provided', () => {
366
+ expect(getProtocol({ cert: 'a', key: 'b' })).toBe('https');
367
+ });
368
+
369
+ it('returns http when no tls config', () => {
370
+ expect(getProtocol()).toBe('http');
371
+ expect(getProtocol(undefined)).toBe('http');
372
+ });
373
+ });
374
+ ```
375
+
376
+ Create `src/__tests__/unit/helpers/selfSignedCert.ts`:
377
+
378
+ ```typescript
379
+ import { execSync } from 'node:child_process';
380
+ import * as fs from 'node:fs';
381
+ import * as os from 'node:os';
382
+ import * as path from 'node:path';
383
+
384
+ /**
385
+ * Generate a self-signed certificate for testing purposes.
386
+ * Uses openssl CLI (available on Linux/macOS).
387
+ */
388
+ export function createSelfSignedCert(): {
389
+ cert: string;
390
+ key: string;
391
+ dir: string;
392
+ } {
393
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'mcp-tls-test-'));
394
+ const certPath = path.join(dir, 'server.crt');
395
+ const keyPath = path.join(dir, 'server.key');
396
+
397
+ execSync(
398
+ `openssl req -x509 -newkey rsa:2048 -keyout "${keyPath}" -out "${certPath}" -days 1 -nodes -subj "/CN=localhost"`,
399
+ { stdio: 'pipe' },
400
+ );
401
+
402
+ return { cert: certPath, key: keyPath, dir };
403
+ }
404
+ ```
405
+
406
+ - [ ] **Step 2: Run test to verify it fails**
407
+
408
+ Run: `npx jest src/__tests__/unit/tlsServer.test.ts --no-coverage`
409
+ Expected: FAIL — `createServerListener` module not found
410
+
411
+ - [ ] **Step 3: Implement createServerListener**
412
+
413
+ Create `src/server/tlsUtils.ts`:
414
+
415
+ ```typescript
416
+ import * as fs from 'node:fs';
417
+ import * as http from 'node:http';
418
+ import * as https from 'node:https';
419
+ import type { TlsConfig } from '../lib/config/IServerConfig.js';
420
+
421
+ /**
422
+ * Create HTTP or HTTPS server based on TLS configuration.
423
+ *
424
+ * When `tls` is provided with cert + key paths, creates an HTTPS server.
425
+ * Otherwise creates a plain HTTP server.
426
+ *
427
+ * @param app - Express application (or any http.RequestListener)
428
+ * @param tls - Optional TLS configuration with file paths
429
+ * @returns http.Server or https.Server
430
+ */
431
+ export function createServerListener(
432
+ app: http.RequestListener,
433
+ tls?: TlsConfig,
434
+ ): http.Server | https.Server {
435
+ if (!tls) {
436
+ return http.createServer(app);
437
+ }
438
+
439
+ if (!fs.existsSync(tls.cert)) {
440
+ throw new Error(`TLS cert file not found: ${tls.cert}`);
441
+ }
442
+ if (!fs.existsSync(tls.key)) {
443
+ throw new Error(`TLS key file not found: ${tls.key}`);
444
+ }
445
+ if (tls.ca && !fs.existsSync(tls.ca)) {
446
+ throw new Error(`TLS CA file not found: ${tls.ca}`);
447
+ }
448
+
449
+ const tlsOptions: https.ServerOptions = {
450
+ cert: fs.readFileSync(tls.cert),
451
+ key: fs.readFileSync(tls.key),
452
+ ...(tls.ca && { ca: fs.readFileSync(tls.ca) }),
453
+ };
454
+
455
+ return https.createServer(tlsOptions, app);
456
+ }
457
+
458
+ /**
459
+ * Returns the protocol string based on TLS configuration.
460
+ */
461
+ export function getProtocol(tls?: TlsConfig): 'https' | 'http' {
462
+ return tls ? 'https' : 'http';
463
+ }
464
+ ```
465
+
466
+ - [ ] **Step 4: Run test to verify it passes**
467
+
468
+ Run: `npx jest src/__tests__/unit/tlsServer.test.ts --no-coverage`
469
+ Expected: PASS
470
+
471
+ - [ ] **Step 5: Commit**
472
+
473
+ ```bash
474
+ git add src/server/tlsUtils.ts src/__tests__/unit/tlsServer.test.ts src/__tests__/unit/helpers/selfSignedCert.ts
475
+ git commit -m "feat: add createServerListener TLS helper with tests"
476
+ ```
477
+
478
+ ---
479
+
480
+ ### Task 6: Integrate TLS into StreamableHttpServer
481
+
482
+ **Files:**
483
+ - Modify: `src/server/StreamableHttpServer.ts`
484
+
485
+ - [ ] **Step 1: Add TLS to options and constructor**
486
+
487
+ Add/update imports at the top:
488
+
489
+ ```typescript
490
+ import type { Server as HttpServer } from 'node:http';
491
+ import type { Server as HttpsServer } from 'node:https';
492
+ import type { TlsConfig } from '../lib/config/IServerConfig.js';
493
+ import { createServerListener, getProtocol } from './tlsUtils.js';
494
+ ```
495
+
496
+ Add to `StreamableHttpServerOptions`:
497
+
498
+ ```typescript
499
+ /**
500
+ * TLS configuration for HTTPS mode
501
+ * When cert + key are provided, server starts in HTTPS mode
502
+ */
503
+ tls?: TlsConfig;
504
+ ```
505
+
506
+ Update `standaloneServer` type in the class (line 74):
507
+
508
+ ```typescript
509
+ private standaloneServer?: HttpServer | HttpsServer;
510
+ ```
511
+
512
+ Add field to the class and set it in constructor:
513
+
514
+ ```typescript
515
+ private readonly tls?: TlsConfig;
516
+ // In constructor:
517
+ this.tls = opts?.tls;
518
+ ```
519
+
520
+ - [ ] **Step 2: Update start() method**
521
+
522
+ Replace in `start()`:
523
+
524
+ ```typescript
525
+ // OLD:
526
+ const server = app.listen(this.port, this.host);
527
+ this.standaloneServer = server;
528
+
529
+ server.once('listening', () => {
530
+ console.error(
531
+ `[StreamableHttpServer] Server started on ${this.host}:${this.port}`,
532
+ );
533
+ console.error(
534
+ `[StreamableHttpServer] Endpoint: http://${this.host}:${this.port}${this.path}`,
535
+ );
536
+ resolve();
537
+ });
538
+ ```
539
+
540
+ With:
541
+
542
+ ```typescript
543
+ const protocol = getProtocol(this.tls);
544
+ const server = createServerListener(app as any, this.tls);
545
+ this.standaloneServer = server;
546
+
547
+ server.listen(this.port, this.host);
548
+ server.once('listening', () => {
549
+ console.error(
550
+ `[StreamableHttpServer] Server started on ${this.host}:${this.port}`,
551
+ );
552
+ console.error(
553
+ `[StreamableHttpServer] Endpoint: ${protocol}://${this.host}:${this.port}${this.path}`,
554
+ );
555
+ resolve();
556
+ });
557
+ ```
558
+
559
+ - [ ] **Step 3: Commit**
560
+
561
+ ```bash
562
+ git add src/server/StreamableHttpServer.ts
563
+ git commit -m "feat: integrate TLS into StreamableHttpServer"
564
+ ```
565
+
566
+ ---
567
+
568
+ ### Task 7: Integrate TLS into SseServer
569
+
570
+ **Files:**
571
+ - Modify: `src/server/SseServer.ts`
572
+
573
+ - [ ] **Step 1: Add TLS to options and constructor**
574
+
575
+ Add/update imports at the top:
576
+
577
+ ```typescript
578
+ import type { Server as HttpServer } from 'node:http';
579
+ import type { Server as HttpsServer } from 'node:https';
580
+ import type { TlsConfig } from '../lib/config/IServerConfig.js';
581
+ import { createServerListener, getProtocol } from './tlsUtils.js';
582
+ ```
583
+
584
+ Add to `SseServerOptions`:
585
+
586
+ ```typescript
587
+ /**
588
+ * TLS configuration for HTTPS mode
589
+ */
590
+ tls?: TlsConfig;
591
+ ```
592
+
593
+ Update `standaloneServer` type in the class (line 79):
594
+
595
+ ```typescript
596
+ private standaloneServer?: HttpServer | HttpsServer;
597
+ ```
598
+
599
+ Add field and set in constructor:
600
+
601
+ ```typescript
602
+ private readonly tls?: TlsConfig;
603
+ // In constructor:
604
+ this.tls = opts?.tls;
605
+ ```
606
+
607
+ - [ ] **Step 2: Update start() method**
608
+
609
+ Replace in `start()`:
610
+
611
+ ```typescript
612
+ // OLD:
613
+ const server = app.listen(this.port, this.host);
614
+ this.standaloneServer = server;
615
+
616
+ server.once('listening', () => {
617
+ console.error(
618
+ `[SseServer] Server started on ${this.host}:${this.port}`,
619
+ );
620
+ console.error(
621
+ `[SseServer] SSE endpoint: http://${this.host}:${this.port}${this.ssePath}`,
622
+ );
623
+ console.error(
624
+ `[SseServer] POST endpoint: http://${this.host}:${this.port}${this.postPath}`,
625
+ );
626
+ resolve();
627
+ });
628
+ ```
629
+
630
+ With:
631
+
632
+ ```typescript
633
+ const protocol = getProtocol(this.tls);
634
+ const server = createServerListener(app as any, this.tls);
635
+ this.standaloneServer = server;
636
+
637
+ server.listen(this.port, this.host);
638
+ server.once('listening', () => {
639
+ console.error(
640
+ `[SseServer] Server started on ${this.host}:${this.port}`,
641
+ );
642
+ console.error(
643
+ `[SseServer] SSE endpoint: ${protocol}://${this.host}:${this.port}${this.ssePath}`,
644
+ );
645
+ console.error(
646
+ `[SseServer] POST endpoint: ${protocol}://${this.host}:${this.port}${this.postPath}`,
647
+ );
648
+ resolve();
649
+ });
650
+ ```
651
+
652
+ - [ ] **Step 3: Commit**
653
+
654
+ ```bash
655
+ git add src/server/SseServer.ts
656
+ git commit -m "feat: integrate TLS into SseServer"
657
+ ```
658
+
659
+ ---
660
+
661
+ ### Task 8: Pass TLS config from launcher
662
+
663
+ **Files:**
664
+ - Modify: `src/server/launcher.ts`
665
+
666
+ - [ ] **Step 1: Pass tls to SseServer constructor**
667
+
668
+ In `launcher.ts`, find the SseServer creation block (~line 335) and add `tls`:
669
+
670
+ ```typescript
671
+ const server = new SseServer(handlersRegistry, authBrokerFactory, {
672
+ host: config.host,
673
+ port: config.port,
674
+ ssePath: config.ssePath,
675
+ postPath: config.postPath,
676
+ defaultDestination:
677
+ config.mcpDestination ?? (config.envFile ? 'default' : undefined),
678
+ logger: loggerForTransport,
679
+ tls: config.tls, // <-- add this
680
+ });
681
+ ```
682
+
683
+ - [ ] **Step 2: Pass tls to StreamableHttpServer constructor**
684
+
685
+ Find the StreamableHttpServer creation block (~line 350) and add `tls`:
686
+
687
+ ```typescript
688
+ const server = new StreamableHttpServer(handlersRegistry, authBrokerFactory, {
689
+ host: config.host,
690
+ port: config.port,
691
+ enableJsonResponse: config.httpJsonResponse,
692
+ path: config.httpPath,
693
+ defaultDestination:
694
+ config.mcpDestination ?? (config.envFile ? 'default' : undefined),
695
+ logger: loggerForTransport,
696
+ tls: config.tls, // <-- add this
697
+ });
698
+ ```
699
+
700
+ - [ ] **Step 3: Add TLS env vars to V2_HELP_SECTIONS**
701
+
702
+ In `V2_HELP_SECTIONS`, add to the `MCP Server Configuration:` block:
703
+
704
+ ```
705
+ MCP_TLS_CERT Path to TLS certificate file (PEM)
706
+ MCP_TLS_KEY Path to TLS private key file (PEM)
707
+ MCP_TLS_CA Path to TLS CA certificate file (PEM, optional)
708
+ ```
709
+
710
+ - [ ] **Step 4: Commit**
711
+
712
+ ```bash
713
+ git add src/server/launcher.ts
714
+ git commit -m "feat: pass TLS config from launcher to HTTP/SSE servers"
715
+ ```
716
+
717
+ ---
718
+
719
+ ### Task 9: Build and verify
720
+
721
+ - [ ] **Step 1: Run build**
722
+
723
+ Run: `npm run build`
724
+ Expected: No compilation errors
725
+
726
+ - [ ] **Step 2: Run existing unit tests**
727
+
728
+ Run: `npx jest src/__tests__/unit/ --no-coverage`
729
+ Expected: All pass (including new TLS tests and existing health endpoint tests)
730
+
731
+ - [ ] **Step 3: Run linter**
732
+
733
+ Run: `npm run lint`
734
+ Expected: No errors
735
+
736
+ - [ ] **Step 4: Commit any fixes if needed**
737
+
738
+ ---
739
+
740
+ ## Usage Examples (for documentation reference)
741
+
742
+ ```bash
743
+ # CLI with TLS
744
+ mcp-abap-adt --transport=http --port=8443 \
745
+ --tls-cert=/path/to/server.crt \
746
+ --tls-key=/path/to/server.key
747
+
748
+ # CLI with CA chain
749
+ mcp-abap-adt --transport=http --port=8443 \
750
+ --tls-cert=/path/to/server.crt \
751
+ --tls-key=/path/to/server.key \
752
+ --tls-ca=/path/to/ca-chain.crt
753
+
754
+ # Via environment variables
755
+ MCP_TRANSPORT=http MCP_HTTP_PORT=8443 \
756
+ MCP_TLS_CERT=/path/to/server.crt \
757
+ MCP_TLS_KEY=/path/to/server.key \
758
+ mcp-abap-adt
759
+ ```
760
+
761
+ ```yaml
762
+ # YAML config
763
+ transport: http
764
+ http:
765
+ port: 8443
766
+ host: 0.0.0.0
767
+ tls:
768
+ cert: /path/to/server.crt
769
+ key: /path/to/server.key
770
+ ca: /path/to/ca-chain.crt
771
+ ```