@aashari/boilerplate-mcp-server 3.1.0 → 3.2.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/CHANGELOG.md +7 -0
- package/README.md +16 -10
- package/SECURITY.md +2 -2
- package/dist/index.js +37 -3
- package/dist/tools/ipaddress-link.tool.js +6 -0
- package/dist/tools/ipaddress.tool.js +6 -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/docs/MCP-MODERNIZATION-RELEASE-RUNBOOK.md +306 -0
- package/package.json +1 -1
- package/package.json.bak +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [3.2.0](https://github.com/aashari/boilerplate-mcp-server/compare/v3.1.0...v3.2.0) (2026-02-17)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* harden HTTP transport security and add tool annotations ([5919f9f](https://github.com/aashari/boilerplate-mcp-server/commit/5919f9f4c1e416da1a6f5c9ce01174a56624ba90))
|
|
7
|
+
|
|
1
8
|
# [3.1.0](https://github.com/aashari/boilerplate-mcp-server/compare/v3.0.0...v3.1.0) (2026-02-17)
|
|
2
9
|
|
|
3
10
|
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ A production-ready foundation for developing custom Model Context Protocol (MCP)
|
|
|
5
5
|
[](https://www.npmjs.com/package/@aashari/boilerplate-mcp-server)
|
|
6
6
|
[](https://opensource.org/licenses/ISC)
|
|
7
7
|
|
|
8
|
-
> **Latest Update (Feb 2026)**: Updated to MCP SDK 1.
|
|
8
|
+
> **Latest Update (Feb 2026)**: Updated to MCP SDK 1.26.0 and Zod 4.3.6 with continued modern `registerTool` patterns and streamable HTTP improvements. See [docs/MODERNIZATION.md](docs/MODERNIZATION.md) for details.
|
|
9
9
|
|
|
10
10
|
## Features
|
|
11
11
|
|
|
@@ -18,7 +18,7 @@ A production-ready foundation for developing custom Model Context Protocol (MCP)
|
|
|
18
18
|
- **TOON Output Format**: Token-Oriented Object Notation for 30-60% fewer tokens than JSON
|
|
19
19
|
- **JMESPath Filtering**: Extract only needed fields from responses to reduce token costs
|
|
20
20
|
- **Raw Response Logging**: Automatic logging of large API responses to `/tmp/mcp/<project>/` with truncation guidance
|
|
21
|
-
- **Modern SDK**: Uses MCP SDK v1.
|
|
21
|
+
- **Modern SDK**: Uses MCP SDK v1.26.0 with `registerTool` API pattern (ready for v2 migration)
|
|
22
22
|
- **Complete IP Address Example**: Tools, resources, prompts, and CLI commands for IP geolocation
|
|
23
23
|
- **Comprehensive Testing**: Unit and integration tests with coverage reporting (47 tests passing)
|
|
24
24
|
- **Production Tooling**: ESLint, Prettier, semantic-release, and MCP Inspector integration
|
|
@@ -31,7 +31,7 @@ Model Context Protocol (MCP) is an open standard for securely connecting AI syst
|
|
|
31
31
|
|
|
32
32
|
## Prerequisites
|
|
33
33
|
|
|
34
|
-
- **Node.js** (>=
|
|
34
|
+
- **Node.js** (>=20.x): [Download](https://nodejs.org/)
|
|
35
35
|
- **Git**: For version control
|
|
36
36
|
|
|
37
37
|
## Quick Start
|
|
@@ -660,12 +660,18 @@ npm run cli -- get-ip-details 8.8.8.8 --jq "{ip: query, country: country}" # JM
|
|
|
660
660
|
|
|
661
661
|
**MCP Tools:**
|
|
662
662
|
- `ip_get_details` - IP geolocation lookup for AI assistants
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
663
|
+
- `ip_get_details_link` - Same lookup + resource link output for resource-aware clients
|
|
664
|
+
|
|
665
|
+
Both tools share the same parameters:
|
|
666
|
+
- `ipAddress` (optional): IP address to lookup (omit for current device's public IP)
|
|
667
|
+
- `includeExtendedData` (optional, default: `false`): Include ASN, host, organization data (requires API token)
|
|
668
|
+
- `useHttps` (optional, default: `true`): Use HTTPS for API calls
|
|
669
|
+
- `jq` (optional): JMESPath expression to filter/transform response
|
|
670
|
+
- `outputFormat` (optional, default: `"toon"`): Output format - "toon" or "json"
|
|
671
|
+
|
|
672
|
+
Output behavior:
|
|
673
|
+
- `ip_get_details`: returns one `text` content block
|
|
674
|
+
- `ip_get_details_link`: returns the same first `text` block plus a `resource_link` block (`ip://<resolved-ip>`)
|
|
669
675
|
|
|
670
676
|
**MCP Resources:**
|
|
671
677
|
- `ip://{ipAddress}` - IP details resource template (e.g., `ip://8.8.8.8`, `ip://1.1.1.1`)
|
|
@@ -713,7 +719,7 @@ PORT=3001 # Custom port
|
|
|
713
719
|
npm run cli -- your-command
|
|
714
720
|
npm run mcp:stdio # Test with MCP Inspector
|
|
715
721
|
```
|
|
716
|
-
4. **
|
|
722
|
+
4. **Release:** Push conventional commits to `main` and let semantic-release publish automatically via GitHub Actions (OIDC trusted publishing).
|
|
717
723
|
|
|
718
724
|
## Testing Strategy
|
|
719
725
|
|
package/SECURITY.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -24,6 +24,7 @@ const analysis_prompt_js_1 = __importDefault(require("./prompts/analysis.prompt.
|
|
|
24
24
|
const logger = logger_util_js_1.Logger.forContext('index.ts');
|
|
25
25
|
let serverInstance = null;
|
|
26
26
|
let transportInstance = null;
|
|
27
|
+
let httpServerInstance = null;
|
|
27
28
|
const httpSessions = new Map();
|
|
28
29
|
function createMcpServer() {
|
|
29
30
|
const server = new mcp_js_1.McpServer({
|
|
@@ -92,8 +93,10 @@ async function startServer(mode = 'stdio') {
|
|
|
92
93
|
const allowedOrigins = [
|
|
93
94
|
'http://localhost',
|
|
94
95
|
'http://127.0.0.1',
|
|
96
|
+
'http://[::1]',
|
|
95
97
|
'https://localhost',
|
|
96
98
|
'https://127.0.0.1',
|
|
99
|
+
'https://[::1]',
|
|
97
100
|
];
|
|
98
101
|
const isAllowed = allowedOrigins.some((allowed) => origin === allowed || origin.startsWith(`${allowed}:`));
|
|
99
102
|
if (!isAllowed) {
|
|
@@ -106,8 +109,8 @@ async function startServer(mode = 'stdio') {
|
|
|
106
109
|
}
|
|
107
110
|
next();
|
|
108
111
|
});
|
|
109
|
-
app.use((0, cors_1.default)());
|
|
110
|
-
app.use(express_1.default.json());
|
|
112
|
+
app.use((0, cors_1.default)({ origin: true }));
|
|
113
|
+
app.use(express_1.default.json({ limit: '1mb' }));
|
|
111
114
|
const mcpEndpoint = '/mcp';
|
|
112
115
|
serverLogger.debug(`MCP endpoint: ${mcpEndpoint}`);
|
|
113
116
|
// Handle MCP POST requests (initialize + normal RPC calls)
|
|
@@ -127,6 +130,7 @@ async function startServer(mode = 'stdio') {
|
|
|
127
130
|
});
|
|
128
131
|
return;
|
|
129
132
|
}
|
|
133
|
+
session.lastActivity = Date.now();
|
|
130
134
|
await session.transport.handleRequest(req, res, req.body);
|
|
131
135
|
return;
|
|
132
136
|
}
|
|
@@ -151,6 +155,7 @@ async function startServer(mode = 'stdio') {
|
|
|
151
155
|
httpSessions.set(newSessionId, {
|
|
152
156
|
server: sessionServer,
|
|
153
157
|
transport: sessionTransport,
|
|
158
|
+
lastActivity: Date.now(),
|
|
154
159
|
});
|
|
155
160
|
serverLogger.info(`Initialized HTTP MCP session ${newSessionId}`);
|
|
156
161
|
},
|
|
@@ -245,13 +250,33 @@ async function startServer(mode = 'stdio') {
|
|
|
245
250
|
const PORT = Number(process.env.PORT ?? 3000);
|
|
246
251
|
const HOST = '127.0.0.1'; // Explicit localhost binding for security
|
|
247
252
|
await new Promise((resolve) => {
|
|
248
|
-
app.listen(PORT, HOST, () => {
|
|
253
|
+
httpServerInstance = app.listen(PORT, HOST, () => {
|
|
249
254
|
serverLogger.info(`HTTP transport listening on http://${HOST}:${PORT}${mcpEndpoint}`);
|
|
250
255
|
serverLogger.info('Server bound to localhost only for security');
|
|
251
256
|
resolve();
|
|
252
257
|
});
|
|
253
258
|
});
|
|
259
|
+
// Reap idle sessions every 5 minutes (TTL: 30 minutes)
|
|
260
|
+
const SESSION_TTL_MS = 30 * 60 * 1000;
|
|
261
|
+
const REAP_INTERVAL_MS = 5 * 60 * 1000;
|
|
262
|
+
const reapInterval = setInterval(() => {
|
|
263
|
+
const now = Date.now();
|
|
264
|
+
for (const [sessionId, session] of httpSessions.entries()) {
|
|
265
|
+
if (now - session.lastActivity > SESSION_TTL_MS) {
|
|
266
|
+
serverLogger.info(`Reaping idle HTTP session ${sessionId}`);
|
|
267
|
+
httpSessions.delete(sessionId);
|
|
268
|
+
void session.transport
|
|
269
|
+
.close()
|
|
270
|
+
.catch((err) => serverLogger.debug(`Error closing transport for reaped session ${sessionId}`, err))
|
|
271
|
+
.then(() => session.server.close())
|
|
272
|
+
.catch((err) => serverLogger.debug(`Error closing server for reaped session ${sessionId}`, err));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}, REAP_INTERVAL_MS);
|
|
276
|
+
reapInterval.unref();
|
|
254
277
|
setupGracefulShutdown();
|
|
278
|
+
// HTTP mode uses per-session servers (managed in httpSessions map).
|
|
279
|
+
// Return a reference server for API compatibility; not connected to any transport.
|
|
255
280
|
return createMcpServer();
|
|
256
281
|
}
|
|
257
282
|
}
|
|
@@ -296,7 +321,11 @@ if (require.main === module) {
|
|
|
296
321
|
*/
|
|
297
322
|
function setupGracefulShutdown() {
|
|
298
323
|
const shutdownLogger = logger_util_js_1.Logger.forContext('index.ts', 'shutdown');
|
|
324
|
+
let shuttingDown = false;
|
|
299
325
|
const shutdown = async () => {
|
|
326
|
+
if (shuttingDown)
|
|
327
|
+
return;
|
|
328
|
+
shuttingDown = true;
|
|
300
329
|
try {
|
|
301
330
|
shutdownLogger.info('Shutting down gracefully...');
|
|
302
331
|
if (httpSessions.size > 0) {
|
|
@@ -317,6 +346,11 @@ function setupGracefulShutdown() {
|
|
|
317
346
|
}
|
|
318
347
|
}
|
|
319
348
|
httpSessions.clear();
|
|
349
|
+
if (httpServerInstance) {
|
|
350
|
+
await new Promise((resolve) => {
|
|
351
|
+
httpServerInstance.close(() => resolve());
|
|
352
|
+
});
|
|
353
|
+
}
|
|
320
354
|
if (transportInstance &&
|
|
321
355
|
'close' in transportInstance &&
|
|
322
356
|
typeof transportInstance.close === 'function') {
|
|
@@ -79,6 +79,12 @@ function registerTools(server) {
|
|
|
79
79
|
title: 'IP Address Lookup (ResourceLink)',
|
|
80
80
|
description: IP_GET_DETAILS_LINK_DESCRIPTION,
|
|
81
81
|
inputSchema: GetIpDetailsLinkToolSchema,
|
|
82
|
+
annotations: {
|
|
83
|
+
readOnlyHint: true,
|
|
84
|
+
destructiveHint: false,
|
|
85
|
+
idempotentHint: true,
|
|
86
|
+
openWorldHint: true,
|
|
87
|
+
},
|
|
82
88
|
}, handleGetIpDetailsLink);
|
|
83
89
|
methodLogger.debug('Successfully registered ip_get_details_link tool.');
|
|
84
90
|
}
|
|
@@ -93,6 +93,12 @@ function registerTools(server) {
|
|
|
93
93
|
title: 'IP Address Lookup',
|
|
94
94
|
description: IP_GET_DETAILS_DESCRIPTION,
|
|
95
95
|
inputSchema: GetIpDetailsToolSchema,
|
|
96
|
+
annotations: {
|
|
97
|
+
readOnlyHint: true,
|
|
98
|
+
destructiveHint: false,
|
|
99
|
+
idempotentHint: true,
|
|
100
|
+
openWorldHint: true,
|
|
101
|
+
},
|
|
96
102
|
}, handleGetIpDetails);
|
|
97
103
|
methodLogger.debug('Successfully registered ip_get_details tool.');
|
|
98
104
|
}
|
|
@@ -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.2.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 = '3.
|
|
14
|
+
exports.VERSION = '3.1.0';
|
|
15
15
|
/**
|
|
16
16
|
* Package name with scope
|
|
17
17
|
* Used for initialization and identification
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# MCP Modernization + Release Runbook
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
This runbook documents the exact modernization + release approach used in this repository so other MCP servers can follow the same pattern with predictable outcomes.
|
|
6
|
+
|
|
7
|
+
Scope covered:
|
|
8
|
+
|
|
9
|
+
- Baseline audit (history, diffs, dependencies, CI)
|
|
10
|
+
- Streamable HTTP transport hardening
|
|
11
|
+
- Tool input/output contract standardization
|
|
12
|
+
- Inspector-based validation
|
|
13
|
+
- Semantic-release driven publishing
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Case Study Window (This Repo)
|
|
18
|
+
|
|
19
|
+
Reference range analyzed:
|
|
20
|
+
|
|
21
|
+
- From: `v3.0.0` (`fadd464`)
|
|
22
|
+
- To: `HEAD` (`08f8a02`)
|
|
23
|
+
|
|
24
|
+
Key commits:
|
|
25
|
+
|
|
26
|
+
- `615b373` `feat: modernize HTTP transport and standardize MCP tool contracts`
|
|
27
|
+
- `287cb4c` `chore(release): 3.1.0 [skip ci]`
|
|
28
|
+
- `08f8a02` `docs: sync README and security guidance with current tooling`
|
|
29
|
+
|
|
30
|
+
### File-Level Change Summary (`v3.0.0..HEAD`)
|
|
31
|
+
|
|
32
|
+
- `.releaserc.json`
|
|
33
|
+
- `CHANGELOG.md`
|
|
34
|
+
- `README.md`
|
|
35
|
+
- `SECURITY.md`
|
|
36
|
+
- `package-lock.json`
|
|
37
|
+
- `package.json`
|
|
38
|
+
- `src/controllers/ipaddress.controller.ts`
|
|
39
|
+
- `src/index.ts`
|
|
40
|
+
- `src/tools/ipaddress-link.tool.ts`
|
|
41
|
+
- `src/types/common.types.ts`
|
|
42
|
+
- `src/utils/constants.util.ts`
|
|
43
|
+
- `src/utils/error-handler.util.ts`
|
|
44
|
+
|
|
45
|
+
High-impact deltas:
|
|
46
|
+
|
|
47
|
+
- `src/index.ts`: moved HTTP handling to session-aware streamable transport flow.
|
|
48
|
+
- `src/tools/ipaddress-link.tool.ts`: aligned input schema with `ip_get_details`, standardized output to `text` + `resource_link`.
|
|
49
|
+
- `src/controllers/ipaddress.controller.ts` + `src/types/common.types.ts`: exposed canonical `resolvedIp` to avoid parsing rendered output.
|
|
50
|
+
- `package.json` + `package-lock.json`: dependency upgrades and script surface simplification.
|
|
51
|
+
- `.releaserc.json`: added `src/utils/constants.util.ts` to git release assets to prevent version drift.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Phase 1: Baseline Audit
|
|
56
|
+
|
|
57
|
+
### 1.1 Capture release baseline
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
git tag --sort=-v:refname | head -n 10
|
|
61
|
+
git log --oneline --decorate vX.Y.Z..HEAD
|
|
62
|
+
git diff --name-status vX.Y.Z..HEAD
|
|
63
|
+
git diff --stat vX.Y.Z..HEAD
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 1.2 Validate release pipeline wiring
|
|
67
|
+
|
|
68
|
+
Check:
|
|
69
|
+
|
|
70
|
+
- `.releaserc.json`
|
|
71
|
+
- `.github/workflows/ci-semantic-release.yml`
|
|
72
|
+
- `package.json` `engines`, scripts, dependencies
|
|
73
|
+
|
|
74
|
+
Release prerequisites:
|
|
75
|
+
|
|
76
|
+
- Conventional commits
|
|
77
|
+
- Semantic-release workflow on push to `main`
|
|
78
|
+
- OIDC trusted publishing (no `NPM_TOKEN` required)
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Phase 2: Modernize Streamable HTTP Transport
|
|
83
|
+
|
|
84
|
+
## Problem Pattern
|
|
85
|
+
|
|
86
|
+
Stateless `StreamableHTTPServerTransport` reuse across requests causes failures after `initialize`.
|
|
87
|
+
|
|
88
|
+
## Correct Pattern
|
|
89
|
+
|
|
90
|
+
Use stateful session management:
|
|
91
|
+
|
|
92
|
+
- Create a transport on initialize
|
|
93
|
+
- Generate `Mcp-Session-Id`
|
|
94
|
+
- Store per-session `{ server, transport }`
|
|
95
|
+
- Route POST/GET/DELETE by session
|
|
96
|
+
- Cleanup on session close + process shutdown
|
|
97
|
+
|
|
98
|
+
## Implementation Checklist
|
|
99
|
+
|
|
100
|
+
- Add session map keyed by `Mcp-Session-Id`
|
|
101
|
+
- Validate initialize requests with `isInitializeRequest`
|
|
102
|
+
- Reject non-initialize requests without session header
|
|
103
|
+
- Implement:
|
|
104
|
+
- `POST /mcp` for initialize + rpc
|
|
105
|
+
- `GET /mcp` for SSE stream channel if used
|
|
106
|
+
- `DELETE /mcp` for session termination
|
|
107
|
+
- Add graceful shutdown over all sessions
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Phase 3: Standardize Tool Contracts
|
|
112
|
+
|
|
113
|
+
Target rule for related tools:
|
|
114
|
+
|
|
115
|
+
- Same input schema unless there is a strong functional reason to diverge.
|
|
116
|
+
- Same base output shape for primary payload.
|
|
117
|
+
- Additive behavior only where required (e.g., extra link item).
|
|
118
|
+
|
|
119
|
+
## Applied Pattern
|
|
120
|
+
|
|
121
|
+
For `ip_get_details` and `ip_get_details_link`:
|
|
122
|
+
|
|
123
|
+
- Input parity:
|
|
124
|
+
- `ipAddress`
|
|
125
|
+
- `includeExtendedData`
|
|
126
|
+
- `useHttps`
|
|
127
|
+
- `jq`
|
|
128
|
+
- `outputFormat`
|
|
129
|
+
- Output parity:
|
|
130
|
+
- First content block is always `text` from the same toon/json renderer.
|
|
131
|
+
- Link tool extension:
|
|
132
|
+
- Second block is `resource_link` (`ip://<resolved-ip>`).
|
|
133
|
+
|
|
134
|
+
## Critical anti-pattern to avoid
|
|
135
|
+
|
|
136
|
+
Do not parse rendered text (regex on TOON/JSON output) to recover structured fields.
|
|
137
|
+
|
|
138
|
+
Instead:
|
|
139
|
+
|
|
140
|
+
- expose canonical data from controller/service boundary (`resolvedIp`) and consume that.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Phase 4: Test Matrix (Required)
|
|
145
|
+
|
|
146
|
+
### 4.1 Static quality gates
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
npm run lint
|
|
150
|
+
npm run build
|
|
151
|
+
npm test -- --runInBand
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 4.2 Streamable HTTP protocol flow test (curl)
|
|
155
|
+
|
|
156
|
+
Required sequence:
|
|
157
|
+
|
|
158
|
+
1. `initialize`
|
|
159
|
+
2. `notifications/initialized`
|
|
160
|
+
3. `tools/list`
|
|
161
|
+
4. `tools/call`
|
|
162
|
+
|
|
163
|
+
Assertions:
|
|
164
|
+
|
|
165
|
+
- `initialize` -> `200`, has `mcp-session-id`
|
|
166
|
+
- `notifications/initialized` -> `202`
|
|
167
|
+
- `tools/list` -> `200`
|
|
168
|
+
- `tools/call` -> `200`
|
|
169
|
+
|
|
170
|
+
### 4.3 SDK client compatibility test
|
|
171
|
+
|
|
172
|
+
Use official transport:
|
|
173
|
+
|
|
174
|
+
- `StreamableHTTPClientTransport`
|
|
175
|
+
- `Client` from MCP TS SDK
|
|
176
|
+
|
|
177
|
+
Assertions:
|
|
178
|
+
|
|
179
|
+
- `connect()` succeeds
|
|
180
|
+
- `tools/list` succeeds
|
|
181
|
+
- representative `tools/call` succeeds
|
|
182
|
+
|
|
183
|
+
### 4.4 Inspector validation
|
|
184
|
+
|
|
185
|
+
- CLI check:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
npx @modelcontextprotocol/inspector --cli "http://127.0.0.1:PORT/mcp" --transport http --method tools/list
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
- UI check via proxy token URL.
|
|
192
|
+
|
|
193
|
+
For remote access:
|
|
194
|
+
|
|
195
|
+
- `HOST=0.0.0.0`
|
|
196
|
+
- `ALLOWED_ORIGINS` includes remote UI origin
|
|
197
|
+
- set `MCP_PROXY_FULL_ADDRESS` to reachable host:port
|
|
198
|
+
|
|
199
|
+
Security note: keep auth enabled (`MCP_PROXY_AUTH_TOKEN`), do not use `DANGEROUSLY_OMIT_AUTH`.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Phase 5: Semantic Release Procedure
|
|
204
|
+
|
|
205
|
+
### 5.1 Pre-release checks
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
git status --short
|
|
209
|
+
npm run lint && npm run build && npm test -- --runInBand
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### 5.2 Commit strategy
|
|
213
|
+
|
|
214
|
+
Use conventional commits:
|
|
215
|
+
|
|
216
|
+
- `fix:` -> patch
|
|
217
|
+
- `feat:` -> minor
|
|
218
|
+
- `feat!:` or `BREAKING CHANGE:` -> major
|
|
219
|
+
|
|
220
|
+
### 5.3 Push and monitor
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
git push origin main
|
|
224
|
+
gh run list --repo <owner>/<repo> --limit 5
|
|
225
|
+
gh run watch <run-id> --repo <owner>/<repo>
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### 5.4 Verify artifacts
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
git fetch --tags origin
|
|
232
|
+
git tag --sort=-v:refname | head
|
|
233
|
+
gh release list --repo <owner>/<repo> --limit 5
|
|
234
|
+
npm view <package-name> version
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Release Config Guardrails
|
|
240
|
+
|
|
241
|
+
### Guardrail 1: Keep version files aligned
|
|
242
|
+
|
|
243
|
+
If custom prepare scripts update files, ensure `@semantic-release/git` assets include them.
|
|
244
|
+
|
|
245
|
+
In this repo:
|
|
246
|
+
|
|
247
|
+
- `scripts/update-version.js` updates `src/utils/constants.util.ts`
|
|
248
|
+
- therefore `src/utils/constants.util.ts` must be in `.releaserc.json` git assets.
|
|
249
|
+
|
|
250
|
+
### Guardrail 2: Avoid script sprawl
|
|
251
|
+
|
|
252
|
+
Keep `package.json` scripts minimal and operationally relevant:
|
|
253
|
+
|
|
254
|
+
- build/lint/test/format
|
|
255
|
+
- core run paths (`cli`, `mcp:stdio`, `mcp:http`, `mcp:inspect`)
|
|
256
|
+
|
|
257
|
+
Remove duplicate aliases that do not add behavior.
|
|
258
|
+
|
|
259
|
+
### Guardrail 3: Update active docs only
|
|
260
|
+
|
|
261
|
+
When behavior changes, update:
|
|
262
|
+
|
|
263
|
+
- `README.md`
|
|
264
|
+
- `SECURITY.md`
|
|
265
|
+
- active setup docs
|
|
266
|
+
|
|
267
|
+
Do not rewrite historical/audit snapshots unless they claim current state.
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Reusable Execution Checklist
|
|
272
|
+
|
|
273
|
+
- [ ] Identify release baseline tag and commit window
|
|
274
|
+
- [ ] Review commit history + per-file diff stats
|
|
275
|
+
- [ ] Validate semantic-release + CI workflow config
|
|
276
|
+
- [ ] Modernize streamable HTTP transport to session-safe pattern
|
|
277
|
+
- [ ] Standardize related tool input/output contracts
|
|
278
|
+
- [ ] Remove output parsing hacks (regex/content scraping)
|
|
279
|
+
- [ ] Run lint/build/tests
|
|
280
|
+
- [ ] Run curl protocol flow tests
|
|
281
|
+
- [ ] Run official SDK client tests
|
|
282
|
+
- [ ] Run Inspector CLI + UI tests
|
|
283
|
+
- [ ] Commit with conventional commit type
|
|
284
|
+
- [ ] Push to `main`
|
|
285
|
+
- [ ] Watch semantic-release workflow to completion
|
|
286
|
+
- [ ] Verify git tag, GitHub release, npm version
|
|
287
|
+
- [ ] Sync active docs with final behavior
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Appendix: Commands Used in This Repo
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
# History/diff tracing
|
|
295
|
+
git log --oneline --decorate v3.0.0..HEAD
|
|
296
|
+
git diff --name-status v3.0.0..HEAD
|
|
297
|
+
git diff --stat v3.0.0..HEAD
|
|
298
|
+
|
|
299
|
+
# Semantic-release dry check (local repo URL fallback)
|
|
300
|
+
npx semantic-release --dry-run --no-ci --branches main \
|
|
301
|
+
--repository-url file:///absolute/path/to/repo \
|
|
302
|
+
--plugins @semantic-release/commit-analyzer @semantic-release/release-notes-generator
|
|
303
|
+
|
|
304
|
+
# Inspector CLI against streamable HTTP
|
|
305
|
+
npx @modelcontextprotocol/inspector --cli "http://127.0.0.1:3330/mcp" --transport http --method tools/list
|
|
306
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aashari/boilerplate-mcp-server",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.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",
|
package/package.json.bak
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",
|