@aashari/boilerplate-mcp-server 3.0.0 → 3.1.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/.releaserc.json CHANGED
@@ -1,5 +1,7 @@
1
1
  {
2
- "branches": ["main"],
2
+ "branches": [
3
+ "main"
4
+ ],
3
5
  "plugins": [
4
6
  "@semantic-release/commit-analyzer",
5
7
  "@semantic-release/release-notes-generator",
@@ -24,7 +26,8 @@
24
26
  "package.json",
25
27
  "CHANGELOG.md",
26
28
  "src/index.ts",
27
- "src/cli/index.ts"
29
+ "src/cli/index.ts",
30
+ "src/utils/constants.util.ts"
28
31
  ],
29
32
  "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
30
33
  }
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [3.1.0](https://github.com/aashari/boilerplate-mcp-server/compare/v3.0.0...v3.1.0) (2026-02-17)
2
+
3
+
4
+ ### Features
5
+
6
+ * modernize HTTP transport and standardize MCP tool contracts ([615b373](https://github.com/aashari/boilerplate-mcp-server/commit/615b3732c10ad2c607a899de0f6632221b6f7bc3))
7
+
1
8
  # [3.0.0](https://github.com/aashari/boilerplate-mcp-server/compare/v2.0.0...v3.0.0) (2026-02-04)
2
9
 
3
10
 
package/README.md CHANGED
@@ -263,10 +263,6 @@ npm run mcp:stdio # STDIO transport for AI assistants
263
263
  npm run mcp:http # HTTP transport on port 3000
264
264
  npm run mcp:inspect # HTTP + auto-open MCP Inspector
265
265
 
266
- # Development with Debugging
267
- npm run dev:stdio # STDIO with MCP Inspector integration
268
- npm run dev:http # HTTP with debug logging enabled
269
-
270
266
  # Testing
271
267
  npm test # Run all tests (Jest)
272
268
  npm run test:coverage # Generate coverage report
@@ -275,7 +271,6 @@ npm run test:cli # Run CLI-specific tests
275
271
  # Code Quality
276
272
  npm run lint # ESLint with TypeScript rules
277
273
  npm run format # Prettier formatting
278
- npm run update:deps # Update dependencies
279
274
  ```
280
275
 
281
276
  ### Environment Variables
@@ -110,7 +110,8 @@ async function get(args = {}) {
110
110
  const useToon = args.outputFormat !== 'json';
111
111
  // Format the output
112
112
  const content = await (0, jq_util_js_1.toOutputString)(filteredData, useToon);
113
- return { content, rawResponsePath };
113
+ // Expose canonical resolved IP so callers do not need to parse rendered output
114
+ return { content, rawResponsePath, resolvedIp: data.query };
114
115
  }
115
116
  catch (error) {
116
117
  throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_2.buildErrorContext)('IP Address', 'get', 'controllers/ipaddress.controller.ts@get', args.ipAddress || 'current device', { args }));
package/dist/index.js CHANGED
@@ -5,9 +5,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  };
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.startServer = startServer;
8
+ const node_crypto_1 = require("node:crypto");
8
9
  const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
9
10
  const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
10
11
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
12
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
11
13
  const logger_util_js_1 = require("./utils/logger.util.js");
12
14
  const config_util_js_1 = require("./utils/config.util.js");
13
15
  const constants_util_js_1 = require("./utils/constants.util.js");
@@ -22,6 +24,28 @@ const analysis_prompt_js_1 = __importDefault(require("./prompts/analysis.prompt.
22
24
  const logger = logger_util_js_1.Logger.forContext('index.ts');
23
25
  let serverInstance = null;
24
26
  let transportInstance = null;
27
+ const httpSessions = new Map();
28
+ function createMcpServer() {
29
+ const server = new mcp_js_1.McpServer({
30
+ name: constants_util_js_1.PACKAGE_NAME,
31
+ version: constants_util_js_1.VERSION,
32
+ });
33
+ ipaddress_tool_js_1.default.registerTools(server);
34
+ ipaddress_link_tool_js_1.default.registerTools(server);
35
+ ipaddress_resource_js_1.default.registerResources(server);
36
+ analysis_prompt_js_1.default.registerPrompts(server);
37
+ return server;
38
+ }
39
+ function getSessionId(req) {
40
+ const rawSessionId = req.headers['mcp-session-id'];
41
+ if (Array.isArray(rawSessionId)) {
42
+ return rawSessionId[0] ?? null;
43
+ }
44
+ if (typeof rawSessionId === 'string' && rawSessionId.length > 0) {
45
+ return rawSessionId;
46
+ }
47
+ return null;
48
+ }
25
49
  /**
26
50
  * Start the MCP server with the specified transport mode
27
51
  */
@@ -34,19 +58,11 @@ async function startServer(mode = 'stdio') {
34
58
  if (config_util_js_1.config.getBoolean('DEBUG')) {
35
59
  serverLogger.debug('Debug mode enabled');
36
60
  }
37
- serverLogger.info(`Initializing Boilerplate MCP server v${constants_util_js_1.VERSION}`);
38
- serverInstance = new mcp_js_1.McpServer({
39
- name: constants_util_js_1.PACKAGE_NAME,
40
- version: constants_util_js_1.VERSION,
41
- });
42
- // Register tools, resources, and prompts
43
- serverLogger.info('Registering MCP tools, resources, and prompts...');
44
- ipaddress_tool_js_1.default.registerTools(serverInstance);
45
- ipaddress_link_tool_js_1.default.registerTools(serverInstance);
46
- ipaddress_resource_js_1.default.registerResources(serverInstance);
47
- analysis_prompt_js_1.default.registerPrompts(serverInstance);
48
- serverLogger.debug('All tools, resources, and prompts registered');
49
61
  if (mode === 'stdio') {
62
+ serverLogger.info(`Initializing Boilerplate MCP server v${constants_util_js_1.VERSION}`);
63
+ serverLogger.info('Registering MCP tools, resources, and prompts...');
64
+ serverInstance = createMcpServer();
65
+ serverLogger.debug('All tools, resources, and prompts registered');
50
66
  serverLogger.info('Using STDIO transport');
51
67
  transportInstance = new stdio_js_1.StdioServerTransport();
52
68
  try {
@@ -94,26 +110,132 @@ async function startServer(mode = 'stdio') {
94
110
  app.use(express_1.default.json());
95
111
  const mcpEndpoint = '/mcp';
96
112
  serverLogger.debug(`MCP endpoint: ${mcpEndpoint}`);
97
- // Create transport instance
98
- const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
99
- // sessionIdGenerator is optional
100
- sessionIdGenerator: undefined,
101
- });
102
- // Connect server to transport
103
- await serverInstance.connect(transport);
104
- transportInstance = transport;
105
- // Handle all MCP requests
106
- app.all(mcpEndpoint, (req, res) => {
107
- transport
108
- .handleRequest(req, res, req.body)
109
- .catch((err) => {
110
- serverLogger.error('Error in transport.handleRequest', err);
113
+ // Handle MCP POST requests (initialize + normal RPC calls)
114
+ app.post(mcpEndpoint, async (req, res) => {
115
+ const sessionId = getSessionId(req);
116
+ try {
117
+ if (sessionId) {
118
+ const session = httpSessions.get(sessionId);
119
+ if (!session) {
120
+ res.status(404).json({
121
+ jsonrpc: '2.0',
122
+ error: {
123
+ code: -32001,
124
+ message: 'Session not found for provided Mcp-Session-Id',
125
+ },
126
+ id: null,
127
+ });
128
+ return;
129
+ }
130
+ await session.transport.handleRequest(req, res, req.body);
131
+ return;
132
+ }
133
+ if (!(0, types_js_1.isInitializeRequest)(req.body)) {
134
+ res.status(400).json({
135
+ jsonrpc: '2.0',
136
+ error: {
137
+ code: -32000,
138
+ message: 'Bad Request: Missing Mcp-Session-Id header',
139
+ },
140
+ id: null,
141
+ });
142
+ return;
143
+ }
144
+ serverLogger.info('Creating new HTTP MCP session for initialize request');
145
+ let initializedSessionId = null;
146
+ const sessionServer = createMcpServer();
147
+ const sessionTransport = new streamableHttp_js_1.StreamableHTTPServerTransport({
148
+ sessionIdGenerator: () => (0, node_crypto_1.randomUUID)(),
149
+ onsessioninitialized: (newSessionId) => {
150
+ initializedSessionId = newSessionId;
151
+ httpSessions.set(newSessionId, {
152
+ server: sessionServer,
153
+ transport: sessionTransport,
154
+ });
155
+ serverLogger.info(`Initialized HTTP MCP session ${newSessionId}`);
156
+ },
157
+ onsessionclosed: (closedSessionId) => {
158
+ const session = httpSessions.get(closedSessionId);
159
+ if (!session) {
160
+ return;
161
+ }
162
+ httpSessions.delete(closedSessionId);
163
+ void session.server.close().catch((err) => {
164
+ serverLogger.error(`Error closing server for session ${closedSessionId}`, err);
165
+ });
166
+ serverLogger.info(`Closed HTTP MCP session ${closedSessionId}`);
167
+ },
168
+ });
169
+ await sessionServer.connect(sessionTransport);
170
+ try {
171
+ await sessionTransport.handleRequest(req, res, req.body);
172
+ }
173
+ catch (err) {
174
+ if (initializedSessionId) {
175
+ httpSessions.delete(initializedSessionId);
176
+ }
177
+ await sessionTransport.close();
178
+ await sessionServer.close();
179
+ throw err;
180
+ }
181
+ }
182
+ catch (err) {
183
+ serverLogger.error('Error in HTTP MCP handler', err);
111
184
  if (!res.headersSent) {
112
185
  res.status(500).json({
113
- error: 'Internal Server Error',
186
+ jsonrpc: '2.0',
187
+ error: {
188
+ code: -32603,
189
+ message: 'Internal server error',
190
+ },
191
+ id: null,
114
192
  });
115
193
  }
116
- });
194
+ }
195
+ });
196
+ // Handle optional GET requests for streamable HTTP SSE
197
+ app.get(mcpEndpoint, async (req, res) => {
198
+ const sessionId = getSessionId(req);
199
+ if (!sessionId) {
200
+ res.status(400).send('Missing Mcp-Session-Id header');
201
+ return;
202
+ }
203
+ const session = httpSessions.get(sessionId);
204
+ if (!session) {
205
+ res.status(404).send('Session not found');
206
+ return;
207
+ }
208
+ try {
209
+ await session.transport.handleRequest(req, res);
210
+ }
211
+ catch (err) {
212
+ serverLogger.error('Error in HTTP MCP GET handler', err);
213
+ if (!res.headersSent) {
214
+ res.status(500).send('Internal Server Error');
215
+ }
216
+ }
217
+ });
218
+ // Handle session termination requests
219
+ app.delete(mcpEndpoint, async (req, res) => {
220
+ const sessionId = getSessionId(req);
221
+ if (!sessionId) {
222
+ res.status(400).send('Missing Mcp-Session-Id header');
223
+ return;
224
+ }
225
+ const session = httpSessions.get(sessionId);
226
+ if (!session) {
227
+ res.status(404).send('Session not found');
228
+ return;
229
+ }
230
+ try {
231
+ await session.transport.handleRequest(req, res);
232
+ }
233
+ catch (err) {
234
+ serverLogger.error('Error in HTTP MCP DELETE handler', err);
235
+ if (!res.headersSent) {
236
+ res.status(500).send('Internal Server Error');
237
+ }
238
+ }
117
239
  });
118
240
  // Health check endpoint
119
241
  app.get('/', (_req, res) => {
@@ -130,7 +252,7 @@ async function startServer(mode = 'stdio') {
130
252
  });
131
253
  });
132
254
  setupGracefulShutdown();
133
- return serverInstance;
255
+ return createMcpServer();
134
256
  }
135
257
  }
136
258
  /**
@@ -177,6 +299,24 @@ function setupGracefulShutdown() {
177
299
  const shutdown = async () => {
178
300
  try {
179
301
  shutdownLogger.info('Shutting down gracefully...');
302
+ if (httpSessions.size > 0) {
303
+ shutdownLogger.info(`Closing ${httpSessions.size} active HTTP session(s)`);
304
+ }
305
+ for (const [sessionId, session] of httpSessions.entries()) {
306
+ try {
307
+ await session.transport.close();
308
+ }
309
+ catch (err) {
310
+ shutdownLogger.error(`Error closing transport for session ${sessionId}`, err);
311
+ }
312
+ try {
313
+ await session.server.close();
314
+ }
315
+ catch (err) {
316
+ shutdownLogger.error(`Error closing server for session ${sessionId}`, err);
317
+ }
318
+ }
319
+ httpSessions.clear();
180
320
  if (transportInstance &&
181
321
  'close' in transportInstance &&
182
322
  typeof transportInstance.close === 'function') {
@@ -5,68 +5,61 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const logger_util_js_1 = require("../utils/logger.util.js");
7
7
  const error_util_js_1 = require("../utils/error.util.js");
8
+ const formatter_util_js_1 = require("../utils/formatter.util.js");
8
9
  const zod_1 = require("zod");
9
10
  const ipaddress_controller_js_1 = __importDefault(require("../controllers/ipaddress.controller.js"));
11
+ const ipaddress_types_js_1 = require("./ipaddress.types.js");
10
12
  const logger = logger_util_js_1.Logger.forContext('tools/ipaddress-link.tool.ts');
11
13
  /**
12
14
  * Zod schema for the resource-link tool arguments
15
+ * Keep argument shape aligned with ip_get_details for consistency.
13
16
  */
14
17
  const GetIpDetailsLinkToolSchema = zod_1.z.object({
15
18
  ipAddress: zod_1.z
16
19
  .string()
17
20
  .optional()
18
21
  .describe('IP address to lookup (omit for current IP)'),
19
- includeExtendedData: zod_1.z
20
- .boolean()
21
- .optional()
22
- .describe('Include extended data (ASN, host, proxy detection)'),
22
+ ...ipaddress_types_js_1.IpAddressToolArgs.shape,
23
23
  });
24
24
  /**
25
25
  * Tool description for ip_get_details_link
26
26
  */
27
- const IP_GET_DETAILS_LINK_DESCRIPTION = `Retrieve IP address details and return as a resource reference (ResourceLink pattern).
28
-
29
- **This demonstrates the ResourceLink pattern** - instead of embedding full data inline, the tool returns a reference to a resource. This is useful for:
30
- - Large responses that would consume many tokens
31
- - Data that clients may cache and reuse
32
- - Responses that other tools can reference
33
-
34
- **When to use ResourceLink vs inline content:**
35
- - ResourceLink: Large data, cacheable, reusable across multiple tools
36
- - Inline: Small data, one-time use, immediate context
27
+ const IP_GET_DETAILS_LINK_DESCRIPTION = `Retrieve IP address details and return both direct content and a resource link.
37
28
 
38
- **Parameters:**
39
- - \`ipAddress\` - IP to lookup (omit for current device's public IP)
40
- - \`includeExtendedData\` - Include ASN, host, proxy detection (requires API token)
29
+ **Consistency with ip_get_details:**
30
+ - Uses the same arguments: \`ipAddress\`, \`includeExtendedData\`, \`useHttps\`, \`jq\`, \`outputFormat\`
31
+ - Uses the same output rendering pipeline (TOON by default, JSON when \`outputFormat: "json"\`)
41
32
 
42
- **Returns:** A resource reference (resourceLink) instead of inline text.
33
+ **What this returns:**
34
+ - A normal text response (same rendered output as \`ip_get_details\`)
35
+ - A \`resource_link\` entry pointing to \`ip://<resolved-ip>\` for resource-style clients
43
36
 
44
37
  **Note:** Cannot lookup private IPs (192.168.x.x, 10.x.x.x). Powered by ip-api.com.`;
45
38
  /**
46
- * Handle IP lookup with ResourceLink pattern
39
+ * Handle IP lookup with resource-link + text output consistency.
47
40
  */
48
41
  async function handleGetIpDetailsLink(args) {
49
42
  const methodLogger = logger.forMethod('handleGetIpDetailsLink');
50
43
  methodLogger.debug(`Getting IP address details link for ${args.ipAddress || 'current IP'}...`, args);
51
44
  try {
52
- // First, verify we can get the data
53
45
  const result = await ipaddress_controller_js_1.default.get(args);
54
- // Extract the actual IP from the result
55
- // The result.content includes the IP in TOON or JSON format
56
- const ipMatch = result.content.match(/query[:\s]+([0-9.]+)/);
57
- const actualIp = ipMatch?.[1] || args.ipAddress || 'current';
58
- methodLogger.debug(`IP resolved to: ${actualIp}`);
59
- // Return a ResourceLink instead of inline content
60
- // This tells the client to fetch the resource separately
46
+ const actualIp = result.resolvedIp ||
47
+ (typeof args.ipAddress === 'string' ? args.ipAddress : 'current');
48
+ methodLogger.debug(`Resolved IP for resource URI: ${actualIp}`);
49
+ const textContent = (0, formatter_util_js_1.truncateForAI)(result.content, result.rawResponsePath);
50
+ const mimeType = args.outputFormat === 'json' ? 'application/json' : 'text/plain';
61
51
  return {
62
52
  content: [
63
53
  {
64
- type: 'resource',
65
- resource: {
66
- uri: `ip://${actualIp}`,
67
- text: `IP lookup result available at resource ip://${actualIp}`,
68
- mimeType: 'text/markdown',
69
- },
54
+ type: 'text',
55
+ text: textContent,
56
+ },
57
+ {
58
+ type: 'resource_link',
59
+ uri: `ip://${actualIp}`,
60
+ name: `IP lookup ${actualIp}`,
61
+ description: `Resource link for IP lookup result ${actualIp}`,
62
+ mimeType,
70
63
  },
71
64
  ],
72
65
  };
@@ -50,4 +50,9 @@ export interface ControllerResponse {
50
50
  * When the response is truncated, this path allows AI to access the full data.
51
51
  */
52
52
  rawResponsePath?: string | null;
53
+ /**
54
+ * Canonical resolved IP from the upstream API response.
55
+ * Use this to avoid parsing formatted output when consumers need the queried IP value.
56
+ */
57
+ resolvedIp?: string;
53
58
  }
@@ -8,7 +8,7 @@
8
8
  * Current application version
9
9
  * This should match the version in package.json
10
10
  */
11
- export declare const VERSION = "3.0.0";
11
+ export declare const VERSION = "3.1.0";
12
12
  /**
13
13
  * Package name with scope
14
14
  * Used for initialization and identification
@@ -11,7 +11,7 @@ exports.CLI_NAME = exports.PACKAGE_NAME = exports.VERSION = void 0;
11
11
  * Current application version
12
12
  * This should match the version in package.json
13
13
  */
14
- exports.VERSION = '3.0.0';
14
+ exports.VERSION = '3.1.0';
15
15
  /**
16
16
  * Package name with scope
17
17
  * Used for initialization and identification
@@ -11,7 +11,7 @@ exports.CLI_NAME = exports.PACKAGE_NAME = exports.VERSION = void 0;
11
11
  * Current application version
12
12
  * This should match the version in package.json
13
13
  */
14
- exports.VERSION = '1.19.0';
14
+ exports.VERSION = '3.0.0';
15
15
  /**
16
16
  * Package name with scope
17
17
  * Used for initialization and identification
@@ -162,7 +162,7 @@ function createUserFriendlyErrorMessage(code, context = {}, originalMessage) {
162
162
  const entity = entityType
163
163
  ? `${entityType}${entityIdStr ? ` ${entityIdStr}` : ''}`
164
164
  : 'Resource';
165
- let message = '';
165
+ let message;
166
166
  switch (code) {
167
167
  case ErrorCode.NOT_FOUND:
168
168
  message = `${entity} not found${entityIdStr ? `: ${entityIdStr}` : ''}. Verify the ID is correct and that you have access to this ${entityType?.toLowerCase() || 'resource'}.`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aashari/boilerplate-mcp-server",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "TypeScript MCP server boilerplate with STDIO and HTTP transport support, CLI tools, and extensible architecture",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -14,28 +14,18 @@
14
14
  },
15
15
  "scripts": {
16
16
  "build": "tsc",
17
+ "clean": "rm -rf dist coverage",
17
18
  "prepare": "npm run build && node scripts/ensure-executable.js",
18
19
  "postinstall": "node scripts/ensure-executable.js",
19
- "clean": "rm -rf dist coverage",
20
+ "lint": "eslint src --ext .ts --config eslint.config.mjs",
21
+ "format": "prettier --write 'src/**/*.ts' 'scripts/**/*.js'",
20
22
  "test": "jest",
21
23
  "test:coverage": "jest --coverage",
22
24
  "test:cli": "jest src/cli/.*\\.cli\\.test\\.ts --runInBand --testTimeout=60000",
23
- "lint": "eslint src --ext .ts --config eslint.config.mjs",
24
- "format": "prettier --write 'src/**/*.ts' 'scripts/**/*.js'",
25
- "publish:npm": "npm publish",
26
- "update:check": "npx npm-check-updates",
27
- "update:deps": "npx npm-check-updates -u && npm install --legacy-peer-deps",
28
- "update:version": "node scripts/update-version.js",
25
+ "cli": "npm run build && node dist/index.js",
29
26
  "mcp:stdio": "TRANSPORT_MODE=stdio npm run build && node dist/index.js",
30
27
  "mcp:http": "TRANSPORT_MODE=http npm run build && node dist/index.js",
31
- "mcp:inspect": "TRANSPORT_MODE=http npm run build && (node dist/index.js &) && sleep 2 && npx @modelcontextprotocol/inspector http://localhost:3000/mcp",
32
- "dev:stdio": "npm run build && npx @modelcontextprotocol/inspector -e TRANSPORT_MODE=stdio -e DEBUG=true node dist/index.js",
33
- "dev:http": "DEBUG=true TRANSPORT_MODE=http npm run build && node dist/index.js",
34
- "dev:server": "DEBUG=true npm run build && npx @modelcontextprotocol/inspector -e DEBUG=true node dist/index.js",
35
- "dev:cli": "DEBUG=true npm run build && DEBUG=true node dist/index.js",
36
- "start:server": "npm run build && npx @modelcontextprotocol/inspector node dist/index.js",
37
- "start:cli": "npm run build && node dist/index.js",
38
- "cli": "npm run build && node dist/index.js"
28
+ "mcp:inspect": "TRANSPORT_MODE=http npm run build && (node dist/index.js &) && sleep 2 && npx @modelcontextprotocol/inspector http://localhost:3000/mcp"
39
29
  },
40
30
  "keywords": [
41
31
  "mcp",
@@ -56,42 +46,42 @@
56
46
  "author": "Andi Ashari",
57
47
  "license": "ISC",
58
48
  "engines": {
59
- "node": ">=18.0.0"
49
+ "node": ">=20.0.0"
60
50
  },
61
51
  "devDependencies": {
62
- "@eslint/js": "^9.39.1",
52
+ "@eslint/js": "^10.0.1",
63
53
  "@semantic-release/changelog": "^6.0.3",
64
54
  "@semantic-release/exec": "^7.1.0",
65
55
  "@semantic-release/git": "^10.0.1",
66
- "@semantic-release/github": "^12.0.2",
67
- "@semantic-release/npm": "^13.1.2",
56
+ "@semantic-release/github": "^12.0.6",
57
+ "@semantic-release/npm": "^13.1.4",
68
58
  "@types/cors": "^2.8.19",
69
- "@types/express": "^5.0.5",
59
+ "@types/express": "^5.0.6",
70
60
  "@types/jest": "^30.0.0",
71
61
  "@types/jmespath": "^0.15.2",
72
- "@types/node": "^24.10.10",
73
- "@typescript-eslint/eslint-plugin": "^8.48.0",
74
- "@typescript-eslint/parser": "^8.48.0",
75
- "eslint": "^9.39.1",
62
+ "@types/node": "^25.2.3",
63
+ "@typescript-eslint/eslint-plugin": "^8.56.0",
64
+ "@typescript-eslint/parser": "^8.56.0",
65
+ "eslint": "^10.0.0",
76
66
  "eslint-config-prettier": "^10.1.8",
77
67
  "eslint-plugin-filenames": "^1.3.2",
78
- "eslint-plugin-prettier": "^5.5.4",
68
+ "eslint-plugin-prettier": "^5.5.5",
79
69
  "jest": "^30.2.0",
80
70
  "nodemon": "^3.1.11",
81
- "npm-check-updates": "^19.1.2",
82
- "prettier": "^3.7.3",
83
- "semantic-release": "^25.0.2",
84
- "ts-jest": "^29.4.5",
71
+ "npm-check-updates": "^19.3.2",
72
+ "prettier": "^3.8.1",
73
+ "semantic-release": "^25.0.3",
74
+ "ts-jest": "^29.4.6",
85
75
  "ts-node": "^10.9.2",
86
76
  "typescript": "^5.9.3",
87
- "typescript-eslint": "^8.48.0"
77
+ "typescript-eslint": "^8.56.0"
88
78
  },
89
79
  "dependencies": {
90
- "@modelcontextprotocol/sdk": "^1.25.3",
80
+ "@modelcontextprotocol/sdk": "^1.26.0",
91
81
  "@toon-format/toon": "^2.1.0",
92
82
  "commander": "^14.0.3",
93
83
  "cors": "^2.8.6",
94
- "dotenv": "^17.2.3",
84
+ "dotenv": "^17.3.1",
95
85
  "express": "^5.2.1",
96
86
  "jmespath": "^0.16.0",
97
87
  "zod": "^4.3.6"
package/package.json.bak CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aashari/boilerplate-mcp-server",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "TypeScript MCP server boilerplate with STDIO and HTTP transport support, CLI tools, and extensible architecture",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -14,28 +14,18 @@
14
14
  },
15
15
  "scripts": {
16
16
  "build": "tsc",
17
+ "clean": "rm -rf dist coverage",
17
18
  "prepare": "npm run build && node scripts/ensure-executable.js",
18
19
  "postinstall": "node scripts/ensure-executable.js",
19
- "clean": "rm -rf dist coverage",
20
+ "lint": "eslint src --ext .ts --config eslint.config.mjs",
21
+ "format": "prettier --write 'src/**/*.ts' 'scripts/**/*.js'",
20
22
  "test": "jest",
21
23
  "test:coverage": "jest --coverage",
22
24
  "test:cli": "jest src/cli/.*\\.cli\\.test\\.ts --runInBand --testTimeout=60000",
23
- "lint": "eslint src --ext .ts --config eslint.config.mjs",
24
- "format": "prettier --write 'src/**/*.ts' 'scripts/**/*.js'",
25
- "publish:npm": "npm publish",
26
- "update:check": "npx npm-check-updates",
27
- "update:deps": "npx npm-check-updates -u && npm install --legacy-peer-deps",
28
- "update:version": "node scripts/update-version.js",
25
+ "cli": "npm run build && node dist/index.js",
29
26
  "mcp:stdio": "TRANSPORT_MODE=stdio npm run build && node dist/index.js",
30
27
  "mcp:http": "TRANSPORT_MODE=http npm run build && node dist/index.js",
31
- "mcp:inspect": "TRANSPORT_MODE=http npm run build && (node dist/index.js &) && sleep 2 && npx @modelcontextprotocol/inspector http://localhost:3000/mcp",
32
- "dev:stdio": "npm run build && npx @modelcontextprotocol/inspector -e TRANSPORT_MODE=stdio -e DEBUG=true node dist/index.js",
33
- "dev:http": "DEBUG=true TRANSPORT_MODE=http npm run build && node dist/index.js",
34
- "dev:server": "DEBUG=true npm run build && npx @modelcontextprotocol/inspector -e DEBUG=true node dist/index.js",
35
- "dev:cli": "DEBUG=true npm run build && DEBUG=true node dist/index.js",
36
- "start:server": "npm run build && npx @modelcontextprotocol/inspector node dist/index.js",
37
- "start:cli": "npm run build && node dist/index.js",
38
- "cli": "npm run build && node dist/index.js"
28
+ "mcp:inspect": "TRANSPORT_MODE=http npm run build && (node dist/index.js &) && sleep 2 && npx @modelcontextprotocol/inspector http://localhost:3000/mcp"
39
29
  },
40
30
  "keywords": [
41
31
  "mcp",
@@ -56,42 +46,42 @@
56
46
  "author": "Andi Ashari",
57
47
  "license": "ISC",
58
48
  "engines": {
59
- "node": ">=18.0.0"
49
+ "node": ">=20.0.0"
60
50
  },
61
51
  "devDependencies": {
62
- "@eslint/js": "^9.39.1",
52
+ "@eslint/js": "^10.0.1",
63
53
  "@semantic-release/changelog": "^6.0.3",
64
54
  "@semantic-release/exec": "^7.1.0",
65
55
  "@semantic-release/git": "^10.0.1",
66
- "@semantic-release/github": "^12.0.2",
67
- "@semantic-release/npm": "^13.1.2",
56
+ "@semantic-release/github": "^12.0.6",
57
+ "@semantic-release/npm": "^13.1.4",
68
58
  "@types/cors": "^2.8.19",
69
- "@types/express": "^5.0.5",
59
+ "@types/express": "^5.0.6",
70
60
  "@types/jest": "^30.0.0",
71
61
  "@types/jmespath": "^0.15.2",
72
- "@types/node": "^24.10.10",
73
- "@typescript-eslint/eslint-plugin": "^8.48.0",
74
- "@typescript-eslint/parser": "^8.48.0",
75
- "eslint": "^9.39.1",
62
+ "@types/node": "^25.2.3",
63
+ "@typescript-eslint/eslint-plugin": "^8.56.0",
64
+ "@typescript-eslint/parser": "^8.56.0",
65
+ "eslint": "^10.0.0",
76
66
  "eslint-config-prettier": "^10.1.8",
77
67
  "eslint-plugin-filenames": "^1.3.2",
78
- "eslint-plugin-prettier": "^5.5.4",
68
+ "eslint-plugin-prettier": "^5.5.5",
79
69
  "jest": "^30.2.0",
80
70
  "nodemon": "^3.1.11",
81
- "npm-check-updates": "^19.1.2",
82
- "prettier": "^3.7.3",
83
- "semantic-release": "^25.0.2",
84
- "ts-jest": "^29.4.5",
71
+ "npm-check-updates": "^19.3.2",
72
+ "prettier": "^3.8.1",
73
+ "semantic-release": "^25.0.3",
74
+ "ts-jest": "^29.4.6",
85
75
  "ts-node": "^10.9.2",
86
76
  "typescript": "^5.9.3",
87
- "typescript-eslint": "^8.48.0"
77
+ "typescript-eslint": "^8.56.0"
88
78
  },
89
79
  "dependencies": {
90
- "@modelcontextprotocol/sdk": "^1.25.3",
80
+ "@modelcontextprotocol/sdk": "^1.26.0",
91
81
  "@toon-format/toon": "^2.1.0",
92
82
  "commander": "^14.0.3",
93
83
  "cors": "^2.8.6",
94
- "dotenv": "^17.2.3",
84
+ "dotenv": "^17.3.1",
95
85
  "express": "^5.2.1",
96
86
  "jmespath": "^0.16.0",
97
87
  "zod": "^4.3.6"