@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 +5 -2
- package/CHANGELOG.md +7 -0
- package/README.md +0 -5
- package/dist/controllers/ipaddress.controller.js +2 -1
- package/dist/index.js +169 -29
- package/dist/tools/ipaddress-link.tool.js +26 -33
- package/dist/types/common.types.d.ts +5 -0
- package/dist/utils/constants.util.d.ts +1 -1
- package/dist/utils/constants.util.js +1 -1
- package/dist/utils/constants.util.js.bak +1 -1
- package/dist/utils/error-handler.util.js +1 -1
- package/package.json +23 -33
- package/package.json.bak +23 -33
package/.releaserc.json
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"branches": [
|
|
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
|
-
|
|
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
|
-
//
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
**
|
|
39
|
-
-
|
|
40
|
-
-
|
|
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
|
-
**
|
|
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
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
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: '
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
}
|
|
@@ -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.
|
|
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 = '
|
|
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.
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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": ">=
|
|
49
|
+
"node": ">=20.0.0"
|
|
60
50
|
},
|
|
61
51
|
"devDependencies": {
|
|
62
|
-
"@eslint/js": "^
|
|
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.
|
|
67
|
-
"@semantic-release/npm": "^13.1.
|
|
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.
|
|
59
|
+
"@types/express": "^5.0.6",
|
|
70
60
|
"@types/jest": "^30.0.0",
|
|
71
61
|
"@types/jmespath": "^0.15.2",
|
|
72
|
-
"@types/node": "^
|
|
73
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
74
|
-
"@typescript-eslint/parser": "^8.
|
|
75
|
-
"eslint": "^
|
|
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.
|
|
68
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
79
69
|
"jest": "^30.2.0",
|
|
80
70
|
"nodemon": "^3.1.11",
|
|
81
|
-
"npm-check-updates": "^19.
|
|
82
|
-
"prettier": "^3.
|
|
83
|
-
"semantic-release": "^25.0.
|
|
84
|
-
"ts-jest": "^29.4.
|
|
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.
|
|
77
|
+
"typescript-eslint": "^8.56.0"
|
|
88
78
|
},
|
|
89
79
|
"dependencies": {
|
|
90
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
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.
|
|
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": "
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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": ">=
|
|
49
|
+
"node": ">=20.0.0"
|
|
60
50
|
},
|
|
61
51
|
"devDependencies": {
|
|
62
|
-
"@eslint/js": "^
|
|
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.
|
|
67
|
-
"@semantic-release/npm": "^13.1.
|
|
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.
|
|
59
|
+
"@types/express": "^5.0.6",
|
|
70
60
|
"@types/jest": "^30.0.0",
|
|
71
61
|
"@types/jmespath": "^0.15.2",
|
|
72
|
-
"@types/node": "^
|
|
73
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
74
|
-
"@typescript-eslint/parser": "^8.
|
|
75
|
-
"eslint": "^
|
|
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.
|
|
68
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
79
69
|
"jest": "^30.2.0",
|
|
80
70
|
"nodemon": "^3.1.11",
|
|
81
|
-
"npm-check-updates": "^19.
|
|
82
|
-
"prettier": "^3.
|
|
83
|
-
"semantic-release": "^25.0.
|
|
84
|
-
"ts-jest": "^29.4.
|
|
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.
|
|
77
|
+
"typescript-eslint": "^8.56.0"
|
|
88
78
|
},
|
|
89
79
|
"dependencies": {
|
|
90
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
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.
|
|
84
|
+
"dotenv": "^17.3.1",
|
|
95
85
|
"express": "^5.2.1",
|
|
96
86
|
"jmespath": "^0.16.0",
|
|
97
87
|
"zod": "^4.3.6"
|