mcp-3d-printer-server 1.0.3 → 1.2.2

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
 
@@ -57,7 +57,7 @@
57
57
  - [Running with Docker](#running-with-docker)
58
58
  - [Using Slicers with Docker](#using-slicers-with-docker)
59
59
  - [Configuration](#configuration)
60
- - [Usage with Claude Desktop](#usage-with-claude-desktop)
60
+ - [Usage](#usage)
61
61
  - [Supported Printer Management Systems](#supported-printer-management-systems)
62
62
  - [OctoPrint](#octoprint)
63
63
  - [Klipper (via Moonraker)](#klipper-via-moonraker)
@@ -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 Safety Notes](#appendix-mcp-safety-notes)
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,47 +225,69 @@ 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=
224
- ```
225
228
 
226
- ## Usage with Claude Desktop
227
-
228
- 1. Edit your Claude Desktop configuration file:
229
-
230
- ```json
231
- {
232
- "mcpServers": {
233
- "3dprint": {
234
- "command": "mcp-3d-printer-server",
235
- "env": {
236
- "API_KEY": "your_api_key_here",
237
- "PRINTER_HOST": "your_printer_ip",
238
- "PRINTER_TYPE": "octoprint"
239
- }
240
- }
241
- }
242
- }
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=
243
240
  ```
244
241
 
245
- 2. For Bambu Labs printers:
242
+ ## Usage
243
+
244
+ Add this server to your MCP client's config (Claude Desktop, Claude Code, Cursor, Codex CLI, or any MCP-compatible client). The config format is the same everywhere -- an `mcpServers` entry with the command and env vars:
246
245
 
247
246
  ```json
248
247
  {
249
248
  "mcpServers": {
250
249
  "3dprint": {
251
- "command": "mcp-3d-printer-server",
250
+ "command": "npx",
251
+ "args": ["-y", "mcp-3d-printer-server"],
252
252
  "env": {
253
253
  "PRINTER_HOST": "your_printer_ip",
254
254
  "PRINTER_TYPE": "bambu",
255
255
  "BAMBU_SERIAL": "your_printer_serial",
256
- "BAMBU_TOKEN": "your_access_token"
256
+ "BAMBU_TOKEN": "your_access_token",
257
+ "BAMBU_MODEL": "p1s",
258
+ "SLICER_TYPE": "bambustudio",
259
+ "SLICER_PATH": "/Applications/BambuStudio.app/Contents/MacOS/BambuStudio"
257
260
  }
258
261
  }
259
262
  }
260
263
  }
261
264
  ```
262
265
 
263
- 3. Restart Claude Desktop
264
- 4. Connect to your printer through Claude
266
+ For non-Bambu printers, replace the Bambu-specific env vars with `API_KEY` and the appropriate `PRINTER_TYPE` (see [Supported Printer Management Systems](#supported-printer-management-systems)).
267
+
268
+ Where this config lives depends on your client:
269
+
270
+ | Client | Config location |
271
+ |--------|----------------|
272
+ | Claude Desktop (macOS) | `~/Library/Application Support/Claude/claude_desktop_config.json` |
273
+ | Claude Desktop (Windows) | `%APPDATA%\Claude\claude_desktop_config.json` |
274
+ | Claude Code (project) | `.mcp.json` in project root |
275
+ | Claude Code (global) | `~/.claude/settings.json` |
276
+ | Cursor | MCP settings in Cursor preferences |
277
+ | Codex CLI | MCP config per Codex docs |
278
+
279
+ Restart your client after editing the config.
280
+
281
+ ### Recommended: use with codemode-mcp
282
+
283
+ For any MCP server with a large tool surface, wrapping it behind [codemode-mcp](https://github.com/jx-codes/codemode-mcp) dramatically reduces token usage. Instead of exposing every tool definition to the model, codemode lets the agent write code against a two-tool interface (`search()` and `execute()`), loading only the tools it needs on demand.
284
+
285
+ Anthropic and Cloudflare independently demonstrated this pattern reduces MCP token costs by up to 98%:
286
+
287
+ - [Code execution with MCP](https://www.anthropic.com/engineering/code-execution-with-mcp) (Anthropic)
288
+ - [Code Mode: give agents an entire API in 1,000 tokens](https://blog.cloudflare.com/code-mode-mcp/) (Cloudflare)
289
+
290
+ This applies to all MCP servers, not just this one.
265
291
 
266
292
  ## Supported Printer Management Systems
267
293
 
@@ -298,8 +324,9 @@ Repetier-Server is a host software for 3D printers.
298
324
  Bambu Lab printers use MQTT for status and control and FTP for file operations.
299
325
 
300
326
  - 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
327
+ - 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.
328
+ - Requirements: Printer must be on the same network with Developer Mode and LAN Only Mode enabled
329
+ - Compatible with: X1C, X1E, P1S, P1P, A1, A1 Mini, H2D
303
330
 
304
331
  #### Finding Your Bambu Printer's Serial Number and Access Token
305
332
 
@@ -658,19 +685,22 @@ Set the temperature of a printer component.
658
685
 
659
686
  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
687
 
688
+ **`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.
689
+
661
690
  ```json
662
691
  {
663
692
  "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
693
+ "bambu_model": "p1s",
694
+ "bed_type": "textured_plate",
695
+ "host": "your_bambu_ip",
696
+ "bambu_serial": "YOUR_SERIAL",
697
+ "bambu_token": "YOUR_TOKEN",
698
+ "use_ams": true,
699
+ "ams_mapping": [0, 1, 2, 3],
700
+ "bed_leveling": true,
701
+ "flow_calibration": false,
702
+ "vibration_calibration": false,
703
+ "timelapse": false
674
704
  }
675
705
  ```
676
706
 
@@ -746,17 +776,17 @@ Here are some example commands you can give to Claude after connecting the MCP s
746
776
 
747
777
  Due to the nature of the Bambu Lab printer API, there are some limitations:
748
778
 
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.
779
+ 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
780
 
751
- 2. **Temperature control**: The Bambu API doesn't provide direct methods to set temperatures. This would require custom G-code commands.
781
+ 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
782
 
753
- 3. **File management**: Files must be uploaded to the "gcodes" directory on the printer.
783
+ 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
784
 
755
- 4. **FTP Security:** File operations currently use the printer's FTP server, which may be unsecured (plain FTP).
785
+ 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
786
 
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.
787
+ 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
788
 
759
- 6. **Status Updates:** Full real-time status monitoring via MQTT needs further implementation.
789
+ 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
790
 
761
791
  ## Limitations and Considerations
762
792
 
@@ -784,6 +814,20 @@ Due to the nature of the Bambu Lab printer API, there are some limitations:
784
814
  - Test modifications on simple geometries before attempting complex ones
785
815
  - Consider running on a system with at least 4GB of available RAM for larger operations
786
816
 
817
+ ## Appendix: MCP Safety Notes
818
+
819
+ See [Recommended: use with codemode-mcp](#recommended-use-with-codemode-mcp) for reducing token overhead with large tool surfaces.
820
+
821
+ ### Prompt Injection: Risks and Mitigations
822
+
823
+ Prompt injection is an open problem for tool-using agents. Practical mitigations:
824
+
825
+ - Least-privilege credentials and short-lived tokens.
826
+ - Strict schema validation and explicit allowlists for actions/hosts.
827
+ - Human confirmation gates for destructive operations.
828
+ - Execution sandboxing with resource/time limits.
829
+ - Treat tool output as untrusted input by default.
830
+
787
831
  ## Badges
788
832
 
789
833
  | 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;