mcp-3d-printer-server 1.0.3 → 1.2.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 CHANGED
@@ -1,3 +1,5 @@
1
+
2
+
1
3
  # MCP 3D Printer Server
2
4
 
3
5
  [![npm version](https://img.shields.io/npm/v/mcp-3d-printer-server.svg)](https://www.npmjs.com/package/mcp-3d-printer-server)
@@ -9,6 +11,7 @@
9
11
  [![Downloads](https://img.shields.io/npm/dm/mcp-3d-printer-server.svg)](https://www.npmjs.com/package/mcp-3d-printer-server)
10
12
  [![GitHub stars](https://img.shields.io/github/stars/dmontgomery40/mcp-3d-printer-server.svg?style=social&label=Star)](https://github.com/yourusername/mcp-3d-printer-server)
11
13
 
14
+
12
15
  <a href="https://glama.ai/mcp/servers/7f6v2enbgk">
13
16
  <img width="380" height="200" src="https://glama.ai/mcp/servers/7f6v2enbgk/badge" alt="3D Printer Server MCP server" />
14
17
  </a>
@@ -16,14 +19,11 @@
16
19
  <details>
17
20
  <summary><strong>✨ What's New / Significant Updates (as of last session)</strong></summary>
18
21
 
19
- - **Bambu `.3mf` Printing:** Added the `print_3mf` tool specifically for Bambu Lab printers. This uploads the `.3mf` file and sends the print command directly via MQTT based on OpenBambuAPI specs.
20
- - **Direct MQTT Communication (Bambu):** Refactored Bambu command handling (`print_3mf`, `cancelJob`) to use direct MQTT (TLS port 8883) instead of relying solely on `bambu-js` for commands.
21
- - **`.3mf` File Parsing:** Implemented a parser (`src/3mf_parser.ts`) to read metadata and Bambu-specific slicer settings (from `project_settings.config`) within `.3mf` files.
22
- - **Bambu Preset Resources:** Added support for reading Bambu Studio preset files (`machine`, `filament`, `process`) as MCP resources (e.g., `preset://bambu/process/MyPreset`) if `BAMBU_STUDIO_CONFIG_PATH` is set.
23
- - **OrcaSlicer Integration:** Added support for using OrcaSlicer via its command-line interface for the `slice_stl` tool.
24
- - **New STL Manipulation Tools:** Added `merge_vertices`, `center_model`, and `lay_flat` tools for basic model preparation using `three.js`.
25
- - **Configuration Update:** Added `BAMBU_STUDIO_CONFIG_PATH` environment variable for preset loading.
26
- - **FTP Usage Note:** Acknowledged in documentation that file operations for Bambu currently use potentially unsecured FTP via `bambu-js`.
22
+ - **Dual Local Transports:** Added explicit `stdio` and `streamable-http` runtime modes with environment-based transport selection.
23
+ - **Bambu Reliability Pass:** Fixed Bambu argument wiring bugs, added FTP-backed file operations, improved status refresh behavior, and implemented practical command paths for `startJob`, `setTemperature`, and `print_3mf`.
24
+ - **Blender Bridge Tooling:** Added `blender_mcp_edit_model` with optional execution mode for model-edit collaboration workflows.
25
+ - **Transport Behavior Tests:** Added real behavior tests for both transports (`initialize`, `tools/list`, success + failing `tools/call`, origin rejection).
26
+ - **Docker Modernization:** Updated Docker build flow to work without BuildKit-specific features and verified streamable HTTP initialization in container smoke testing.
27
27
 
28
28
  </details>
29
29
 
@@ -85,6 +85,7 @@
85
85
  - [Visualization Limitations](#visualization-limitations)
86
86
  - [Performance Considerations](#performance-considerations)
87
87
  - [Testing Recommendations](#testing-recommendations)
88
+ - [Appendix: MCP in Practice (Code Execution, Scale, and Safety)](#appendix-mcp-in-practice-code-execution-scale-and-safety)
88
89
  - [Badges](#badges)
89
90
  - [License](#license)
90
91
 
@@ -210,9 +211,12 @@ TEMP_DIR=/path/to/temp/dir
210
211
  # Bambu Labs specific configuration
211
212
  BAMBU_SERIAL=your_printer_serial # REQUIRED for Bambu
212
213
  BAMBU_TOKEN=your_access_token # REQUIRED for Bambu
214
+ BAMBU_MODEL=p1s # REQUIRED for Bambu: p1s, p1p, x1c, x1e, a1, a1mini, h2d
215
+ BED_TYPE=textured_plate # Bed plate: textured_plate, cool_plate, engineering_plate, hot_plate
216
+ NOZZLE_DIAMETER=0.4 # Nozzle diameter in mm (default: 0.4)
213
217
 
214
218
  # Slicer configuration (for slice_stl tool)
215
- SLICER_TYPE=prusaslicer # Options: prusaslicer, cura, slic3r, orcaslicer
219
+ SLICER_TYPE=prusaslicer # Options: prusaslicer, cura, slic3r, orcaslicer, bambustudio
216
220
  SLICER_PATH=/path/to/slicer/executable
217
221
  SLICER_PROFILE=/path/to/slicer/profile
218
222
 
@@ -221,6 +225,18 @@ SLICER_PROFILE=/path/to/slicer/profile
221
225
  # Example Windows: C:\Users\your_user\AppData\Roaming\BambuStudio\user\YOUR_USER_ID
222
226
  # Example Linux: /home/your_user/.config/BambuStudio/user/YOUR_USER_ID
223
227
  BAMBU_STUDIO_CONFIG_PATH=
228
+
229
+ # MCP transport configuration
230
+ MCP_TRANSPORT=stdio # Options: stdio, streamable-http
231
+ MCP_HTTP_HOST=127.0.0.1
232
+ MCP_HTTP_PORT=3000
233
+ MCP_HTTP_PATH=/mcp
234
+ MCP_HTTP_STATEFUL=true
235
+ MCP_HTTP_JSON_RESPONSE=true
236
+ MCP_HTTP_ALLOWED_ORIGINS=http://localhost
237
+
238
+ # Optional bridge command for blender_mcp_edit_model execute=true mode
239
+ BLENDER_MCP_BRIDGE_COMMAND=
224
240
  ```
225
241
 
226
242
  ## Usage with Claude Desktop
@@ -253,7 +269,8 @@ BAMBU_STUDIO_CONFIG_PATH=
253
269
  "PRINTER_HOST": "your_printer_ip",
254
270
  "PRINTER_TYPE": "bambu",
255
271
  "BAMBU_SERIAL": "your_printer_serial",
256
- "BAMBU_TOKEN": "your_access_token"
272
+ "BAMBU_TOKEN": "your_access_token",
273
+ "BAMBU_MODEL": "p1s"
257
274
  }
258
275
  }
259
276
  }
@@ -298,8 +315,9 @@ Repetier-Server is a host software for 3D printers.
298
315
  Bambu Lab printers use MQTT for status and control and FTP for file operations.
299
316
 
300
317
  - Authentication: Serial number and access token required (set `BAMBU_SERIAL` and `BAMBU_TOKEN`)
301
- - Requirements: Printer must be on the same network or have cloud connection enabled
302
- - Compatible with: X1C, P1S, P1P, A1, and other Bambu Lab printers
318
+ - Printer model: **Required** (set `BAMBU_MODEL`). Valid values: `p1s`, `p1p`, `x1c`, `x1e`, `a1`, `a1mini`, `h2d`. This ensures the slicer generates correct G-code for your specific printer.
319
+ - Requirements: Printer must be on the same network with Developer Mode and LAN Only Mode enabled
320
+ - Compatible with: X1C, X1E, P1S, P1P, A1, A1 Mini, H2D
303
321
 
304
322
  #### Finding Your Bambu Printer's Serial Number and Access Token
305
323
 
@@ -658,19 +676,22 @@ Set the temperature of a printer component.
658
676
 
659
677
  Uploads a `.3mf` file to a Bambu printer via FTP and initiates the print job via an MQTT command. Allows overriding some print parameters like AMS mapping.
660
678
 
679
+ **`bambu_model` is required** -- it ensures the slicer generates G-code for the correct printer. Using the wrong model can cause the bed to crash into the nozzle and damage the printer. If not provided in the tool call and `BAMBU_MODEL` is not set in the environment, the server will ask interactively via MCP elicitation (if supported by your client) or return a clear error.
680
+
661
681
  ```json
662
682
  {
663
683
  "three_mf_path": "/path/to/your_model.3mf",
664
- "host": "your_bambu_ip", // Optional if default is set
665
- "bambu_serial": "YOUR_SERIAL", // Optional if default is set
666
- "bambu_token": "YOUR_TOKEN", // Optional if default is set
667
- // Optional Overrides:
668
- "use_ams": true, // Default: true
669
- "ams_mapping": [0, 1, 2, 3], // Array of AMS slot indices to use
670
- "bed_leveling": true, // Default: true
671
- "flow_calibration": false, // Default: false
672
- "vibration_calibration": false, // Default: false
673
- "timelapse": false // Default: false
684
+ "bambu_model": "p1s",
685
+ "bed_type": "textured_plate",
686
+ "host": "your_bambu_ip",
687
+ "bambu_serial": "YOUR_SERIAL",
688
+ "bambu_token": "YOUR_TOKEN",
689
+ "use_ams": true,
690
+ "ams_mapping": [0, 1, 2, 3],
691
+ "bed_leveling": true,
692
+ "flow_calibration": false,
693
+ "vibration_calibration": false,
694
+ "timelapse": false
674
695
  }
675
696
  ```
676
697
 
@@ -746,17 +767,17 @@ Here are some example commands you can give to Claude after connecting the MCP s
746
767
 
747
768
  Due to the nature of the Bambu Lab printer API, there are some limitations:
748
769
 
749
- 1. **Starting prints**: Starting a print requires the 3MF project file path, gcode file name, print name, and MD5 hash. The simplified API in this server doesn't support this fully yet.
770
+ 1. **Printable 3MF requirement:** `print_3mf` requires a sliced 3MF that includes at least one `Metadata/plate_<n>.gcode` entry so the server can compute MD5 and start the job correctly.
750
771
 
751
- 2. **Temperature control**: The Bambu API doesn't provide direct methods to set temperatures. This would require custom G-code commands.
772
+ 2. **AMS behavior caveat:** The current `bambu-js` project-file command path always sends `use_ams=true`; passing `use_ams=false` is treated as best-effort and surfaced with a warning.
752
773
 
753
- 3. **File management**: Files must be uploaded to the "gcodes" directory on the printer.
774
+ 3. **Temperature control path:** Temperature updates are implemented through G-code command dispatch (`M104`/`M140`) over MQTT, so effective behavior still depends on printer firmware acceptance and current printer state.
754
775
 
755
- 4. **FTP Security:** File operations currently use the printer's FTP server, which may be unsecured (plain FTP).
776
+ 4. **File transfer channel:** File operations use Bambu's FTPS path (port 990) via `bambu-js`. This is more secure than plain FTP, but still assumes a trusted local network environment and library-managed TLS behavior.
756
777
 
757
- 5. **Parameter Overrides:** Only parameters supported by the MQTT `project_file` command can be overridden via the `print_3mf` tool (e.g., AMS usage, calibration flags). Slicer settings like layer height or temperature cannot be changed at print time via this command.
778
+ 5. **Direct start path scope:** `startJob` currently targets `.gcode` files on printer storage; `.3mf` jobs should be initiated through `print_3mf` so metadata and plate selection are handled.
758
779
 
759
- 6. **Status Updates:** Full real-time status monitoring via MQTT needs further implementation.
780
+ 6. **Status consistency:** Status reads force a `pushall` refresh when possible, but complete real-time, event-stream status semantics across all Bambu models still need deeper hardening.
760
781
 
761
782
  ## Limitations and Considerations
762
783
 
@@ -784,6 +805,57 @@ Due to the nature of the Bambu Lab printer API, there are some limitations:
784
805
  - Test modifications on simple geometries before attempting complex ones
785
806
  - Consider running on a system with at least 4GB of available RAM for larger operations
786
807
 
808
+ ## Appendix: MCP in Practice (Code Execution, Scale, and Safety)
809
+
810
+ Last updated: 2026-02-24
811
+
812
+ ### State of MCP Right Now
813
+ MCP remains a high-value protocol for interoperability, but large tool surfaces have a real downside: tool schemas, retries, and tool-call traces can flood the context window. More tools often means more token overhead unless the execution model is disciplined.
814
+
815
+ ### Why Code Mode / Code Execution Has Become Important
816
+ Recent production workflows increasingly move orchestration out of conversational turns and into executable code loops. This keeps context leaner, makes behavior easier to audit, and improves reproducibility.
817
+
818
+ Core reading:
819
+ - Cloudflare: https://blog.cloudflare.com/code-mode/
820
+ - Cloudflare: https://blog.cloudflare.com/code-execution-with-mcp/
821
+ - Anthropic: https://www.anthropic.com/engineering/code-execution-with-mcp
822
+
823
+ ### Setup Guidance for Users
824
+ For practical day-to-day use, start with a codemode-oriented gateway and keep direct tool exposure narrow:
825
+ - `codemode-mcp`: https://github.com/jx-codes/codemode-mcp
826
+ - UTCP routing guidance: https://www.utcp.io
827
+
828
+ Even with strong setup, model/tool usage can still be inconsistent across client versions and model releases, so retries and deterministic fallbacks are still required.
829
+
830
+ ### Peter Steinberger Workflow Pattern
831
+ A high-signal pattern is converting broad MCP toolsets into targeted CLIs so the model calls fewer, better-defined commands:
832
+ - MCPorter: https://github.com/steipete/mcporter
833
+ - OpenClaw: https://github.com/steipete/openclaw
834
+
835
+ ### What Works Best With Which Clients
836
+ - Claude Code, Codex CLI, and Cursor agent modes: strong fit for direct MCP and code-execution workflows.
837
+ - Thin hosted chat clients: usually better when MCP servers are wrapped behind narrower CLIs/gateways.
838
+ - Large multi-tool servers: best when grouped into task-specific wrappers instead of exposing every tool directly.
839
+
840
+ This ecosystem changes quickly; if you are reading this later, parts of this section may already be stale.
841
+
842
+ ### Prompt Injection: Risks, Consequences, and Mitigations
843
+ Prompt injection is still an open problem for tool-using agents. It is manageable, but not solved.
844
+
845
+ Primary risks:
846
+ - Hidden malicious instructions in remote content or tool output.
847
+ - Secret exfiltration via unintended network/tool calls.
848
+ - Unauthorized state changes (filesystem, infrastructure, or printer actions).
849
+
850
+ Practical mitigations:
851
+ - Least-privilege credentials and short-lived tokens.
852
+ - Strict schema validation and explicit allowlists for actions/hosts.
853
+ - Human confirmation gates for destructive operations.
854
+ - Execution sandboxing with resource/time limits.
855
+ - Structured logs and replayable runs for incident response.
856
+
857
+ Treat tool output as untrusted input by default.
858
+
787
859
  ## Badges
788
860
 
789
861
  | Badge | Description |
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ declare class ThreeDPrinterMCPServerHTTP {
3
+ private server;
4
+ private printerFactory;
5
+ private stlManipulator;
6
+ private app;
7
+ constructor();
8
+ private setupExpressApp;
9
+ private handleJSONRPCRequest;
10
+ setupErrorHandling(): void;
11
+ setupHandlers(): void;
12
+ setupResourceHandlers(): void;
13
+ setupToolHandlers(): void;
14
+ run(): Promise<void>;
15
+ }
16
+ export default ThreeDPrinterMCPServerHTTP;
@@ -0,0 +1,268 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import express from 'express';
4
+ import cors from 'cors';
5
+ import dotenv from "dotenv";
6
+ import fs from "fs";
7
+ import path from "path";
8
+ import { PrinterFactory } from "./printers/printer-factory.js";
9
+ import { STLManipulator } from "./stl/stl-manipulator.js";
10
+ // Load environment variables from .env file
11
+ dotenv.config();
12
+ // Default values
13
+ const DEFAULT_HOST = process.env.PRINTER_HOST || "localhost";
14
+ const DEFAULT_PORT = process.env.PRINTER_PORT || "80";
15
+ const DEFAULT_API_KEY = process.env.API_KEY || "";
16
+ const DEFAULT_TYPE = process.env.PRINTER_TYPE || "octoprint";
17
+ const TEMP_DIR = process.env.TEMP_DIR || path.join(process.cwd(), "temp");
18
+ // HTTP Server configuration
19
+ const HTTP_PORT = parseInt(process.env.HTTP_PORT || "3001");
20
+ // Slicer configuration
21
+ const DEFAULT_SLICER_TYPE = process.env.SLICER_TYPE || "prusaslicer";
22
+ const DEFAULT_SLICER_PATH = process.env.SLICER_PATH || "";
23
+ const DEFAULT_SLICER_PROFILE = process.env.SLICER_PROFILE || "";
24
+ // Bambu-specific default values
25
+ const DEFAULT_BAMBU_SERIAL = process.env.BAMBU_SERIAL || "";
26
+ const DEFAULT_BAMBU_TOKEN = process.env.BAMBU_TOKEN || "";
27
+ // Ensure temp directory exists
28
+ if (!fs.existsSync(TEMP_DIR)) {
29
+ fs.mkdirSync(TEMP_DIR, { recursive: true });
30
+ }
31
+ class ThreeDPrinterMCPServerHTTP {
32
+ constructor() {
33
+ this.server = new Server({
34
+ name: "mcp-3d-printer-server",
35
+ version: "1.0.0"
36
+ }, {
37
+ capabilities: {
38
+ resources: {},
39
+ tools: {},
40
+ prompts: {}
41
+ }
42
+ });
43
+ this.printerFactory = new PrinterFactory();
44
+ this.stlManipulator = new STLManipulator(TEMP_DIR);
45
+ this.app = express();
46
+ this.setupExpressApp();
47
+ this.setupHandlers();
48
+ this.setupErrorHandling();
49
+ }
50
+ setupExpressApp() {
51
+ // Enable CORS for all origins
52
+ this.app.use(cors({
53
+ origin: '*',
54
+ methods: ['GET', 'POST', 'OPTIONS'],
55
+ allowedHeaders: ['Content-Type', 'Accept'],
56
+ credentials: true
57
+ }));
58
+ // Parse JSON bodies
59
+ this.app.use(express.json({ limit: '50mb' }));
60
+ // Main MCP endpoint - supports both standard and streaming responses
61
+ this.app.post('/mcp', async (req, res) => {
62
+ const acceptHeader = req.get('Accept') || '';
63
+ const wantsStream = acceptHeader.includes('text/event-stream');
64
+ try {
65
+ const requests = Array.isArray(req.body) ? req.body : [req.body];
66
+ const responses = [];
67
+ for (const request of requests) {
68
+ const response = await this.handleJSONRPCRequest(request);
69
+ if (response) {
70
+ responses.push(response);
71
+ }
72
+ }
73
+ // If client wants streaming and we have responses, use SSE format
74
+ if (wantsStream && responses.length > 0) {
75
+ res.setHeader('Content-Type', 'text/event-stream');
76
+ res.setHeader('Cache-Control', 'no-cache');
77
+ res.setHeader('Connection', 'keep-alive');
78
+ for (const response of responses) {
79
+ res.write(`data: ${JSON.stringify(response)}\n\n`);
80
+ }
81
+ res.end();
82
+ }
83
+ else if (responses.length > 0) {
84
+ // Standard JSON response
85
+ res.json(responses.length === 1 ? responses[0] : responses);
86
+ }
87
+ else {
88
+ // No responses (notifications)
89
+ res.status(202).send();
90
+ }
91
+ }
92
+ catch (error) {
93
+ console.error('Error handling request:', error);
94
+ res.status(500).json({
95
+ jsonrpc: "2.0",
96
+ error: {
97
+ code: -32603,
98
+ message: "Internal error",
99
+ data: error instanceof Error ? error.message : String(error)
100
+ }
101
+ });
102
+ }
103
+ });
104
+ // GET endpoint for establishing SSE stream (Streamable HTTP)
105
+ this.app.get('/mcp', async (req, res) => {
106
+ const acceptHeader = req.get('Accept') || '';
107
+ if (!acceptHeader.includes('text/event-stream')) {
108
+ res.status(405).json({
109
+ error: 'Method not allowed. Use POST for non-streaming requests.'
110
+ });
111
+ return;
112
+ }
113
+ // Set SSE headers
114
+ res.setHeader('Content-Type', 'text/event-stream');
115
+ res.setHeader('Cache-Control', 'no-cache');
116
+ res.setHeader('Connection', 'keep-alive');
117
+ res.setHeader('X-Accel-Buffering', 'no');
118
+ // Send initial connection event
119
+ res.write(`event: open\ndata: {"type": "connection", "status": "connected"}\n\n`);
120
+ // Keep connection alive with periodic pings
121
+ const pingInterval = setInterval(() => {
122
+ if (!res.writableEnded) {
123
+ res.write(`event: ping\ndata: ${new Date().toISOString()}\n\n`);
124
+ }
125
+ }, 30000);
126
+ // Handle client disconnect
127
+ req.on('close', () => {
128
+ clearInterval(pingInterval);
129
+ res.end();
130
+ });
131
+ });
132
+ // Health check endpoint
133
+ this.app.get('/health', (req, res) => {
134
+ res.json({
135
+ status: 'ok',
136
+ server: 'mcp-3d-printer-server',
137
+ transport: 'streamable-http',
138
+ version: '1.0.0'
139
+ });
140
+ });
141
+ // Root endpoint
142
+ this.app.get('/', (req, res) => {
143
+ res.json({
144
+ name: 'MCP 3D Printer Server (HTTP)',
145
+ version: '1.0.0',
146
+ endpoints: {
147
+ mcp: '/mcp',
148
+ health: '/health'
149
+ },
150
+ transport: 'streamable-http',
151
+ features: ['stdio', 'sse', 'http'],
152
+ documentation: 'https://github.com/DMontgomery40/mcp-3D-printer-server'
153
+ });
154
+ });
155
+ }
156
+ async handleJSONRPCRequest(request) {
157
+ try {
158
+ // Route based on method
159
+ switch (request.method) {
160
+ case 'initialize':
161
+ return {
162
+ jsonrpc: "2.0",
163
+ id: request.id,
164
+ result: {
165
+ protocolVersion: "2025-03-26",
166
+ capabilities: this.server.capabilities,
167
+ serverInfo: {
168
+ name: "mcp-3d-printer-server",
169
+ version: "1.0.0"
170
+ }
171
+ }
172
+ };
173
+ case 'resources/list':
174
+ const resourcesResult = await this.server.handleRequest(request);
175
+ return {
176
+ jsonrpc: "2.0",
177
+ id: request.id,
178
+ result: resourcesResult
179
+ };
180
+ case 'resources/read':
181
+ const readResult = await this.server.handleRequest(request);
182
+ return {
183
+ jsonrpc: "2.0",
184
+ id: request.id,
185
+ result: readResult
186
+ };
187
+ case 'tools/list':
188
+ const toolsResult = await this.server.handleRequest(request);
189
+ return {
190
+ jsonrpc: "2.0",
191
+ id: request.id,
192
+ result: toolsResult
193
+ };
194
+ case 'tools/call':
195
+ const callResult = await this.server.handleRequest(request);
196
+ return {
197
+ jsonrpc: "2.0",
198
+ id: request.id,
199
+ result: callResult
200
+ };
201
+ default:
202
+ if (request.id) {
203
+ return {
204
+ jsonrpc: "2.0",
205
+ id: request.id,
206
+ error: {
207
+ code: -32601,
208
+ message: `Method not found: ${request.method}`
209
+ }
210
+ };
211
+ }
212
+ return null; // Notification
213
+ }
214
+ }
215
+ catch (error) {
216
+ if (request.id) {
217
+ return {
218
+ jsonrpc: "2.0",
219
+ id: request.id,
220
+ error: {
221
+ code: -32603,
222
+ message: "Internal error",
223
+ data: error instanceof Error ? error.message : String(error)
224
+ }
225
+ };
226
+ }
227
+ return null;
228
+ }
229
+ }
230
+ setupErrorHandling() {
231
+ this.server.onerror = (error) => {
232
+ console.error("[MCP Error]", error);
233
+ };
234
+ process.on("SIGINT", async () => {
235
+ console.log("\nShutting down HTTP server...");
236
+ await this.printerFactory.disconnectAll();
237
+ await this.server.close();
238
+ process.exit(0);
239
+ });
240
+ }
241
+ setupHandlers() {
242
+ this.setupResourceHandlers();
243
+ this.setupToolHandlers();
244
+ }
245
+ // Copy all handlers from original index.ts
246
+ setupResourceHandlers() {
247
+ // ... (copy from original)
248
+ }
249
+ setupToolHandlers() {
250
+ // ... (copy from original)
251
+ }
252
+ // Copy all delegating methods from original index.ts
253
+ // ... (copy all printer methods)
254
+ async run() {
255
+ // Start Express server
256
+ this.app.listen(HTTP_PORT, () => {
257
+ console.log(`🚀 MCP 3D Printer Server (HTTP) running on http://localhost:${HTTP_PORT}`);
258
+ console.log(`📡 MCP endpoint: http://localhost:${HTTP_PORT}/mcp`);
259
+ console.log(`✨ Supports both standard HTTP and Server-Sent Events`);
260
+ });
261
+ }
262
+ }
263
+ // Check if running as main module
264
+ if (import.meta.url === `file://${process.argv[1]}`) {
265
+ const server = new ThreeDPrinterMCPServerHTTP();
266
+ server.run().catch(console.error);
267
+ }
268
+ export default ThreeDPrinterMCPServerHTTP;