@aashari/boilerplate-mcp-server 1.0.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/.eslintrc.json +19 -0
- package/.gitkeep +0 -0
- package/.node-version +1 -0
- package/.releaserc.json +34 -0
- package/CHANGELOG.md +107 -0
- package/README.md +357 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +28 -0
- package/dist/cli/index.js.bak +28 -0
- package/dist/cli/ipaddress.cli.d.ts +10 -0
- package/dist/cli/ipaddress.cli.js +31 -0
- package/dist/controllers/ipaddress.controller.d.ts +7 -0
- package/dist/controllers/ipaddress.controller.js +33 -0
- package/dist/controllers/ipaddress.test.d.ts +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +88 -0
- package/dist/index.js.bak +88 -0
- package/dist/resources/ipaddress.resource.d.ts +10 -0
- package/dist/resources/ipaddress.resource.js +37 -0
- package/dist/services/vendor.ip-api.com.service.d.ts +6 -0
- package/dist/services/vendor.ip-api.com.service.js +43 -0
- package/dist/services/vendor.ip-api.com.test.d.ts +1 -0
- package/dist/services/vendor.ip-api.com.type.d.ts +16 -0
- package/dist/services/vendor.ip-api.com.type.js +2 -0
- package/dist/tools/ipaddress.tool.d.ts +6 -0
- package/dist/tools/ipaddress.tool.js +33 -0
- package/dist/tools/ipaddress.type.d.ts +10 -0
- package/dist/tools/ipaddress.type.js +8 -0
- package/dist/utils/config.util.d.ts +43 -0
- package/dist/utils/config.util.js +116 -0
- package/dist/utils/error.util.d.ts +62 -0
- package/dist/utils/error.util.js +112 -0
- package/dist/utils/error.util.test.d.ts +1 -0
- package/dist/utils/logger.util.d.ts +9 -0
- package/dist/utils/logger.util.js +44 -0
- package/eslint.config.mjs +46 -0
- package/jest.config.mjs +19 -0
- package/package.json +88 -0
- package/package.json.bak +88 -0
- package/scripts/package.json +3 -0
- package/scripts/update-version.js +202 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.McpError = exports.ErrorType = void 0;
|
|
4
|
+
exports.createAuthMissingError = createAuthMissingError;
|
|
5
|
+
exports.createAuthInvalidError = createAuthInvalidError;
|
|
6
|
+
exports.createApiError = createApiError;
|
|
7
|
+
exports.createUnexpectedError = createUnexpectedError;
|
|
8
|
+
exports.ensureMcpError = ensureMcpError;
|
|
9
|
+
exports.formatErrorForMcpTool = formatErrorForMcpTool;
|
|
10
|
+
exports.formatErrorForMcpResource = formatErrorForMcpResource;
|
|
11
|
+
exports.handleCliError = handleCliError;
|
|
12
|
+
const logger_util_js_1 = require("./logger.util.js");
|
|
13
|
+
/**
|
|
14
|
+
* Error types for classification
|
|
15
|
+
*/
|
|
16
|
+
var ErrorType;
|
|
17
|
+
(function (ErrorType) {
|
|
18
|
+
ErrorType["AUTH_MISSING"] = "AUTH_MISSING";
|
|
19
|
+
ErrorType["AUTH_INVALID"] = "AUTH_INVALID";
|
|
20
|
+
ErrorType["API_ERROR"] = "API_ERROR";
|
|
21
|
+
ErrorType["UNEXPECTED_ERROR"] = "UNEXPECTED_ERROR";
|
|
22
|
+
})(ErrorType || (exports.ErrorType = ErrorType = {}));
|
|
23
|
+
/**
|
|
24
|
+
* Custom error class with type classification
|
|
25
|
+
*/
|
|
26
|
+
class McpError extends Error {
|
|
27
|
+
constructor(message, type, statusCode, originalError) {
|
|
28
|
+
super(message);
|
|
29
|
+
this.name = 'McpError';
|
|
30
|
+
this.type = type;
|
|
31
|
+
this.statusCode = statusCode;
|
|
32
|
+
this.originalError = originalError;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.McpError = McpError;
|
|
36
|
+
/**
|
|
37
|
+
* Create an authentication missing error
|
|
38
|
+
*/
|
|
39
|
+
function createAuthMissingError(message = 'Authentication credentials are missing') {
|
|
40
|
+
return new McpError(message, ErrorType.AUTH_MISSING);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Create an authentication invalid error
|
|
44
|
+
*/
|
|
45
|
+
function createAuthInvalidError(message = 'Authentication credentials are invalid') {
|
|
46
|
+
return new McpError(message, ErrorType.AUTH_INVALID, 401);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Create an API error
|
|
50
|
+
*/
|
|
51
|
+
function createApiError(message, statusCode, originalError) {
|
|
52
|
+
return new McpError(message, ErrorType.API_ERROR, statusCode, originalError);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Create an unexpected error
|
|
56
|
+
*/
|
|
57
|
+
function createUnexpectedError(message = 'An unexpected error occurred', originalError) {
|
|
58
|
+
return new McpError(message, ErrorType.UNEXPECTED_ERROR, undefined, originalError);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Ensure an error is an McpError
|
|
62
|
+
*/
|
|
63
|
+
function ensureMcpError(error) {
|
|
64
|
+
if (error instanceof McpError) {
|
|
65
|
+
return error;
|
|
66
|
+
}
|
|
67
|
+
if (error instanceof Error) {
|
|
68
|
+
return createUnexpectedError(error.message, error);
|
|
69
|
+
}
|
|
70
|
+
return createUnexpectedError(String(error));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Format error for MCP tool response
|
|
74
|
+
*/
|
|
75
|
+
function formatErrorForMcpTool(error) {
|
|
76
|
+
const mcpError = ensureMcpError(error);
|
|
77
|
+
logger_util_js_1.logger.error(`[src/utils/error.util.ts@formatErrorForMcpTool] ${mcpError.type} error`, mcpError);
|
|
78
|
+
return {
|
|
79
|
+
content: [
|
|
80
|
+
{
|
|
81
|
+
type: 'text',
|
|
82
|
+
text: `Error: ${mcpError.message}`,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Format error for MCP resource response
|
|
89
|
+
*/
|
|
90
|
+
function formatErrorForMcpResource(error, uri) {
|
|
91
|
+
const mcpError = ensureMcpError(error);
|
|
92
|
+
logger_util_js_1.logger.error(`[src/utils/error.util.ts@formatErrorForMcpResource] ${mcpError.type} error`, mcpError);
|
|
93
|
+
return {
|
|
94
|
+
contents: [
|
|
95
|
+
{
|
|
96
|
+
uri,
|
|
97
|
+
text: `Error: ${mcpError.message}`,
|
|
98
|
+
mimeType: 'text/plain',
|
|
99
|
+
description: `Error: ${mcpError.type}`,
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Handle error in CLI context
|
|
106
|
+
*/
|
|
107
|
+
function handleCliError(error) {
|
|
108
|
+
const mcpError = ensureMcpError(error);
|
|
109
|
+
logger_util_js_1.logger.error(`[src/utils/error.util.ts@handleCliError] ${mcpError.type} error`, mcpError);
|
|
110
|
+
console.error(`Error: ${mcpError.message}`);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
declare class Logger {
|
|
2
|
+
_log(level: 'info' | 'warn' | 'error' | 'debug', message: string, ...args: unknown[]): void;
|
|
3
|
+
info(message: string, ...args: unknown[]): void;
|
|
4
|
+
warn(message: string, ...args: unknown[]): void;
|
|
5
|
+
error(message: string, ...args: unknown[]): void;
|
|
6
|
+
debug(message: string, ...args: unknown[]): void;
|
|
7
|
+
}
|
|
8
|
+
export declare const logger: Logger;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.logger = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Format a timestamp for logging
|
|
6
|
+
* @returns Formatted timestamp [HH:MM:SS]
|
|
7
|
+
*/
|
|
8
|
+
function getTimestamp() {
|
|
9
|
+
const now = new Date();
|
|
10
|
+
return `[${now.toISOString().split('T')[1].split('.')[0]}]`;
|
|
11
|
+
}
|
|
12
|
+
class Logger {
|
|
13
|
+
_log(level, message, ...args) {
|
|
14
|
+
// Skip debug messages if DEBUG is not set to true
|
|
15
|
+
if (level === 'debug' && process.env.DEBUG !== 'true') {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const timestamp = getTimestamp();
|
|
19
|
+
const prefix = `${timestamp} [${level.toUpperCase()}]`;
|
|
20
|
+
let logMessage = `${prefix} ${message}`;
|
|
21
|
+
if (args.length > 0) {
|
|
22
|
+
logMessage += ` ${args.map((arg) => JSON.stringify(arg)).join(' ')}`;
|
|
23
|
+
}
|
|
24
|
+
if (process.env.NODE_ENV === 'test') {
|
|
25
|
+
console[level](logMessage);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
console.error(logMessage);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
info(message, ...args) {
|
|
32
|
+
this._log('info', message, ...args);
|
|
33
|
+
}
|
|
34
|
+
warn(message, ...args) {
|
|
35
|
+
this._log('warn', message, ...args);
|
|
36
|
+
}
|
|
37
|
+
error(message, ...args) {
|
|
38
|
+
this._log('error', message, ...args);
|
|
39
|
+
}
|
|
40
|
+
debug(message, ...args) {
|
|
41
|
+
this._log('debug', message, ...args);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.logger = new Logger();
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import eslint from '@eslint/js';
|
|
2
|
+
import tseslint from 'typescript-eslint';
|
|
3
|
+
import prettierPlugin from 'eslint-plugin-prettier';
|
|
4
|
+
import eslintConfigPrettier from 'eslint-config-prettier';
|
|
5
|
+
|
|
6
|
+
export default tseslint.config(
|
|
7
|
+
{
|
|
8
|
+
ignores: ['node_modules/**', 'dist/**', 'examples/**'],
|
|
9
|
+
},
|
|
10
|
+
eslint.configs.recommended,
|
|
11
|
+
...tseslint.configs.recommended,
|
|
12
|
+
{
|
|
13
|
+
plugins: {
|
|
14
|
+
prettier: prettierPlugin,
|
|
15
|
+
},
|
|
16
|
+
rules: {
|
|
17
|
+
'prettier/prettier': 'error',
|
|
18
|
+
indent: ['error', 'tab', { SwitchCase: 1 }],
|
|
19
|
+
'@typescript-eslint/no-unused-vars': [
|
|
20
|
+
'error',
|
|
21
|
+
{ argsIgnorePattern: '^_' },
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
languageOptions: {
|
|
25
|
+
parserOptions: {
|
|
26
|
+
ecmaVersion: 'latest',
|
|
27
|
+
sourceType: 'module',
|
|
28
|
+
},
|
|
29
|
+
globals: {
|
|
30
|
+
node: 'readonly',
|
|
31
|
+
jest: 'readonly',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
// Special rules for test files
|
|
36
|
+
{
|
|
37
|
+
files: ['**/*.test.ts'],
|
|
38
|
+
rules: {
|
|
39
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
40
|
+
'@typescript-eslint/no-require-imports': 'off',
|
|
41
|
+
'@typescript-eslint/no-unsafe-function-type': 'off',
|
|
42
|
+
'@typescript-eslint/no-unused-vars': 'off',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
eslintConfigPrettier,
|
|
46
|
+
);
|
package/jest.config.mjs
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
|
2
|
+
export default {
|
|
3
|
+
preset: 'ts-jest',
|
|
4
|
+
testEnvironment: 'node',
|
|
5
|
+
testMatch: ['**/src/**/*.test.ts'],
|
|
6
|
+
transform: {
|
|
7
|
+
'^.+\\.tsx?$': [
|
|
8
|
+
'ts-jest',
|
|
9
|
+
{
|
|
10
|
+
useESM: true,
|
|
11
|
+
},
|
|
12
|
+
],
|
|
13
|
+
},
|
|
14
|
+
moduleNameMapper: {
|
|
15
|
+
'(.*)\\.(js|jsx)$': '$1',
|
|
16
|
+
},
|
|
17
|
+
extensionsToTreatAsEsm: ['.ts'],
|
|
18
|
+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
|
|
19
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aashari/boilerplate-mcp-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A TypeScript-based Model Context Protocol (MCP) server boilerplate for building AI-connected tools. Features IP lookup tools, CLI support, MCP Inspector integration, and extensible architecture for connecting Claude/Anthropic AI systems to external data sources.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/aashari/boilerplate-mcp-server.git"
|
|
11
|
+
},
|
|
12
|
+
"bin": {
|
|
13
|
+
"mcp-server": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"test": "jest",
|
|
18
|
+
"test:coverage": "jest --coverage",
|
|
19
|
+
"lint": "eslint src --ext .ts --config eslint.config.mjs",
|
|
20
|
+
"format": "prettier --write 'src/**/*.ts' 'scripts/**/*.js'",
|
|
21
|
+
"publish:npm": "npm publish",
|
|
22
|
+
"update:check": "npx npm-check-updates",
|
|
23
|
+
"update:deps": "npx npm-check-updates -u && npm install --legacy-peer-deps",
|
|
24
|
+
"update:version": "node scripts/update-version.js",
|
|
25
|
+
"start": "node dist/index.js",
|
|
26
|
+
"dev": "nodemon --watch src --ext ts --exec 'npm run build && npm start'",
|
|
27
|
+
"inspect": "npx @modelcontextprotocol/inspector node dist/index.js",
|
|
28
|
+
"inspect:debug": "npx @modelcontextprotocol/inspector -e DEBUG=true node dist/index.js"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"mcp",
|
|
32
|
+
"typescript",
|
|
33
|
+
"claude",
|
|
34
|
+
"anthropic",
|
|
35
|
+
"ai",
|
|
36
|
+
"boilerplate",
|
|
37
|
+
"server",
|
|
38
|
+
"model-context-protocol",
|
|
39
|
+
"tools",
|
|
40
|
+
"resources",
|
|
41
|
+
"tooling",
|
|
42
|
+
"ai-integration",
|
|
43
|
+
"mcp-server",
|
|
44
|
+
"llm",
|
|
45
|
+
"ai-connector",
|
|
46
|
+
"external-tools",
|
|
47
|
+
"cli",
|
|
48
|
+
"mcp-inspector"
|
|
49
|
+
],
|
|
50
|
+
"author": "",
|
|
51
|
+
"license": "ISC",
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@eslint/js": "^9.23.0",
|
|
54
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
55
|
+
"@semantic-release/exec": "^7.0.3",
|
|
56
|
+
"@semantic-release/git": "^10.0.1",
|
|
57
|
+
"@semantic-release/github": "^11.0.1",
|
|
58
|
+
"@semantic-release/npm": "^12.0.1",
|
|
59
|
+
"@types/jest": "^29.5.14",
|
|
60
|
+
"@types/node": "^22.13.11",
|
|
61
|
+
"@typescript-eslint/eslint-plugin": "^8.27.0",
|
|
62
|
+
"@typescript-eslint/parser": "^8.27.0",
|
|
63
|
+
"eslint": "^9.23.0",
|
|
64
|
+
"eslint-config-prettier": "^10.1.1",
|
|
65
|
+
"eslint-plugin-prettier": "^5.2.3",
|
|
66
|
+
"jest": "^29.7.0",
|
|
67
|
+
"nodemon": "^3.1.9",
|
|
68
|
+
"npm-check-updates": "^17.1.16",
|
|
69
|
+
"prettier": "^3.5.3",
|
|
70
|
+
"semantic-release": "^24.2.3",
|
|
71
|
+
"ts-jest": "^29.2.6",
|
|
72
|
+
"typescript": "^5.8.2",
|
|
73
|
+
"typescript-eslint": "^8.27.0"
|
|
74
|
+
},
|
|
75
|
+
"publishConfig": {
|
|
76
|
+
"registry": "https://registry.npmjs.org/",
|
|
77
|
+
"access": "public"
|
|
78
|
+
},
|
|
79
|
+
"dependencies": {
|
|
80
|
+
"commander": "^13.1.0",
|
|
81
|
+
"@modelcontextprotocol/sdk": "^1.7.0",
|
|
82
|
+
"dotenv": "^16.4.7",
|
|
83
|
+
"zod": "^3.24.2"
|
|
84
|
+
},
|
|
85
|
+
"directories": {
|
|
86
|
+
"example": "examples"
|
|
87
|
+
}
|
|
88
|
+
}
|
package/package.json.bak
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aashari/boilerplate-mcp-server",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "A TypeScript-based Model Context Protocol (MCP) server boilerplate for building AI-connected tools. Features IP lookup tools, CLI support, MCP Inspector integration, and extensible architecture for connecting Claude/Anthropic AI systems to external data sources.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/aashari/boilerplate-mcp-server.git"
|
|
11
|
+
},
|
|
12
|
+
"bin": {
|
|
13
|
+
"mcp-server": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"test": "jest",
|
|
18
|
+
"test:coverage": "jest --coverage",
|
|
19
|
+
"lint": "eslint src --ext .ts --config eslint.config.mjs",
|
|
20
|
+
"format": "prettier --write 'src/**/*.ts' 'scripts/**/*.js'",
|
|
21
|
+
"publish:npm": "npm publish",
|
|
22
|
+
"update:check": "npx npm-check-updates",
|
|
23
|
+
"update:deps": "npx npm-check-updates -u && npm install --legacy-peer-deps",
|
|
24
|
+
"update:version": "node scripts/update-version.js",
|
|
25
|
+
"start": "node dist/index.js",
|
|
26
|
+
"dev": "nodemon --watch src --ext ts --exec 'npm run build && npm start'",
|
|
27
|
+
"inspect": "npx @modelcontextprotocol/inspector node dist/index.js",
|
|
28
|
+
"inspect:debug": "npx @modelcontextprotocol/inspector -e DEBUG=true node dist/index.js"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"mcp",
|
|
32
|
+
"typescript",
|
|
33
|
+
"claude",
|
|
34
|
+
"anthropic",
|
|
35
|
+
"ai",
|
|
36
|
+
"boilerplate",
|
|
37
|
+
"server",
|
|
38
|
+
"model-context-protocol",
|
|
39
|
+
"tools",
|
|
40
|
+
"resources",
|
|
41
|
+
"tooling",
|
|
42
|
+
"ai-integration",
|
|
43
|
+
"mcp-server",
|
|
44
|
+
"llm",
|
|
45
|
+
"ai-connector",
|
|
46
|
+
"external-tools",
|
|
47
|
+
"cli",
|
|
48
|
+
"mcp-inspector"
|
|
49
|
+
],
|
|
50
|
+
"author": "",
|
|
51
|
+
"license": "ISC",
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@eslint/js": "^9.23.0",
|
|
54
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
55
|
+
"@semantic-release/exec": "^7.0.3",
|
|
56
|
+
"@semantic-release/git": "^10.0.1",
|
|
57
|
+
"@semantic-release/github": "^11.0.1",
|
|
58
|
+
"@semantic-release/npm": "^12.0.1",
|
|
59
|
+
"@types/jest": "^29.5.14",
|
|
60
|
+
"@types/node": "^22.13.11",
|
|
61
|
+
"@typescript-eslint/eslint-plugin": "^8.27.0",
|
|
62
|
+
"@typescript-eslint/parser": "^8.27.0",
|
|
63
|
+
"eslint": "^9.23.0",
|
|
64
|
+
"eslint-config-prettier": "^10.1.1",
|
|
65
|
+
"eslint-plugin-prettier": "^5.2.3",
|
|
66
|
+
"jest": "^29.7.0",
|
|
67
|
+
"nodemon": "^3.1.9",
|
|
68
|
+
"npm-check-updates": "^17.1.16",
|
|
69
|
+
"prettier": "^3.5.3",
|
|
70
|
+
"semantic-release": "^24.2.3",
|
|
71
|
+
"ts-jest": "^29.2.6",
|
|
72
|
+
"typescript": "^5.8.2",
|
|
73
|
+
"typescript-eslint": "^8.27.0"
|
|
74
|
+
},
|
|
75
|
+
"publishConfig": {
|
|
76
|
+
"registry": "https://registry.npmjs.org/",
|
|
77
|
+
"access": "public"
|
|
78
|
+
},
|
|
79
|
+
"dependencies": {
|
|
80
|
+
"commander": "^13.1.0",
|
|
81
|
+
"@modelcontextprotocol/sdk": "^1.7.0",
|
|
82
|
+
"dotenv": "^16.4.7",
|
|
83
|
+
"zod": "^3.24.2"
|
|
84
|
+
},
|
|
85
|
+
"directories": {
|
|
86
|
+
"example": "examples"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Script to update version numbers across the project
|
|
5
|
+
* Usage: node scripts/update-version.js [version] [options]
|
|
6
|
+
* Options:
|
|
7
|
+
* --dry-run Show what changes would be made without applying them
|
|
8
|
+
* --verbose Show detailed logging information
|
|
9
|
+
*
|
|
10
|
+
* If no version is provided, it will use the version from package.json
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import fs from 'fs';
|
|
14
|
+
import path from 'path';
|
|
15
|
+
import { fileURLToPath } from 'url';
|
|
16
|
+
|
|
17
|
+
// Get the directory name of the current module
|
|
18
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
19
|
+
const __dirname = path.dirname(__filename);
|
|
20
|
+
const rootDir = path.resolve(__dirname, '..');
|
|
21
|
+
|
|
22
|
+
// Parse command line arguments
|
|
23
|
+
const args = process.argv.slice(2);
|
|
24
|
+
const options = {
|
|
25
|
+
dryRun: args.includes('--dry-run'),
|
|
26
|
+
verbose: args.includes('--verbose'),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Get the version (first non-flag argument)
|
|
30
|
+
let newVersion = args.find((arg) => !arg.startsWith('--'));
|
|
31
|
+
|
|
32
|
+
// Log helper function
|
|
33
|
+
const log = (message, verbose = false) => {
|
|
34
|
+
if (!verbose || options.verbose) {
|
|
35
|
+
console.log(message);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// File paths that may contain version information
|
|
40
|
+
const versionFiles = [
|
|
41
|
+
{
|
|
42
|
+
path: path.join(rootDir, 'package.json'),
|
|
43
|
+
pattern: /"version": "([^"]*)"/,
|
|
44
|
+
replacement: (match, currentVersion) =>
|
|
45
|
+
match.replace(currentVersion, newVersion),
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
path: path.join(rootDir, 'src', 'cli', 'index.ts'),
|
|
49
|
+
pattern: /const VERSION = ['"]([^'"]*)['"]/,
|
|
50
|
+
replacement: (match, currentVersion) =>
|
|
51
|
+
match.replace(currentVersion, newVersion),
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
path: path.join(rootDir, 'src', 'index.ts'),
|
|
55
|
+
pattern: /version: ['"]([^'"]*)['"]/,
|
|
56
|
+
replacement: (match, currentVersion) =>
|
|
57
|
+
match.replace(currentVersion, newVersion),
|
|
58
|
+
},
|
|
59
|
+
// Also update the compiled JavaScript files if they exist
|
|
60
|
+
{
|
|
61
|
+
path: path.join(rootDir, 'dist', 'cli', 'index.js'),
|
|
62
|
+
pattern: /const VERSION = ['"]([^'"]*)['"]/,
|
|
63
|
+
replacement: (match, currentVersion) =>
|
|
64
|
+
match.replace(currentVersion, newVersion),
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
path: path.join(rootDir, 'dist', 'index.js'),
|
|
68
|
+
pattern: /version: ['"]([^'"]*)['"]/,
|
|
69
|
+
replacement: (match, currentVersion) =>
|
|
70
|
+
match.replace(currentVersion, newVersion),
|
|
71
|
+
},
|
|
72
|
+
// Additional files can be added here with their patterns and replacement logic
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Read the version from package.json
|
|
77
|
+
* @returns {string} The version from package.json
|
|
78
|
+
*/
|
|
79
|
+
function getPackageVersion() {
|
|
80
|
+
try {
|
|
81
|
+
const packageJsonPath = path.join(rootDir, 'package.json');
|
|
82
|
+
log(`Reading version from ${packageJsonPath}`, true);
|
|
83
|
+
|
|
84
|
+
const packageJson = JSON.parse(
|
|
85
|
+
fs.readFileSync(packageJsonPath, 'utf8'),
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
if (!packageJson.version) {
|
|
89
|
+
throw new Error('No version field found in package.json');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return packageJson.version;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error(`Error reading package.json: ${error.message}`);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Validate the semantic version format
|
|
101
|
+
* @param {string} version - The version to validate
|
|
102
|
+
* @returns {boolean} True if valid, throws error if invalid
|
|
103
|
+
*/
|
|
104
|
+
function validateVersion(version) {
|
|
105
|
+
// More comprehensive semver regex
|
|
106
|
+
const semverRegex =
|
|
107
|
+
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
|
|
108
|
+
|
|
109
|
+
if (!semverRegex.test(version)) {
|
|
110
|
+
throw new Error(
|
|
111
|
+
`Invalid version format: ${version}\nPlease use semantic versioning format (e.g., 1.2.3, 1.2.3-beta.1, etc.)`,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Update version in a specific file
|
|
120
|
+
* @param {Object} fileConfig - Configuration for the file to update
|
|
121
|
+
*/
|
|
122
|
+
function updateFileVersion(fileConfig) {
|
|
123
|
+
const { path: filePath, pattern, replacement } = fileConfig;
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
log(`Checking ${filePath}...`, true);
|
|
127
|
+
|
|
128
|
+
if (!fs.existsSync(filePath)) {
|
|
129
|
+
console.warn(`Warning: File not found: ${filePath}`);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Read file content
|
|
134
|
+
const fileContent = fs.readFileSync(filePath, 'utf8');
|
|
135
|
+
const match = fileContent.match(pattern);
|
|
136
|
+
|
|
137
|
+
if (!match) {
|
|
138
|
+
console.warn(`Warning: Version pattern not found in ${filePath}`);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const currentVersion = match[1];
|
|
143
|
+
if (currentVersion === newVersion) {
|
|
144
|
+
log(
|
|
145
|
+
`Version in ${path.basename(filePath)} is already ${newVersion}`,
|
|
146
|
+
true,
|
|
147
|
+
);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Create new content with the updated version
|
|
152
|
+
const updatedContent = fileContent.replace(pattern, replacement);
|
|
153
|
+
|
|
154
|
+
// Write the changes or log them in dry run mode
|
|
155
|
+
if (options.dryRun) {
|
|
156
|
+
log(
|
|
157
|
+
`Would update version in ${filePath} from ${currentVersion} to ${newVersion}`,
|
|
158
|
+
);
|
|
159
|
+
} else {
|
|
160
|
+
// Create a backup of the original file
|
|
161
|
+
fs.writeFileSync(`${filePath}.bak`, fileContent);
|
|
162
|
+
log(`Backup created: ${filePath}.bak`, true);
|
|
163
|
+
|
|
164
|
+
// Write the updated content
|
|
165
|
+
fs.writeFileSync(filePath, updatedContent);
|
|
166
|
+
log(
|
|
167
|
+
`Updated version in ${path.basename(filePath)} from ${currentVersion} to ${newVersion}`,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
} catch (error) {
|
|
171
|
+
console.error(`Error updating ${filePath}: ${error.message}`);
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Main execution
|
|
177
|
+
try {
|
|
178
|
+
// If no version specified, get from package.json
|
|
179
|
+
if (!newVersion) {
|
|
180
|
+
newVersion = getPackageVersion();
|
|
181
|
+
log(
|
|
182
|
+
`No version specified, using version from package.json: ${newVersion}`,
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Validate the version format
|
|
187
|
+
validateVersion(newVersion);
|
|
188
|
+
|
|
189
|
+
// Update all configured files
|
|
190
|
+
for (const fileConfig of versionFiles) {
|
|
191
|
+
updateFileVersion(fileConfig);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (options.dryRun) {
|
|
195
|
+
log(`\nDry run completed. No files were modified.`);
|
|
196
|
+
} else {
|
|
197
|
+
log(`\nVersion successfully updated to ${newVersion}`);
|
|
198
|
+
}
|
|
199
|
+
} catch (error) {
|
|
200
|
+
console.error(`\nVersion update failed: ${error.message}`);
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|