├── .github ├── conventional-changelog.config.cjs ├── conventional-changelog.config.js └── workflows │ ├── pr-validation.yml │ ├── publish.yml │ └── refresh-badges.yml ├── .gitignore ├── CHANGELOG.md ├── Dockerfile ├── LICENSE ├── README.md ├── commitlint.config.js ├── package-lock.json ├── package.json ├── scripts └── build.js ├── smithery.yaml ├── src ├── index.ts ├── resources │ ├── config.md │ ├── examples.md │ └── response-format.md └── version.ts.template └── tsconfig.json /.github/conventional-changelog.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | types: [ 3 | { type: 'feat', section: 'Features', hidden: false }, 4 | { type: 'fix', section: 'Bug Fixes', hidden: false }, 5 | { type: 'chore', section: 'Maintenance', hidden: false }, 6 | { type: 'docs', section: 'Documentation', hidden: false }, 7 | { type: 'style', section: 'Styling', hidden: false }, 8 | { type: 'refactor', section: 'Code Refactoring', hidden: false }, 9 | { type: 'perf', section: 'Performance', hidden: false }, 10 | { type: 'test', section: 'Testing', hidden: false }, 11 | { type: 'ci', section: 'CI/CD', hidden: false }, 12 | { type: 'build', section: 'Build System', hidden: false } 13 | ], 14 | releaseRules: [ 15 | { type: 'feat', release: 'minor' }, 16 | { type: 'fix', release: 'patch' }, 17 | { type: 'perf', release: 'patch' }, 18 | { type: 'chore', release: 'patch' }, 19 | { type: 'docs', release: 'patch' }, 20 | { type: 'style', release: 'patch' }, 21 | { type: 'refactor', release: 'patch' }, 22 | { type: 'test', release: 'patch' }, 23 | { type: 'ci', release: 'patch' }, 24 | { type: 'build', release: 'patch' } 25 | ] 26 | }; 27 | -------------------------------------------------------------------------------- /.github/conventional-changelog.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | types: [ 3 | { type: 'feat', section: 'Features' }, 4 | { type: 'fix', section: 'Bug Fixes' }, 5 | { type: 'chore', section: 'Maintenance' }, 6 | { type: 'docs', section: 'Documentation' }, 7 | { type: 'style', section: 'Styling' }, 8 | { type: 'refactor', section: 'Code Refactoring' }, 9 | { type: 'perf', section: 'Performance' }, 10 | { type: 'test', section: 'Testing' }, 11 | { type: 'ci', section: 'CI/CD' }, 12 | { type: 'build', section: 'Build System' } 13 | ] 14 | }; 15 | -------------------------------------------------------------------------------- /.github/workflows/pr-validation.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request Validation 2 | 3 | on: 4 | pull_request: 5 | branches: [ main ] 6 | 7 | jobs: 8 | validate: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | with: 13 | fetch-depth: 0 14 | 15 | - name: Setup Node.js 16 | uses: actions/setup-node@v4 17 | with: 18 | node-version: '18' 19 | cache: 'npm' 20 | 21 | - name: Install dependencies 22 | run: npm ci 23 | 24 | - name: Validate Conventional Commits 25 | run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose 26 | 27 | - name: Build 28 | run: npm run build 29 | 30 | - name: Run Tests 31 | run: | 32 | if [ -f "package.json" ] && grep -q "\"test\":" "package.json"; then 33 | npm test 34 | else 35 | echo "No test script found in package.json" 36 | fi 37 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Package 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | workflow_dispatch: 7 | 8 | permissions: 9 | contents: write 10 | pull-requests: write 11 | 12 | jobs: 13 | publish: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | fetch-depth: 0 19 | 20 | - name: Setup Node.js 21 | uses: actions/setup-node@v4 22 | with: 23 | node-version: '18.x' 24 | registry-url: 'https://registry.npmjs.org' 25 | 26 | - name: Install dependencies 27 | run: npm ci 28 | 29 | - name: Conventional Changelog Action 30 | id: changelog 31 | uses: TriPSs/conventional-changelog-action@v6 32 | with: 33 | github-token: ${{ secrets.GITHUB_TOKEN }} 34 | git-message: 'chore(release): {version}' 35 | config-file-path: '.github/conventional-changelog.config.cjs' 36 | tag-prefix: 'v' 37 | output-file: 'CHANGELOG.md' 38 | skip-version-file: false 39 | skip-commit: false 40 | skip-on-empty: false 41 | git-user-name: ${{ secrets.CHANGELOG_GIT_NAME }} 42 | git-user-email: ${{ secrets.CHANGELOG_GIT_EMAIL }} 43 | 44 | - name: Build 45 | run: npm run build 46 | 47 | - name: Create Release 48 | if: steps.changelog.outputs.skipped == 'false' 49 | env: 50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 51 | run: | 52 | gh release create v${{ steps.changelog.outputs.version }} \ 53 | --title "Release v${{ steps.changelog.outputs.version }}" \ 54 | --notes "${{ steps.changelog.outputs.clean_changelog }}" 55 | 56 | - name: Publish to NPM 57 | if: steps.changelog.outputs.skipped == 'false' 58 | run: npm publish 59 | env: 60 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 61 | -------------------------------------------------------------------------------- /.github/workflows/refresh-badges.yml: -------------------------------------------------------------------------------- 1 | name: Refresh Badges 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' # Run at 00:00 UTC every day 6 | push: 7 | branches: 8 | - main 9 | workflow_dispatch: # Allow manual triggering 10 | 11 | jobs: 12 | refresh: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Refresh badges 16 | uses: b3b00/refreshBadgesAction@v1.0.7 17 | with: 18 | repository: 'zenturacp/mcp-rest-api' 19 | branch: 'main' 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | src/version.ts 4 | .DS_Store 5 | *.log 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.4.0](https://github.com/dkmaker/mcp-rest-api/compare/v0.3.0...v0.4.0) (2025-01-08) 2 | 3 | 4 | ### Features 5 | 6 | * add custom header support ([9a48e0d](https://github.com/dkmaker/mcp-rest-api/commit/9a48e0d794a743f7a62c7cb73d6f5b1be9e44107)) 7 | 8 | ## [0.3.0](https://github.com/dkmaker/mcp-rest-api/compare/v0.2.0...v0.3.0) (2024-12-28) 9 | 10 | 11 | ### Features 12 | 13 | * add config documentation and improve URL resolution examples ([8c6100f](https://github.com/dkmaker/mcp-rest-api/commit/8c6100f47777605a0571edbd161ffd20fc48b640)) 14 | * add MCP resources for documentation ([a20cf35](https://github.com/dkmaker/mcp-rest-api/commit/a20cf352e9731841a8d7e833007a96bdd1a0c390)) 15 | 16 | 17 | ### Bug Fixes 18 | 19 | * correct response truncation to return first N bytes ([ce34649](https://github.com/dkmaker/mcp-rest-api/commit/ce34649c4d8e6bc6d740e8f3fbc6e3df517e0eec)) 20 | 21 | ## [0.2.0](https://github.com/dkmaker/mcp-rest-api/compare/0fdbe844dd4ce8b79f38a33df323a29e28253724...v0.2.0) (2024-12-21) 22 | 23 | 24 | ### Features 25 | 26 | * **ssl:** add SSL verification control with secure defaults ([0fdbe84](https://github.com/dkmaker/mcp-rest-api/commit/0fdbe844dd4ce8b79f38a33df323a29e28253724)) 27 | 28 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile 2 | # Use the Node.js image with the required version for the project 3 | FROM node:18-alpine AS builder 4 | 5 | # Set working directory 6 | WORKDIR /app 7 | 8 | # Copy package files to the working directory 9 | COPY package.json package-lock.json ./ 10 | 11 | # Install dependencies 12 | RUN npm install 13 | 14 | # Copy all files to the working directory 15 | COPY . . 16 | 17 | # Build the TypeScript files 18 | RUN npm run build 19 | 20 | # Create the final release image 21 | FROM node:18-alpine AS release 22 | 23 | # Set working directory 24 | WORKDIR /app 25 | 26 | # Copy built files and necessary package information 27 | COPY --from=builder /app/build /app/build 28 | COPY --from=builder /app/package.json /app/package-lock.json /app/node_modules ./ 29 | 30 | # Environment configuration for runtime (configured externally) 31 | ENV REST_BASE_URL="" 32 | ENV AUTH_BASIC_USERNAME="" 33 | ENV AUTH_BASIC_PASSWORD="" 34 | ENV AUTH_BEARER="" 35 | ENV AUTH_APIKEY_HEADER_NAME="" 36 | ENV AUTH_APIKEY_VALUE="" 37 | ENV REST_ENABLE_SSL_VERIFY="true" 38 | ENV REST_RESPONSE_SIZE_LIMIT="10000" 39 | 40 | # Command to run the server 41 | ENTRYPOINT ["node", "build/index.js"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Christian Pedersen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MCP REST API Tester 2 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 3 | [![NPM Package](https://img.shields.io/npm/v/dkmaker-mcp-rest-api.svg)](https://www.npmjs.com/package/dkmaker-mcp-rest-api) 4 | [![smithery badge](https://smithery.ai/badge/dkmaker-mcp-rest-api)](https://smithery.ai/server/dkmaker-mcp-rest-api) 5 | 6 | A TypeScript-based MCP server that enables testing of REST APIs through Cline. This tool allows you to test and interact with any REST API endpoints directly from your development environment. 7 | 8 | 9 | 10 | 11 | 12 | ## Installation 13 | 14 | ### Installing via Smithery 15 | 16 | To install REST API Tester for Claude Desktop automatically via [Smithery](https://smithery.ai/server/dkmaker-mcp-rest-api): 17 | 18 | ```bash 19 | npx -y @smithery/cli install dkmaker-mcp-rest-api --client claude 20 | ``` 21 | 22 | ### Installing Manually 23 | 1. Install the package globally: 24 | ```bash 25 | npm install -g dkmaker-mcp-rest-api 26 | ``` 27 | 28 | 2. Configure Cline Custom Instructions: 29 | 30 | To ensure Cline understands how to effectively use this tool, add the following to your Cline custom instructions (Settings > Custom Instructions): 31 | 32 | ```markdown 33 | # REST API Testing Instructions 34 | 35 | The `test_request` tool enables testing, debugging, and interacting with REST API endpoints. The tool provides comprehensive request/response information and handles authentication automatically. 36 | 37 | ## When to Use 38 | 39 | - Testing specific API endpoints 40 | - Debugging API responses 41 | - Verifying API functionality 42 | - Checking response times 43 | - Validating request/response formats 44 | - Testing local development servers 45 | - Testing API sequences 46 | - Verifying error handling 47 | 48 | ## Key Features 49 | 50 | - Supports GET, POST, PUT, DELETE methods 51 | - Handles authentication (Basic, Bearer, API Key) 52 | - Normalizes endpoints automatically 53 | - Provides detailed response information 54 | - Configurable SSL verification and response limits 55 | 56 | ## Resources 57 | 58 | The following resources provide detailed documentation: 59 | 60 | - examples: Usage examples and common patterns 61 | - response-format: Response structure and fields 62 | - config: Configuration options and setup guide 63 | 64 | Access these resources to understand usage, response formats, and configuration options. 65 | 66 | ## Important Notes 67 | 68 | - Review API implementation for expected behavior 69 | - Handle sensitive data appropriately 70 | - Consider rate limits and API constraints 71 | - Restart server after configuration changes 72 | ``` 73 | 74 | 3. Add the server to your MCP configuration: 75 | 76 | While these instructions are for Cline, the server should work with any MCP implementation. Configure based on your operating system: 77 | 78 | ### Windows 79 | ⚠️ **IMPORTANT**: Due to a known issue with Windows path resolution ([issue #40](https://github.com/modelcontextprotocol/servers/issues/40)), you must use the full path instead of %APPDATA%. 80 | 81 | Add to `C:\Users\\AppData\Roaming\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json`: 82 | ```json 83 | { 84 | "mcpServers": { 85 | "rest-api": { 86 | "command": "node", 87 | "args": [ 88 | "C:/Users//AppData/Roaming/npm/node_modules/dkmaker-mcp-rest-api/build/index.js" 89 | ], 90 | "env": { 91 | "REST_BASE_URL": "https://api.example.com", 92 | // Basic Auth 93 | "AUTH_BASIC_USERNAME": "your-username", 94 | "AUTH_BASIC_PASSWORD": "your-password", 95 | // OR Bearer Token 96 | "AUTH_BEARER": "your-token", 97 | // OR API Key 98 | "AUTH_APIKEY_HEADER_NAME": "X-API-Key", 99 | "AUTH_APIKEY_VALUE": "your-api-key", 100 | // SSL Verification (enabled by default) 101 | "REST_ENABLE_SSL_VERIFY": "false", // Set to false to disable SSL verification for self-signed certificates 102 | // Response Size Limit (optional, defaults to 10000 bytes) 103 | "REST_RESPONSE_SIZE_LIMIT": "10000", // Maximum response size in bytes 104 | // Custom Headers (optional) 105 | "HEADER_X-API-Version": "2.0", 106 | "HEADER_Custom-Client": "my-client", 107 | "HEADER_Accept": "application/json" 108 | } 109 | } 110 | } 111 | } 112 | ``` 113 | 114 | ### macOS 115 | Add to `~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json`: 116 | ```json 117 | { 118 | "mcpServers": { 119 | "rest-api": { 120 | "command": "npx", 121 | "args": [ 122 | "-y", 123 | "dkmaker-mcp-rest-api" 124 | ], 125 | "env": { 126 | "REST_BASE_URL": "https://api.example.com", 127 | // Basic Auth 128 | "AUTH_BASIC_USERNAME": "your-username", 129 | "AUTH_BASIC_PASSWORD": "your-password", 130 | // OR Bearer Token 131 | "AUTH_BEARER": "your-token", 132 | // OR API Key 133 | "AUTH_APIKEY_HEADER_NAME": "X-API-Key", 134 | "AUTH_APIKEY_VALUE": "your-api-key", 135 | // SSL Verification (enabled by default) 136 | "REST_ENABLE_SSL_VERIFY": "false", // Set to false to disable SSL verification for self-signed certificates 137 | // Custom Headers (optional) 138 | "HEADER_X-API-Version": "2.0", 139 | "HEADER_Custom-Client": "my-client", 140 | "HEADER_Accept": "application/json" 141 | } 142 | } 143 | } 144 | } 145 | ``` 146 | 147 | Note: Replace the environment variables with your actual values. Only configure one authentication method at a time: 148 | 1. Basic Authentication (username/password) 149 | 2. Bearer Token (if Basic Auth is not configured) 150 | 3. API Key (if neither Basic Auth nor Bearer Token is configured) 151 | 152 | ## Features 153 | 154 | - Test REST API endpoints with different HTTP methods 155 | - Support for GET, POST, PUT, and DELETE requests 156 | - Detailed response information including status, headers, and body 157 | - Custom Headers: 158 | - Global headers via HEADER_* environment variables 159 | - Case-insensitive prefix (HEADER_, header_, HeAdEr_) 160 | - Case preservation for header names 161 | - Priority-based application (per-request > auth > custom) 162 | - Request body handling for POST/PUT methods 163 | - Response Size Management: 164 | - Automatic response size limiting (default: 10KB/10000 bytes) 165 | - Configurable size limit via REST_RESPONSE_SIZE_LIMIT environment variable 166 | - Clear truncation metadata when responses exceed limit 167 | - Preserves response structure while only truncating body content 168 | 169 | - SSL Certificate Verification: 170 | - Enabled by default for secure operation 171 | - Can be disabled for self-signed certificates or development environments 172 | - Control via REST_ENABLE_SSL_VERIFY environment variable 173 | - Multiple authentication methods: 174 | - Basic Authentication (username/password) 175 | - Bearer Token Authentication 176 | - API Key Authentication (custom header) 177 | 178 | ## Usage Examples 179 | 180 | Once installed and configured, you can use the REST API Tester through Cline to test your API endpoints: 181 | 182 | ```typescript 183 | // Test a GET endpoint 184 | use_mcp_tool('rest-api', 'test_request', { 185 | "method": "GET", 186 | "endpoint": "/users" 187 | }); 188 | 189 | // Test a POST endpoint with body 190 | use_mcp_tool('rest-api', 'test_request', { 191 | "method": "POST", 192 | "endpoint": "/users", 193 | "body": { 194 | "name": "John Doe", 195 | "email": "john@example.com" 196 | } 197 | }); 198 | 199 | // Test with custom headers 200 | use_mcp_tool('rest-api', 'test_request', { 201 | "method": "GET", 202 | "endpoint": "/products", 203 | "headers": { 204 | "Accept-Language": "en-US", 205 | "X-Custom-Header": "custom-value" 206 | } 207 | }); 208 | ``` 209 | 210 | ## Development 211 | 212 | 1. Clone the repository: 213 | ```bash 214 | git clone https://github.com/zenturacp/mcp-rest-api.git 215 | cd mcp-rest-api 216 | ``` 217 | 218 | 2. Install dependencies: 219 | ```bash 220 | npm install 221 | ``` 222 | 223 | 3. Build the project: 224 | ```bash 225 | npm run build 226 | ``` 227 | 228 | For development with auto-rebuild: 229 | ```bash 230 | npm run watch 231 | ``` 232 | 233 | ## License 234 | 235 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 236 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | extends: ['@commitlint/config-conventional'], 3 | rules: { 4 | 'type-enum': [ 5 | 2, 6 | 'always', 7 | [ 8 | 'build', 9 | 'chore', 10 | 'ci', 11 | 'docs', 12 | 'feat', 13 | 'fix', 14 | 'perf', 15 | 'refactor', 16 | 'revert', 17 | 'style', 18 | 'test' 19 | ] 20 | ], 21 | 'type-case': [2, 'always', 'lower-case'], 22 | 'type-empty': [2, 'never'], 23 | 'scope-case': [2, 'always', 'lower-case'], 24 | 'subject-case': [2, 'always', 'lower-case'], 25 | 'subject-empty': [2, 'never'], 26 | 'subject-full-stop': [2, 'never', '.'] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dkmaker-mcp-rest-api", 3 | "version": "0.4.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "dkmaker-mcp-rest-api", 9 | "version": "0.4.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@modelcontextprotocol/sdk": "^1.0.4", 13 | "axios": "^1.7.9" 14 | }, 15 | "bin": { 16 | "dkmaker-mcp-rest-api": "build/index.js" 17 | }, 18 | "devDependencies": { 19 | "@commitlint/cli": "^19.6.1", 20 | "@commitlint/config-conventional": "^19.6.0", 21 | "@types/node": "^20.11.24", 22 | "typescript": "^5.3.3" 23 | }, 24 | "engines": { 25 | "node": ">=18.0.0" 26 | } 27 | }, 28 | "node_modules/@babel/code-frame": { 29 | "version": "7.26.2", 30 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", 31 | "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", 32 | "dev": true, 33 | "license": "MIT", 34 | "dependencies": { 35 | "@babel/helper-validator-identifier": "^7.25.9", 36 | "js-tokens": "^4.0.0", 37 | "picocolors": "^1.0.0" 38 | }, 39 | "engines": { 40 | "node": ">=6.9.0" 41 | } 42 | }, 43 | "node_modules/@babel/helper-validator-identifier": { 44 | "version": "7.25.9", 45 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", 46 | "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", 47 | "dev": true, 48 | "license": "MIT", 49 | "engines": { 50 | "node": ">=6.9.0" 51 | } 52 | }, 53 | "node_modules/@commitlint/cli": { 54 | "version": "19.6.1", 55 | "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-19.6.1.tgz", 56 | "integrity": "sha512-8hcyA6ZoHwWXC76BoC8qVOSr8xHy00LZhZpauiD0iO0VYbVhMnED0da85lTfIULxl7Lj4c6vZgF0Wu/ed1+jlQ==", 57 | "dev": true, 58 | "license": "MIT", 59 | "dependencies": { 60 | "@commitlint/format": "^19.5.0", 61 | "@commitlint/lint": "^19.6.0", 62 | "@commitlint/load": "^19.6.1", 63 | "@commitlint/read": "^19.5.0", 64 | "@commitlint/types": "^19.5.0", 65 | "tinyexec": "^0.3.0", 66 | "yargs": "^17.0.0" 67 | }, 68 | "bin": { 69 | "commitlint": "cli.js" 70 | }, 71 | "engines": { 72 | "node": ">=v18" 73 | } 74 | }, 75 | "node_modules/@commitlint/config-conventional": { 76 | "version": "19.6.0", 77 | "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-19.6.0.tgz", 78 | "integrity": "sha512-DJT40iMnTYtBtUfw9ApbsLZFke1zKh6llITVJ+x9mtpHD08gsNXaIRqHTmwTZL3dNX5+WoyK7pCN/5zswvkBCQ==", 79 | "dev": true, 80 | "license": "MIT", 81 | "dependencies": { 82 | "@commitlint/types": "^19.5.0", 83 | "conventional-changelog-conventionalcommits": "^7.0.2" 84 | }, 85 | "engines": { 86 | "node": ">=v18" 87 | } 88 | }, 89 | "node_modules/@commitlint/config-validator": { 90 | "version": "19.5.0", 91 | "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.5.0.tgz", 92 | "integrity": "sha512-CHtj92H5rdhKt17RmgALhfQt95VayrUo2tSqY9g2w+laAXyk7K/Ef6uPm9tn5qSIwSmrLjKaXK9eiNuxmQrDBw==", 93 | "dev": true, 94 | "license": "MIT", 95 | "dependencies": { 96 | "@commitlint/types": "^19.5.0", 97 | "ajv": "^8.11.0" 98 | }, 99 | "engines": { 100 | "node": ">=v18" 101 | } 102 | }, 103 | "node_modules/@commitlint/ensure": { 104 | "version": "19.5.0", 105 | "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-19.5.0.tgz", 106 | "integrity": "sha512-Kv0pYZeMrdg48bHFEU5KKcccRfKmISSm9MvgIgkpI6m+ohFTB55qZlBW6eYqh/XDfRuIO0x4zSmvBjmOwWTwkg==", 107 | "dev": true, 108 | "license": "MIT", 109 | "dependencies": { 110 | "@commitlint/types": "^19.5.0", 111 | "lodash.camelcase": "^4.3.0", 112 | "lodash.kebabcase": "^4.1.1", 113 | "lodash.snakecase": "^4.1.1", 114 | "lodash.startcase": "^4.4.0", 115 | "lodash.upperfirst": "^4.3.1" 116 | }, 117 | "engines": { 118 | "node": ">=v18" 119 | } 120 | }, 121 | "node_modules/@commitlint/execute-rule": { 122 | "version": "19.5.0", 123 | "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-19.5.0.tgz", 124 | "integrity": "sha512-aqyGgytXhl2ejlk+/rfgtwpPexYyri4t8/n4ku6rRJoRhGZpLFMqrZ+YaubeGysCP6oz4mMA34YSTaSOKEeNrg==", 125 | "dev": true, 126 | "license": "MIT", 127 | "engines": { 128 | "node": ">=v18" 129 | } 130 | }, 131 | "node_modules/@commitlint/format": { 132 | "version": "19.5.0", 133 | "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-19.5.0.tgz", 134 | "integrity": "sha512-yNy088miE52stCI3dhG/vvxFo9e4jFkU1Mj3xECfzp/bIS/JUay4491huAlVcffOoMK1cd296q0W92NlER6r3A==", 135 | "dev": true, 136 | "license": "MIT", 137 | "dependencies": { 138 | "@commitlint/types": "^19.5.0", 139 | "chalk": "^5.3.0" 140 | }, 141 | "engines": { 142 | "node": ">=v18" 143 | } 144 | }, 145 | "node_modules/@commitlint/is-ignored": { 146 | "version": "19.6.0", 147 | "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-19.6.0.tgz", 148 | "integrity": "sha512-Ov6iBgxJQFR9koOupDPHvcHU9keFupDgtB3lObdEZDroiG4jj1rzky60fbQozFKVYRTUdrBGICHG0YVmRuAJmw==", 149 | "dev": true, 150 | "license": "MIT", 151 | "dependencies": { 152 | "@commitlint/types": "^19.5.0", 153 | "semver": "^7.6.0" 154 | }, 155 | "engines": { 156 | "node": ">=v18" 157 | } 158 | }, 159 | "node_modules/@commitlint/lint": { 160 | "version": "19.6.0", 161 | "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-19.6.0.tgz", 162 | "integrity": "sha512-LRo7zDkXtcIrpco9RnfhOKeg8PAnE3oDDoalnrVU/EVaKHYBWYL1DlRR7+3AWn0JiBqD8yKOfetVxJGdEtZ0tg==", 163 | "dev": true, 164 | "license": "MIT", 165 | "dependencies": { 166 | "@commitlint/is-ignored": "^19.6.0", 167 | "@commitlint/parse": "^19.5.0", 168 | "@commitlint/rules": "^19.6.0", 169 | "@commitlint/types": "^19.5.0" 170 | }, 171 | "engines": { 172 | "node": ">=v18" 173 | } 174 | }, 175 | "node_modules/@commitlint/load": { 176 | "version": "19.6.1", 177 | "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.6.1.tgz", 178 | "integrity": "sha512-kE4mRKWWNju2QpsCWt428XBvUH55OET2N4QKQ0bF85qS/XbsRGG1MiTByDNlEVpEPceMkDr46LNH95DtRwcsfA==", 179 | "dev": true, 180 | "license": "MIT", 181 | "dependencies": { 182 | "@commitlint/config-validator": "^19.5.0", 183 | "@commitlint/execute-rule": "^19.5.0", 184 | "@commitlint/resolve-extends": "^19.5.0", 185 | "@commitlint/types": "^19.5.0", 186 | "chalk": "^5.3.0", 187 | "cosmiconfig": "^9.0.0", 188 | "cosmiconfig-typescript-loader": "^6.1.0", 189 | "lodash.isplainobject": "^4.0.6", 190 | "lodash.merge": "^4.6.2", 191 | "lodash.uniq": "^4.5.0" 192 | }, 193 | "engines": { 194 | "node": ">=v18" 195 | } 196 | }, 197 | "node_modules/@commitlint/message": { 198 | "version": "19.5.0", 199 | "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-19.5.0.tgz", 200 | "integrity": "sha512-R7AM4YnbxN1Joj1tMfCyBryOC5aNJBdxadTZkuqtWi3Xj0kMdutq16XQwuoGbIzL2Pk62TALV1fZDCv36+JhTQ==", 201 | "dev": true, 202 | "license": "MIT", 203 | "engines": { 204 | "node": ">=v18" 205 | } 206 | }, 207 | "node_modules/@commitlint/parse": { 208 | "version": "19.5.0", 209 | "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-19.5.0.tgz", 210 | "integrity": "sha512-cZ/IxfAlfWYhAQV0TwcbdR1Oc0/r0Ik1GEessDJ3Lbuma/MRO8FRQX76eurcXtmhJC//rj52ZSZuXUg0oIX0Fw==", 211 | "dev": true, 212 | "license": "MIT", 213 | "dependencies": { 214 | "@commitlint/types": "^19.5.0", 215 | "conventional-changelog-angular": "^7.0.0", 216 | "conventional-commits-parser": "^5.0.0" 217 | }, 218 | "engines": { 219 | "node": ">=v18" 220 | } 221 | }, 222 | "node_modules/@commitlint/read": { 223 | "version": "19.5.0", 224 | "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-19.5.0.tgz", 225 | "integrity": "sha512-TjS3HLPsLsxFPQj6jou8/CZFAmOP2y+6V4PGYt3ihbQKTY1Jnv0QG28WRKl/d1ha6zLODPZqsxLEov52dhR9BQ==", 226 | "dev": true, 227 | "license": "MIT", 228 | "dependencies": { 229 | "@commitlint/top-level": "^19.5.0", 230 | "@commitlint/types": "^19.5.0", 231 | "git-raw-commits": "^4.0.0", 232 | "minimist": "^1.2.8", 233 | "tinyexec": "^0.3.0" 234 | }, 235 | "engines": { 236 | "node": ">=v18" 237 | } 238 | }, 239 | "node_modules/@commitlint/resolve-extends": { 240 | "version": "19.5.0", 241 | "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-19.5.0.tgz", 242 | "integrity": "sha512-CU/GscZhCUsJwcKTJS9Ndh3AKGZTNFIOoQB2n8CmFnizE0VnEuJoum+COW+C1lNABEeqk6ssfc1Kkalm4bDklA==", 243 | "dev": true, 244 | "license": "MIT", 245 | "dependencies": { 246 | "@commitlint/config-validator": "^19.5.0", 247 | "@commitlint/types": "^19.5.0", 248 | "global-directory": "^4.0.1", 249 | "import-meta-resolve": "^4.0.0", 250 | "lodash.mergewith": "^4.6.2", 251 | "resolve-from": "^5.0.0" 252 | }, 253 | "engines": { 254 | "node": ">=v18" 255 | } 256 | }, 257 | "node_modules/@commitlint/rules": { 258 | "version": "19.6.0", 259 | "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-19.6.0.tgz", 260 | "integrity": "sha512-1f2reW7lbrI0X0ozZMesS/WZxgPa4/wi56vFuJENBmed6mWq5KsheN/nxqnl/C23ioxpPO/PL6tXpiiFy5Bhjw==", 261 | "dev": true, 262 | "license": "MIT", 263 | "dependencies": { 264 | "@commitlint/ensure": "^19.5.0", 265 | "@commitlint/message": "^19.5.0", 266 | "@commitlint/to-lines": "^19.5.0", 267 | "@commitlint/types": "^19.5.0" 268 | }, 269 | "engines": { 270 | "node": ">=v18" 271 | } 272 | }, 273 | "node_modules/@commitlint/to-lines": { 274 | "version": "19.5.0", 275 | "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-19.5.0.tgz", 276 | "integrity": "sha512-R772oj3NHPkodOSRZ9bBVNq224DOxQtNef5Pl8l2M8ZnkkzQfeSTr4uxawV2Sd3ui05dUVzvLNnzenDBO1KBeQ==", 277 | "dev": true, 278 | "license": "MIT", 279 | "engines": { 280 | "node": ">=v18" 281 | } 282 | }, 283 | "node_modules/@commitlint/top-level": { 284 | "version": "19.5.0", 285 | "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-19.5.0.tgz", 286 | "integrity": "sha512-IP1YLmGAk0yWrImPRRc578I3dDUI5A2UBJx9FbSOjxe9sTlzFiwVJ+zeMLgAtHMtGZsC8LUnzmW1qRemkFU4ng==", 287 | "dev": true, 288 | "license": "MIT", 289 | "dependencies": { 290 | "find-up": "^7.0.0" 291 | }, 292 | "engines": { 293 | "node": ">=v18" 294 | } 295 | }, 296 | "node_modules/@commitlint/types": { 297 | "version": "19.5.0", 298 | "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-19.5.0.tgz", 299 | "integrity": "sha512-DSHae2obMSMkAtTBSOulg5X7/z+rGLxcXQIkg3OmWvY6wifojge5uVMydfhUvs7yQj+V7jNmRZ2Xzl8GJyqRgg==", 300 | "dev": true, 301 | "license": "MIT", 302 | "dependencies": { 303 | "@types/conventional-commits-parser": "^5.0.0", 304 | "chalk": "^5.3.0" 305 | }, 306 | "engines": { 307 | "node": ">=v18" 308 | } 309 | }, 310 | "node_modules/@modelcontextprotocol/sdk": { 311 | "version": "1.0.4", 312 | "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.0.4.tgz", 313 | "integrity": "sha512-C+jw1lF6HSGzs7EZpzHbXfzz9rj9him4BaoumlTciW/IDDgIpweF/qiCWKlP02QKg5PPcgY6xY2WCt5y2tpYow==", 314 | "license": "MIT", 315 | "dependencies": { 316 | "content-type": "^1.0.5", 317 | "raw-body": "^3.0.0", 318 | "zod": "^3.23.8" 319 | } 320 | }, 321 | "node_modules/@types/conventional-commits-parser": { 322 | "version": "5.0.1", 323 | "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.1.tgz", 324 | "integrity": "sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ==", 325 | "dev": true, 326 | "license": "MIT", 327 | "dependencies": { 328 | "@types/node": "*" 329 | } 330 | }, 331 | "node_modules/@types/node": { 332 | "version": "20.17.10", 333 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.10.tgz", 334 | "integrity": "sha512-/jrvh5h6NXhEauFFexRin69nA0uHJ5gwk4iDivp/DeoEua3uwCUto6PC86IpRITBOs4+6i2I56K5x5b6WYGXHA==", 335 | "dev": true, 336 | "license": "MIT", 337 | "dependencies": { 338 | "undici-types": "~6.19.2" 339 | } 340 | }, 341 | "node_modules/ajv": { 342 | "version": "8.17.1", 343 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", 344 | "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", 345 | "dev": true, 346 | "license": "MIT", 347 | "dependencies": { 348 | "fast-deep-equal": "^3.1.3", 349 | "fast-uri": "^3.0.1", 350 | "json-schema-traverse": "^1.0.0", 351 | "require-from-string": "^2.0.2" 352 | }, 353 | "funding": { 354 | "type": "github", 355 | "url": "https://github.com/sponsors/epoberezkin" 356 | } 357 | }, 358 | "node_modules/ansi-regex": { 359 | "version": "5.0.1", 360 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 361 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 362 | "dev": true, 363 | "license": "MIT", 364 | "engines": { 365 | "node": ">=8" 366 | } 367 | }, 368 | "node_modules/ansi-styles": { 369 | "version": "4.3.0", 370 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 371 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 372 | "dev": true, 373 | "license": "MIT", 374 | "dependencies": { 375 | "color-convert": "^2.0.1" 376 | }, 377 | "engines": { 378 | "node": ">=8" 379 | }, 380 | "funding": { 381 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 382 | } 383 | }, 384 | "node_modules/argparse": { 385 | "version": "2.0.1", 386 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 387 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 388 | "dev": true, 389 | "license": "Python-2.0" 390 | }, 391 | "node_modules/array-ify": { 392 | "version": "1.0.0", 393 | "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", 394 | "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", 395 | "dev": true, 396 | "license": "MIT" 397 | }, 398 | "node_modules/asynckit": { 399 | "version": "0.4.0", 400 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 401 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", 402 | "license": "MIT" 403 | }, 404 | "node_modules/axios": { 405 | "version": "1.7.9", 406 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", 407 | "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", 408 | "license": "MIT", 409 | "dependencies": { 410 | "follow-redirects": "^1.15.6", 411 | "form-data": "^4.0.0", 412 | "proxy-from-env": "^1.1.0" 413 | } 414 | }, 415 | "node_modules/bytes": { 416 | "version": "3.1.2", 417 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 418 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 419 | "license": "MIT", 420 | "engines": { 421 | "node": ">= 0.8" 422 | } 423 | }, 424 | "node_modules/callsites": { 425 | "version": "3.1.0", 426 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 427 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 428 | "dev": true, 429 | "license": "MIT", 430 | "engines": { 431 | "node": ">=6" 432 | } 433 | }, 434 | "node_modules/chalk": { 435 | "version": "5.4.1", 436 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", 437 | "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", 438 | "dev": true, 439 | "license": "MIT", 440 | "engines": { 441 | "node": "^12.17.0 || ^14.13 || >=16.0.0" 442 | }, 443 | "funding": { 444 | "url": "https://github.com/chalk/chalk?sponsor=1" 445 | } 446 | }, 447 | "node_modules/cliui": { 448 | "version": "8.0.1", 449 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", 450 | "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", 451 | "dev": true, 452 | "license": "ISC", 453 | "dependencies": { 454 | "string-width": "^4.2.0", 455 | "strip-ansi": "^6.0.1", 456 | "wrap-ansi": "^7.0.0" 457 | }, 458 | "engines": { 459 | "node": ">=12" 460 | } 461 | }, 462 | "node_modules/color-convert": { 463 | "version": "2.0.1", 464 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 465 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 466 | "dev": true, 467 | "license": "MIT", 468 | "dependencies": { 469 | "color-name": "~1.1.4" 470 | }, 471 | "engines": { 472 | "node": ">=7.0.0" 473 | } 474 | }, 475 | "node_modules/color-name": { 476 | "version": "1.1.4", 477 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 478 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 479 | "dev": true, 480 | "license": "MIT" 481 | }, 482 | "node_modules/combined-stream": { 483 | "version": "1.0.8", 484 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 485 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 486 | "license": "MIT", 487 | "dependencies": { 488 | "delayed-stream": "~1.0.0" 489 | }, 490 | "engines": { 491 | "node": ">= 0.8" 492 | } 493 | }, 494 | "node_modules/compare-func": { 495 | "version": "2.0.0", 496 | "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", 497 | "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", 498 | "dev": true, 499 | "license": "MIT", 500 | "dependencies": { 501 | "array-ify": "^1.0.0", 502 | "dot-prop": "^5.1.0" 503 | } 504 | }, 505 | "node_modules/content-type": { 506 | "version": "1.0.5", 507 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 508 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", 509 | "license": "MIT", 510 | "engines": { 511 | "node": ">= 0.6" 512 | } 513 | }, 514 | "node_modules/conventional-changelog-angular": { 515 | "version": "7.0.0", 516 | "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", 517 | "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", 518 | "dev": true, 519 | "license": "ISC", 520 | "dependencies": { 521 | "compare-func": "^2.0.0" 522 | }, 523 | "engines": { 524 | "node": ">=16" 525 | } 526 | }, 527 | "node_modules/conventional-changelog-conventionalcommits": { 528 | "version": "7.0.2", 529 | "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz", 530 | "integrity": "sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==", 531 | "dev": true, 532 | "license": "ISC", 533 | "dependencies": { 534 | "compare-func": "^2.0.0" 535 | }, 536 | "engines": { 537 | "node": ">=16" 538 | } 539 | }, 540 | "node_modules/conventional-commits-parser": { 541 | "version": "5.0.0", 542 | "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", 543 | "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", 544 | "dev": true, 545 | "license": "MIT", 546 | "dependencies": { 547 | "is-text-path": "^2.0.0", 548 | "JSONStream": "^1.3.5", 549 | "meow": "^12.0.1", 550 | "split2": "^4.0.0" 551 | }, 552 | "bin": { 553 | "conventional-commits-parser": "cli.mjs" 554 | }, 555 | "engines": { 556 | "node": ">=16" 557 | } 558 | }, 559 | "node_modules/cosmiconfig": { 560 | "version": "9.0.0", 561 | "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", 562 | "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", 563 | "dev": true, 564 | "license": "MIT", 565 | "dependencies": { 566 | "env-paths": "^2.2.1", 567 | "import-fresh": "^3.3.0", 568 | "js-yaml": "^4.1.0", 569 | "parse-json": "^5.2.0" 570 | }, 571 | "engines": { 572 | "node": ">=14" 573 | }, 574 | "funding": { 575 | "url": "https://github.com/sponsors/d-fischer" 576 | }, 577 | "peerDependencies": { 578 | "typescript": ">=4.9.5" 579 | }, 580 | "peerDependenciesMeta": { 581 | "typescript": { 582 | "optional": true 583 | } 584 | } 585 | }, 586 | "node_modules/cosmiconfig-typescript-loader": { 587 | "version": "6.1.0", 588 | "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.1.0.tgz", 589 | "integrity": "sha512-tJ1w35ZRUiM5FeTzT7DtYWAFFv37ZLqSRkGi2oeCK1gPhvaWjkAtfXvLmvE1pRfxxp9aQo6ba/Pvg1dKj05D4g==", 590 | "dev": true, 591 | "license": "MIT", 592 | "dependencies": { 593 | "jiti": "^2.4.1" 594 | }, 595 | "engines": { 596 | "node": ">=v18" 597 | }, 598 | "peerDependencies": { 599 | "@types/node": "*", 600 | "cosmiconfig": ">=9", 601 | "typescript": ">=5" 602 | } 603 | }, 604 | "node_modules/dargs": { 605 | "version": "8.1.0", 606 | "resolved": "https://registry.npmjs.org/dargs/-/dargs-8.1.0.tgz", 607 | "integrity": "sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==", 608 | "dev": true, 609 | "license": "MIT", 610 | "engines": { 611 | "node": ">=12" 612 | }, 613 | "funding": { 614 | "url": "https://github.com/sponsors/sindresorhus" 615 | } 616 | }, 617 | "node_modules/delayed-stream": { 618 | "version": "1.0.0", 619 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 620 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 621 | "license": "MIT", 622 | "engines": { 623 | "node": ">=0.4.0" 624 | } 625 | }, 626 | "node_modules/depd": { 627 | "version": "2.0.0", 628 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 629 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 630 | "license": "MIT", 631 | "engines": { 632 | "node": ">= 0.8" 633 | } 634 | }, 635 | "node_modules/dot-prop": { 636 | "version": "5.3.0", 637 | "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", 638 | "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", 639 | "dev": true, 640 | "license": "MIT", 641 | "dependencies": { 642 | "is-obj": "^2.0.0" 643 | }, 644 | "engines": { 645 | "node": ">=8" 646 | } 647 | }, 648 | "node_modules/emoji-regex": { 649 | "version": "8.0.0", 650 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 651 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 652 | "dev": true, 653 | "license": "MIT" 654 | }, 655 | "node_modules/env-paths": { 656 | "version": "2.2.1", 657 | "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", 658 | "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", 659 | "dev": true, 660 | "license": "MIT", 661 | "engines": { 662 | "node": ">=6" 663 | } 664 | }, 665 | "node_modules/error-ex": { 666 | "version": "1.3.2", 667 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", 668 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", 669 | "dev": true, 670 | "license": "MIT", 671 | "dependencies": { 672 | "is-arrayish": "^0.2.1" 673 | } 674 | }, 675 | "node_modules/escalade": { 676 | "version": "3.2.0", 677 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", 678 | "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", 679 | "dev": true, 680 | "license": "MIT", 681 | "engines": { 682 | "node": ">=6" 683 | } 684 | }, 685 | "node_modules/fast-deep-equal": { 686 | "version": "3.1.3", 687 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 688 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 689 | "dev": true, 690 | "license": "MIT" 691 | }, 692 | "node_modules/fast-uri": { 693 | "version": "3.0.6", 694 | "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", 695 | "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", 696 | "dev": true, 697 | "funding": [ 698 | { 699 | "type": "github", 700 | "url": "https://github.com/sponsors/fastify" 701 | }, 702 | { 703 | "type": "opencollective", 704 | "url": "https://opencollective.com/fastify" 705 | } 706 | ], 707 | "license": "BSD-3-Clause" 708 | }, 709 | "node_modules/find-up": { 710 | "version": "7.0.0", 711 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", 712 | "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", 713 | "dev": true, 714 | "license": "MIT", 715 | "dependencies": { 716 | "locate-path": "^7.2.0", 717 | "path-exists": "^5.0.0", 718 | "unicorn-magic": "^0.1.0" 719 | }, 720 | "engines": { 721 | "node": ">=18" 722 | }, 723 | "funding": { 724 | "url": "https://github.com/sponsors/sindresorhus" 725 | } 726 | }, 727 | "node_modules/follow-redirects": { 728 | "version": "1.15.9", 729 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", 730 | "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", 731 | "funding": [ 732 | { 733 | "type": "individual", 734 | "url": "https://github.com/sponsors/RubenVerborgh" 735 | } 736 | ], 737 | "license": "MIT", 738 | "engines": { 739 | "node": ">=4.0" 740 | }, 741 | "peerDependenciesMeta": { 742 | "debug": { 743 | "optional": true 744 | } 745 | } 746 | }, 747 | "node_modules/form-data": { 748 | "version": "4.0.1", 749 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", 750 | "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", 751 | "license": "MIT", 752 | "dependencies": { 753 | "asynckit": "^0.4.0", 754 | "combined-stream": "^1.0.8", 755 | "mime-types": "^2.1.12" 756 | }, 757 | "engines": { 758 | "node": ">= 6" 759 | } 760 | }, 761 | "node_modules/get-caller-file": { 762 | "version": "2.0.5", 763 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 764 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 765 | "dev": true, 766 | "license": "ISC", 767 | "engines": { 768 | "node": "6.* || 8.* || >= 10.*" 769 | } 770 | }, 771 | "node_modules/git-raw-commits": { 772 | "version": "4.0.0", 773 | "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz", 774 | "integrity": "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==", 775 | "dev": true, 776 | "license": "MIT", 777 | "dependencies": { 778 | "dargs": "^8.0.0", 779 | "meow": "^12.0.1", 780 | "split2": "^4.0.0" 781 | }, 782 | "bin": { 783 | "git-raw-commits": "cli.mjs" 784 | }, 785 | "engines": { 786 | "node": ">=16" 787 | } 788 | }, 789 | "node_modules/global-directory": { 790 | "version": "4.0.1", 791 | "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", 792 | "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", 793 | "dev": true, 794 | "license": "MIT", 795 | "dependencies": { 796 | "ini": "4.1.1" 797 | }, 798 | "engines": { 799 | "node": ">=18" 800 | }, 801 | "funding": { 802 | "url": "https://github.com/sponsors/sindresorhus" 803 | } 804 | }, 805 | "node_modules/http-errors": { 806 | "version": "2.0.0", 807 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 808 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 809 | "license": "MIT", 810 | "dependencies": { 811 | "depd": "2.0.0", 812 | "inherits": "2.0.4", 813 | "setprototypeof": "1.2.0", 814 | "statuses": "2.0.1", 815 | "toidentifier": "1.0.1" 816 | }, 817 | "engines": { 818 | "node": ">= 0.8" 819 | } 820 | }, 821 | "node_modules/iconv-lite": { 822 | "version": "0.6.3", 823 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", 824 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", 825 | "license": "MIT", 826 | "dependencies": { 827 | "safer-buffer": ">= 2.1.2 < 3.0.0" 828 | }, 829 | "engines": { 830 | "node": ">=0.10.0" 831 | } 832 | }, 833 | "node_modules/import-fresh": { 834 | "version": "3.3.0", 835 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 836 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 837 | "dev": true, 838 | "license": "MIT", 839 | "dependencies": { 840 | "parent-module": "^1.0.0", 841 | "resolve-from": "^4.0.0" 842 | }, 843 | "engines": { 844 | "node": ">=6" 845 | }, 846 | "funding": { 847 | "url": "https://github.com/sponsors/sindresorhus" 848 | } 849 | }, 850 | "node_modules/import-fresh/node_modules/resolve-from": { 851 | "version": "4.0.0", 852 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 853 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 854 | "dev": true, 855 | "license": "MIT", 856 | "engines": { 857 | "node": ">=4" 858 | } 859 | }, 860 | "node_modules/import-meta-resolve": { 861 | "version": "4.1.0", 862 | "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", 863 | "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", 864 | "dev": true, 865 | "license": "MIT", 866 | "funding": { 867 | "type": "github", 868 | "url": "https://github.com/sponsors/wooorm" 869 | } 870 | }, 871 | "node_modules/inherits": { 872 | "version": "2.0.4", 873 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 874 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 875 | "license": "ISC" 876 | }, 877 | "node_modules/ini": { 878 | "version": "4.1.1", 879 | "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", 880 | "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", 881 | "dev": true, 882 | "license": "ISC", 883 | "engines": { 884 | "node": "^14.17.0 || ^16.13.0 || >=18.0.0" 885 | } 886 | }, 887 | "node_modules/is-arrayish": { 888 | "version": "0.2.1", 889 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 890 | "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", 891 | "dev": true, 892 | "license": "MIT" 893 | }, 894 | "node_modules/is-fullwidth-code-point": { 895 | "version": "3.0.0", 896 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 897 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 898 | "dev": true, 899 | "license": "MIT", 900 | "engines": { 901 | "node": ">=8" 902 | } 903 | }, 904 | "node_modules/is-obj": { 905 | "version": "2.0.0", 906 | "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", 907 | "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", 908 | "dev": true, 909 | "license": "MIT", 910 | "engines": { 911 | "node": ">=8" 912 | } 913 | }, 914 | "node_modules/is-text-path": { 915 | "version": "2.0.0", 916 | "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", 917 | "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", 918 | "dev": true, 919 | "license": "MIT", 920 | "dependencies": { 921 | "text-extensions": "^2.0.0" 922 | }, 923 | "engines": { 924 | "node": ">=8" 925 | } 926 | }, 927 | "node_modules/jiti": { 928 | "version": "2.4.2", 929 | "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", 930 | "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", 931 | "dev": true, 932 | "license": "MIT", 933 | "bin": { 934 | "jiti": "lib/jiti-cli.mjs" 935 | } 936 | }, 937 | "node_modules/js-tokens": { 938 | "version": "4.0.0", 939 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 940 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 941 | "dev": true, 942 | "license": "MIT" 943 | }, 944 | "node_modules/js-yaml": { 945 | "version": "4.1.0", 946 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 947 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 948 | "dev": true, 949 | "license": "MIT", 950 | "dependencies": { 951 | "argparse": "^2.0.1" 952 | }, 953 | "bin": { 954 | "js-yaml": "bin/js-yaml.js" 955 | } 956 | }, 957 | "node_modules/json-parse-even-better-errors": { 958 | "version": "2.3.1", 959 | "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", 960 | "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", 961 | "dev": true, 962 | "license": "MIT" 963 | }, 964 | "node_modules/json-schema-traverse": { 965 | "version": "1.0.0", 966 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", 967 | "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", 968 | "dev": true, 969 | "license": "MIT" 970 | }, 971 | "node_modules/jsonparse": { 972 | "version": "1.3.1", 973 | "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", 974 | "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", 975 | "dev": true, 976 | "engines": [ 977 | "node >= 0.2.0" 978 | ], 979 | "license": "MIT" 980 | }, 981 | "node_modules/JSONStream": { 982 | "version": "1.3.5", 983 | "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", 984 | "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", 985 | "dev": true, 986 | "license": "(MIT OR Apache-2.0)", 987 | "dependencies": { 988 | "jsonparse": "^1.2.0", 989 | "through": ">=2.2.7 <3" 990 | }, 991 | "bin": { 992 | "JSONStream": "bin.js" 993 | }, 994 | "engines": { 995 | "node": "*" 996 | } 997 | }, 998 | "node_modules/lines-and-columns": { 999 | "version": "1.2.4", 1000 | "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", 1001 | "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", 1002 | "dev": true, 1003 | "license": "MIT" 1004 | }, 1005 | "node_modules/locate-path": { 1006 | "version": "7.2.0", 1007 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", 1008 | "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", 1009 | "dev": true, 1010 | "license": "MIT", 1011 | "dependencies": { 1012 | "p-locate": "^6.0.0" 1013 | }, 1014 | "engines": { 1015 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 1016 | }, 1017 | "funding": { 1018 | "url": "https://github.com/sponsors/sindresorhus" 1019 | } 1020 | }, 1021 | "node_modules/lodash.camelcase": { 1022 | "version": "4.3.0", 1023 | "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", 1024 | "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", 1025 | "dev": true, 1026 | "license": "MIT" 1027 | }, 1028 | "node_modules/lodash.isplainobject": { 1029 | "version": "4.0.6", 1030 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 1031 | "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", 1032 | "dev": true, 1033 | "license": "MIT" 1034 | }, 1035 | "node_modules/lodash.kebabcase": { 1036 | "version": "4.1.1", 1037 | "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", 1038 | "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", 1039 | "dev": true, 1040 | "license": "MIT" 1041 | }, 1042 | "node_modules/lodash.merge": { 1043 | "version": "4.6.2", 1044 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 1045 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", 1046 | "dev": true, 1047 | "license": "MIT" 1048 | }, 1049 | "node_modules/lodash.mergewith": { 1050 | "version": "4.6.2", 1051 | "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", 1052 | "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", 1053 | "dev": true, 1054 | "license": "MIT" 1055 | }, 1056 | "node_modules/lodash.snakecase": { 1057 | "version": "4.1.1", 1058 | "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", 1059 | "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", 1060 | "dev": true, 1061 | "license": "MIT" 1062 | }, 1063 | "node_modules/lodash.startcase": { 1064 | "version": "4.4.0", 1065 | "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", 1066 | "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", 1067 | "dev": true, 1068 | "license": "MIT" 1069 | }, 1070 | "node_modules/lodash.uniq": { 1071 | "version": "4.5.0", 1072 | "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", 1073 | "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", 1074 | "dev": true, 1075 | "license": "MIT" 1076 | }, 1077 | "node_modules/lodash.upperfirst": { 1078 | "version": "4.3.1", 1079 | "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", 1080 | "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", 1081 | "dev": true, 1082 | "license": "MIT" 1083 | }, 1084 | "node_modules/meow": { 1085 | "version": "12.1.1", 1086 | "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", 1087 | "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", 1088 | "dev": true, 1089 | "license": "MIT", 1090 | "engines": { 1091 | "node": ">=16.10" 1092 | }, 1093 | "funding": { 1094 | "url": "https://github.com/sponsors/sindresorhus" 1095 | } 1096 | }, 1097 | "node_modules/mime-db": { 1098 | "version": "1.52.0", 1099 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 1100 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 1101 | "license": "MIT", 1102 | "engines": { 1103 | "node": ">= 0.6" 1104 | } 1105 | }, 1106 | "node_modules/mime-types": { 1107 | "version": "2.1.35", 1108 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 1109 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 1110 | "license": "MIT", 1111 | "dependencies": { 1112 | "mime-db": "1.52.0" 1113 | }, 1114 | "engines": { 1115 | "node": ">= 0.6" 1116 | } 1117 | }, 1118 | "node_modules/minimist": { 1119 | "version": "1.2.8", 1120 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", 1121 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", 1122 | "dev": true, 1123 | "license": "MIT", 1124 | "funding": { 1125 | "url": "https://github.com/sponsors/ljharb" 1126 | } 1127 | }, 1128 | "node_modules/p-limit": { 1129 | "version": "4.0.0", 1130 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", 1131 | "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", 1132 | "dev": true, 1133 | "license": "MIT", 1134 | "dependencies": { 1135 | "yocto-queue": "^1.0.0" 1136 | }, 1137 | "engines": { 1138 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 1139 | }, 1140 | "funding": { 1141 | "url": "https://github.com/sponsors/sindresorhus" 1142 | } 1143 | }, 1144 | "node_modules/p-locate": { 1145 | "version": "6.0.0", 1146 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", 1147 | "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", 1148 | "dev": true, 1149 | "license": "MIT", 1150 | "dependencies": { 1151 | "p-limit": "^4.0.0" 1152 | }, 1153 | "engines": { 1154 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 1155 | }, 1156 | "funding": { 1157 | "url": "https://github.com/sponsors/sindresorhus" 1158 | } 1159 | }, 1160 | "node_modules/parent-module": { 1161 | "version": "1.0.1", 1162 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 1163 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 1164 | "dev": true, 1165 | "license": "MIT", 1166 | "dependencies": { 1167 | "callsites": "^3.0.0" 1168 | }, 1169 | "engines": { 1170 | "node": ">=6" 1171 | } 1172 | }, 1173 | "node_modules/parse-json": { 1174 | "version": "5.2.0", 1175 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", 1176 | "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", 1177 | "dev": true, 1178 | "license": "MIT", 1179 | "dependencies": { 1180 | "@babel/code-frame": "^7.0.0", 1181 | "error-ex": "^1.3.1", 1182 | "json-parse-even-better-errors": "^2.3.0", 1183 | "lines-and-columns": "^1.1.6" 1184 | }, 1185 | "engines": { 1186 | "node": ">=8" 1187 | }, 1188 | "funding": { 1189 | "url": "https://github.com/sponsors/sindresorhus" 1190 | } 1191 | }, 1192 | "node_modules/path-exists": { 1193 | "version": "5.0.0", 1194 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", 1195 | "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", 1196 | "dev": true, 1197 | "license": "MIT", 1198 | "engines": { 1199 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 1200 | } 1201 | }, 1202 | "node_modules/picocolors": { 1203 | "version": "1.1.1", 1204 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 1205 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 1206 | "dev": true, 1207 | "license": "ISC" 1208 | }, 1209 | "node_modules/proxy-from-env": { 1210 | "version": "1.1.0", 1211 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 1212 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", 1213 | "license": "MIT" 1214 | }, 1215 | "node_modules/raw-body": { 1216 | "version": "3.0.0", 1217 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", 1218 | "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", 1219 | "license": "MIT", 1220 | "dependencies": { 1221 | "bytes": "3.1.2", 1222 | "http-errors": "2.0.0", 1223 | "iconv-lite": "0.6.3", 1224 | "unpipe": "1.0.0" 1225 | }, 1226 | "engines": { 1227 | "node": ">= 0.8" 1228 | } 1229 | }, 1230 | "node_modules/require-directory": { 1231 | "version": "2.1.1", 1232 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 1233 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 1234 | "dev": true, 1235 | "license": "MIT", 1236 | "engines": { 1237 | "node": ">=0.10.0" 1238 | } 1239 | }, 1240 | "node_modules/require-from-string": { 1241 | "version": "2.0.2", 1242 | "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", 1243 | "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", 1244 | "dev": true, 1245 | "license": "MIT", 1246 | "engines": { 1247 | "node": ">=0.10.0" 1248 | } 1249 | }, 1250 | "node_modules/resolve-from": { 1251 | "version": "5.0.0", 1252 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", 1253 | "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", 1254 | "dev": true, 1255 | "license": "MIT", 1256 | "engines": { 1257 | "node": ">=8" 1258 | } 1259 | }, 1260 | "node_modules/safer-buffer": { 1261 | "version": "2.1.2", 1262 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1263 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 1264 | "license": "MIT" 1265 | }, 1266 | "node_modules/semver": { 1267 | "version": "7.7.0", 1268 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz", 1269 | "integrity": "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==", 1270 | "dev": true, 1271 | "license": "ISC", 1272 | "bin": { 1273 | "semver": "bin/semver.js" 1274 | }, 1275 | "engines": { 1276 | "node": ">=10" 1277 | } 1278 | }, 1279 | "node_modules/setprototypeof": { 1280 | "version": "1.2.0", 1281 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 1282 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", 1283 | "license": "ISC" 1284 | }, 1285 | "node_modules/split2": { 1286 | "version": "4.2.0", 1287 | "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", 1288 | "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", 1289 | "dev": true, 1290 | "license": "ISC", 1291 | "engines": { 1292 | "node": ">= 10.x" 1293 | } 1294 | }, 1295 | "node_modules/statuses": { 1296 | "version": "2.0.1", 1297 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 1298 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 1299 | "license": "MIT", 1300 | "engines": { 1301 | "node": ">= 0.8" 1302 | } 1303 | }, 1304 | "node_modules/string-width": { 1305 | "version": "4.2.3", 1306 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1307 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1308 | "dev": true, 1309 | "license": "MIT", 1310 | "dependencies": { 1311 | "emoji-regex": "^8.0.0", 1312 | "is-fullwidth-code-point": "^3.0.0", 1313 | "strip-ansi": "^6.0.1" 1314 | }, 1315 | "engines": { 1316 | "node": ">=8" 1317 | } 1318 | }, 1319 | "node_modules/strip-ansi": { 1320 | "version": "6.0.1", 1321 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1322 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1323 | "dev": true, 1324 | "license": "MIT", 1325 | "dependencies": { 1326 | "ansi-regex": "^5.0.1" 1327 | }, 1328 | "engines": { 1329 | "node": ">=8" 1330 | } 1331 | }, 1332 | "node_modules/text-extensions": { 1333 | "version": "2.4.0", 1334 | "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", 1335 | "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", 1336 | "dev": true, 1337 | "license": "MIT", 1338 | "engines": { 1339 | "node": ">=8" 1340 | }, 1341 | "funding": { 1342 | "url": "https://github.com/sponsors/sindresorhus" 1343 | } 1344 | }, 1345 | "node_modules/through": { 1346 | "version": "2.3.8", 1347 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1348 | "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", 1349 | "dev": true, 1350 | "license": "MIT" 1351 | }, 1352 | "node_modules/tinyexec": { 1353 | "version": "0.3.2", 1354 | "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", 1355 | "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", 1356 | "dev": true, 1357 | "license": "MIT" 1358 | }, 1359 | "node_modules/toidentifier": { 1360 | "version": "1.0.1", 1361 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 1362 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 1363 | "license": "MIT", 1364 | "engines": { 1365 | "node": ">=0.6" 1366 | } 1367 | }, 1368 | "node_modules/typescript": { 1369 | "version": "5.7.2", 1370 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", 1371 | "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", 1372 | "dev": true, 1373 | "license": "Apache-2.0", 1374 | "bin": { 1375 | "tsc": "bin/tsc", 1376 | "tsserver": "bin/tsserver" 1377 | }, 1378 | "engines": { 1379 | "node": ">=14.17" 1380 | } 1381 | }, 1382 | "node_modules/undici-types": { 1383 | "version": "6.19.8", 1384 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", 1385 | "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", 1386 | "dev": true, 1387 | "license": "MIT" 1388 | }, 1389 | "node_modules/unicorn-magic": { 1390 | "version": "0.1.0", 1391 | "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", 1392 | "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", 1393 | "dev": true, 1394 | "license": "MIT", 1395 | "engines": { 1396 | "node": ">=18" 1397 | }, 1398 | "funding": { 1399 | "url": "https://github.com/sponsors/sindresorhus" 1400 | } 1401 | }, 1402 | "node_modules/unpipe": { 1403 | "version": "1.0.0", 1404 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1405 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 1406 | "license": "MIT", 1407 | "engines": { 1408 | "node": ">= 0.8" 1409 | } 1410 | }, 1411 | "node_modules/wrap-ansi": { 1412 | "version": "7.0.0", 1413 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1414 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1415 | "dev": true, 1416 | "license": "MIT", 1417 | "dependencies": { 1418 | "ansi-styles": "^4.0.0", 1419 | "string-width": "^4.1.0", 1420 | "strip-ansi": "^6.0.0" 1421 | }, 1422 | "engines": { 1423 | "node": ">=10" 1424 | }, 1425 | "funding": { 1426 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 1427 | } 1428 | }, 1429 | "node_modules/y18n": { 1430 | "version": "5.0.8", 1431 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 1432 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 1433 | "dev": true, 1434 | "license": "ISC", 1435 | "engines": { 1436 | "node": ">=10" 1437 | } 1438 | }, 1439 | "node_modules/yargs": { 1440 | "version": "17.7.2", 1441 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", 1442 | "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", 1443 | "dev": true, 1444 | "license": "MIT", 1445 | "dependencies": { 1446 | "cliui": "^8.0.1", 1447 | "escalade": "^3.1.1", 1448 | "get-caller-file": "^2.0.5", 1449 | "require-directory": "^2.1.1", 1450 | "string-width": "^4.2.3", 1451 | "y18n": "^5.0.5", 1452 | "yargs-parser": "^21.1.1" 1453 | }, 1454 | "engines": { 1455 | "node": ">=12" 1456 | } 1457 | }, 1458 | "node_modules/yargs-parser": { 1459 | "version": "21.1.1", 1460 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", 1461 | "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", 1462 | "dev": true, 1463 | "license": "ISC", 1464 | "engines": { 1465 | "node": ">=12" 1466 | } 1467 | }, 1468 | "node_modules/yocto-queue": { 1469 | "version": "1.1.1", 1470 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", 1471 | "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", 1472 | "dev": true, 1473 | "license": "MIT", 1474 | "engines": { 1475 | "node": ">=12.20" 1476 | }, 1477 | "funding": { 1478 | "url": "https://github.com/sponsors/sindresorhus" 1479 | } 1480 | }, 1481 | "node_modules/zod": { 1482 | "version": "3.24.1", 1483 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", 1484 | "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", 1485 | "license": "MIT", 1486 | "funding": { 1487 | "url": "https://github.com/sponsors/colinhacks" 1488 | } 1489 | } 1490 | } 1491 | } 1492 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dkmaker-mcp-rest-api", 3 | "version": "0.4.0", 4 | "description": "A generic REST API tester for testing HTTP endpoints", 5 | "license": "MIT", 6 | "type": "module", 7 | "bin": { 8 | "dkmaker-mcp-rest-api": "./build/index.js" 9 | }, 10 | "files": [ 11 | "build", 12 | "README.md", 13 | "LICENSE" 14 | ], 15 | "scripts": { 16 | "prebuild": "node scripts/build.js", 17 | "build": "tsc", 18 | "prepare": "npm run build", 19 | "watch": "tsc --watch", 20 | "inspector": "npx @modelcontextprotocol/inspector build/index.js" 21 | }, 22 | "dependencies": { 23 | "@modelcontextprotocol/sdk": "^1.0.4", 24 | "axios": "^1.7.9" 25 | }, 26 | "devDependencies": { 27 | "@commitlint/cli": "^19.6.1", 28 | "@commitlint/config-conventional": "^19.6.0", 29 | "@types/node": "^20.11.24", 30 | "typescript": "^5.3.3" 31 | }, 32 | "keywords": [ 33 | "mcp", 34 | "rest", 35 | "api", 36 | "http", 37 | "testing", 38 | "cline", 39 | "development", 40 | "typescript" 41 | ], 42 | "author": "zenturacp", 43 | "repository": { 44 | "type": "git", 45 | "url": "git+https://github.com/dkmaker/mcp-rest-api.git" 46 | }, 47 | "bugs": { 48 | "url": "https://github.com/dkmaker/mcp-rest-api/issues" 49 | }, 50 | "homepage": "https://github.com/dkmaker/mcp-rest-api#readme", 51 | "engines": { 52 | "node": ">=18.0.0" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /scripts/build.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import fs from 'fs/promises'; 3 | import path from 'path'; 4 | import { fileURLToPath } from 'url'; 5 | 6 | const __filename = fileURLToPath(import.meta.url); 7 | const __dirname = path.dirname(__filename); 8 | 9 | async function main() { 10 | const pkg = JSON.parse( 11 | await fs.readFile( 12 | path.join(__dirname, '..', 'package.json'), 13 | 'utf8' 14 | ) 15 | ); 16 | 17 | const versionPath = path.join(__dirname, '..', 'src', 'version.ts'); 18 | 19 | // Always generate version.ts with actual values during build 20 | const content = `// Auto-generated by build script 21 | export const VERSION = '${pkg.version}'; 22 | export const PACKAGE_NAME = '${pkg.name}'; 23 | export const SERVER_NAME = '${pkg.name.split('-').slice(-2).join('-')}'; 24 | `; 25 | 26 | await fs.writeFile(versionPath, content); 27 | console.log('Generated version.ts with package values'); 28 | 29 | // Copy resources to build directory 30 | const resourcesSrcDir = path.join(__dirname, '..', 'src', 'resources'); 31 | const resourcesBuildDir = path.join(__dirname, '..', 'build', 'resources'); 32 | 33 | try { 34 | await fs.mkdir(resourcesBuildDir, { recursive: true }); 35 | const files = await fs.readdir(resourcesSrcDir); 36 | 37 | for (const file of files) { 38 | await fs.copyFile( 39 | path.join(resourcesSrcDir, file), 40 | path.join(resourcesBuildDir, file) 41 | ); 42 | } 43 | console.log('Copied resources to build directory'); 44 | } catch (error) { 45 | console.error('Error copying resources:', error); 46 | throw error; 47 | } 48 | } 49 | 50 | main().catch(console.error); 51 | -------------------------------------------------------------------------------- /smithery.yaml: -------------------------------------------------------------------------------- 1 | # Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml 2 | 3 | startCommand: 4 | type: stdio 5 | configSchema: 6 | # JSON Schema defining the configuration options for the MCP. 7 | type: object 8 | required: 9 | - restBaseUrl 10 | properties: 11 | restBaseUrl: 12 | type: string 13 | description: The base URL for the REST API. 14 | authBasicUsername: 15 | type: string 16 | description: The username for Basic Authentication. 17 | authBasicPassword: 18 | type: string 19 | description: The password for Basic Authentication. 20 | authBearer: 21 | type: string 22 | description: The bearer token for authentication. 23 | authApiKeyHeaderName: 24 | type: string 25 | description: The header name for API Key Authentication. 26 | authApiKeyValue: 27 | type: string 28 | description: The API key value for API Key Authentication. 29 | restEnableSslVerify: 30 | type: boolean 31 | default: true 32 | description: Enable or disable SSL verification. 33 | restResponseSizeLimit: 34 | type: number 35 | default: 10000 36 | description: The maximum response size limit in bytes. 37 | commandFunction: 38 | # A function that produces the CLI command to start the MCP on stdio. 39 | |- 40 | config => ({ command: 'node', args: ['build/index.js'], env: { REST_BASE_URL: config.restBaseUrl, AUTH_BASIC_USERNAME: config.authBasicUsername, AUTH_BASIC_PASSWORD: config.authBasicPassword, AUTH_BEARER: config.authBearer, AUTH_APIKEY_HEADER_NAME: config.authApiKeyHeaderName, AUTH_APIKEY_VALUE: config.authApiKeyValue, REST_ENABLE_SSL_VERIFY: config.restEnableSslVerify.toString(), REST_RESPONSE_SIZE_LIMIT: config.restResponseSizeLimit.toString() } }) -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import { Server } from '@modelcontextprotocol/sdk/server/index.js'; 3 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; 4 | import { 5 | CallToolRequestSchema, 6 | ErrorCode, 7 | ListToolsRequestSchema, 8 | ListResourcesRequestSchema, 9 | ReadResourceRequestSchema, 10 | McpError, 11 | } from '@modelcontextprotocol/sdk/types.js'; 12 | import axios, { AxiosInstance, AxiosRequestConfig, Method } from 'axios'; 13 | import { VERSION, SERVER_NAME } from './version.js'; 14 | 15 | if (!process.env.REST_BASE_URL) { 16 | throw new Error('REST_BASE_URL environment variable is required'); 17 | } 18 | 19 | // Default response size limit: 10KB (10000 bytes) 20 | const RESPONSE_SIZE_LIMIT = process.env.REST_RESPONSE_SIZE_LIMIT 21 | ? parseInt(process.env.REST_RESPONSE_SIZE_LIMIT, 10) 22 | : 10000; 23 | 24 | if (isNaN(RESPONSE_SIZE_LIMIT) || RESPONSE_SIZE_LIMIT <= 0) { 25 | throw new Error('REST_RESPONSE_SIZE_LIMIT must be a positive number'); 26 | } 27 | const AUTH_BASIC_USERNAME = process.env.AUTH_BASIC_USERNAME; 28 | const AUTH_BASIC_PASSWORD = process.env.AUTH_BASIC_PASSWORD; 29 | const AUTH_BEARER = process.env.AUTH_BEARER; 30 | const AUTH_APIKEY_HEADER_NAME = process.env.AUTH_APIKEY_HEADER_NAME; 31 | const AUTH_APIKEY_VALUE = process.env.AUTH_APIKEY_VALUE; 32 | const REST_ENABLE_SSL_VERIFY = process.env.REST_ENABLE_SSL_VERIFY !== 'false'; 33 | 34 | interface EndpointArgs { 35 | method: 'GET' | 'POST' | 'PUT' | 'DELETE'; 36 | endpoint: string; 37 | body?: any; 38 | headers?: Record; 39 | } 40 | 41 | interface ValidationResult { 42 | isError: boolean; 43 | messages: string[]; 44 | truncated?: { 45 | originalSize: number; 46 | returnedSize: number; 47 | truncationPoint: number; 48 | sizeLimit: number; 49 | }; 50 | } 51 | 52 | // Function to sanitize headers by removing sensitive values and non-approved headers 53 | const sanitizeHeaders = ( 54 | headers: Record, 55 | isFromOptionalParams: boolean = false 56 | ): Record => { 57 | const sanitized: Record = {}; 58 | 59 | for (const [key, value] of Object.entries(headers)) { 60 | const lowerKey = key.toLowerCase(); 61 | 62 | // Always include headers from optional parameters 63 | if (isFromOptionalParams) { 64 | sanitized[key] = value; 65 | continue; 66 | } 67 | 68 | // Handle authentication headers 69 | if ( 70 | lowerKey === 'authorization' || 71 | (AUTH_APIKEY_HEADER_NAME && lowerKey === AUTH_APIKEY_HEADER_NAME.toLowerCase()) 72 | ) { 73 | sanitized[key] = '[REDACTED]'; 74 | continue; 75 | } 76 | 77 | // For headers from config/env 78 | const customHeaders = getCustomHeaders(); 79 | if (key in customHeaders) { 80 | // Show value only for headers that are in the approved list 81 | const safeHeaders = new Set([ 82 | 'accept', 83 | 'accept-language', 84 | 'content-type', 85 | 'user-agent', 86 | 'cache-control', 87 | 'if-match', 88 | 'if-none-match', 89 | 'if-modified-since', 90 | 'if-unmodified-since' 91 | ]); 92 | const lowerKey = key.toLowerCase(); 93 | sanitized[key] = safeHeaders.has(lowerKey) ? value : '[REDACTED]'; 94 | } 95 | } 96 | 97 | return sanitized; 98 | }; 99 | 100 | interface ResponseObject { 101 | request: { 102 | url: string; 103 | method: string; 104 | headers: Record; 105 | body: any; 106 | authMethod: string; 107 | }; 108 | response: { 109 | statusCode: number; 110 | statusText: string; 111 | timing: string; 112 | headers: Record; 113 | body: any; 114 | }; 115 | validation: ValidationResult; 116 | } 117 | 118 | const normalizeBaseUrl = (url: string): string => url.replace(/\/+$/, ''); 119 | 120 | const isValidEndpointArgs = (args: any): args is EndpointArgs => { 121 | if (typeof args !== 'object' || args === null) return false; 122 | if (!['GET', 'POST', 'PUT', 'DELETE'].includes(args.method)) return false; 123 | if (typeof args.endpoint !== 'string') return false; 124 | if (args.headers !== undefined && (typeof args.headers !== 'object' || args.headers === null)) return false; 125 | 126 | // Check if endpoint contains a full URL 127 | const urlPattern = /^(https?:\/\/|www\.)/i; 128 | if (urlPattern.test(args.endpoint)) { 129 | throw new McpError( 130 | ErrorCode.InvalidParams, 131 | `Invalid endpoint format. Do not include full URLs. Instead of "${args.endpoint}", use just the path (e.g. "/api/users"). ` + 132 | `Your path will be resolved to: ${process.env.REST_BASE_URL}${args.endpoint.replace(/^\/+|\/+$/g, '')}. ` + 133 | `To test a different base URL, update the REST_BASE_URL environment variable.` 134 | ); 135 | } 136 | 137 | return true; 138 | }; 139 | 140 | const hasBasicAuth = () => AUTH_BASIC_USERNAME && AUTH_BASIC_PASSWORD; 141 | const hasBearerAuth = () => !!AUTH_BEARER; 142 | const hasApiKeyAuth = () => AUTH_APIKEY_HEADER_NAME && AUTH_APIKEY_VALUE; 143 | 144 | // Collect custom headers from environment variables 145 | const getCustomHeaders = (): Record => { 146 | const headers: Record = {}; 147 | const headerPrefix = /^header_/i; // Case-insensitive match for 'header_' 148 | 149 | for (const [key, value] of Object.entries(process.env)) { 150 | if (headerPrefix.test(key) && value !== undefined) { 151 | // Extract header name after the prefix, preserving case 152 | const headerName = key.replace(headerPrefix, ''); 153 | headers[headerName] = value; 154 | } 155 | } 156 | 157 | return headers; 158 | }; 159 | 160 | class RestTester { 161 | private server!: Server; 162 | private axiosInstance!: AxiosInstance; 163 | 164 | constructor() { 165 | this.setupServer(); 166 | } 167 | 168 | private async setupServer() { 169 | this.server = new Server( 170 | { 171 | name: SERVER_NAME, 172 | version: VERSION, 173 | }, 174 | { 175 | capabilities: { 176 | tools: {}, 177 | resources: {}, 178 | }, 179 | } 180 | ); 181 | 182 | const https = await import('https'); 183 | this.axiosInstance = axios.create({ 184 | baseURL: normalizeBaseUrl(process.env.REST_BASE_URL!), 185 | validateStatus: () => true, // Allow any status code 186 | httpsAgent: REST_ENABLE_SSL_VERIFY ? undefined : new https.Agent({ // Disable SSL verification only when explicitly set to false 187 | rejectUnauthorized: false 188 | }) 189 | }); 190 | 191 | this.setupToolHandlers(); 192 | this.setupResourceHandlers(); 193 | 194 | this.server.onerror = (error) => console.error('[MCP Error]', error); 195 | process.on('SIGINT', async () => { 196 | await this.server.close(); 197 | process.exit(0); 198 | }); 199 | } 200 | 201 | private setupResourceHandlers() { 202 | this.server.setRequestHandler(ListResourcesRequestSchema, async () => ({ 203 | resources: [ 204 | { 205 | uri: `${SERVER_NAME}://examples`, 206 | name: 'REST API Usage Examples', 207 | description: 'Detailed examples of using the REST API testing tool', 208 | mimeType: 'text/markdown' 209 | }, 210 | { 211 | uri: `${SERVER_NAME}://response-format`, 212 | name: 'Response Format Documentation', 213 | description: 'Documentation of the response format and structure', 214 | mimeType: 'text/markdown' 215 | }, 216 | { 217 | uri: `${SERVER_NAME}://config`, 218 | name: 'Configuration Documentation', 219 | description: 'Documentation of all configuration options and how to use them', 220 | mimeType: 'text/markdown' 221 | } 222 | ] 223 | })); 224 | 225 | this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => { 226 | const uriPattern = new RegExp(`^${SERVER_NAME}://(.+)$`); 227 | const match = request.params.uri.match(uriPattern); 228 | 229 | if (!match) { 230 | throw new McpError( 231 | ErrorCode.InvalidRequest, 232 | `Invalid resource URI format: ${request.params.uri}` 233 | ); 234 | } 235 | 236 | const resource = match[1]; 237 | const fs = await import('fs'); 238 | const path = await import('path'); 239 | 240 | try { 241 | const url = await import('url'); 242 | const __filename = url.fileURLToPath(import.meta.url); 243 | const __dirname = path.dirname(__filename); 244 | 245 | // In the built app, resources are in build/resources 246 | // In development, they're in src/resources 247 | const resourcePath = path.join(__dirname, 'resources', `${resource}.md`); 248 | const content = await fs.promises.readFile(resourcePath, 'utf8'); 249 | 250 | return { 251 | contents: [{ 252 | uri: request.params.uri, 253 | mimeType: 'text/markdown', 254 | text: content 255 | }] 256 | }; 257 | } catch (error) { 258 | throw new McpError( 259 | ErrorCode.InvalidRequest, 260 | `Resource not found: ${resource}` 261 | ); 262 | } 263 | }); 264 | } 265 | 266 | private setupToolHandlers() { 267 | this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ 268 | tools: [ 269 | { 270 | name: 'test_request', 271 | description: `Test a REST API endpoint and get detailed response information. Base URL: ${normalizeBaseUrl(process.env.REST_BASE_URL!)} | SSL Verification ${REST_ENABLE_SSL_VERIFY ? 'enabled' : 'disabled'} (see config resource for SSL settings) | Authentication: ${ 272 | hasBasicAuth() ? 273 | `Basic Auth with username: ${AUTH_BASIC_USERNAME}` : 274 | hasBearerAuth() ? 275 | 'Bearer token authentication configured' : 276 | hasApiKeyAuth() ? 277 | `API Key using header: ${AUTH_APIKEY_HEADER_NAME}` : 278 | 'No authentication configured' 279 | } | ${(() => { 280 | const customHeaders = getCustomHeaders(); 281 | if (Object.keys(customHeaders).length === 0) { 282 | return 'No custom headers defined (see config resource for headers)'; 283 | } 284 | 285 | // List of common headers that are safe to show values for 286 | const safeHeaders = new Set([ 287 | 'accept', 288 | 'accept-language', 289 | 'content-type', 290 | 'user-agent', 291 | 'cache-control', 292 | 'if-match', 293 | 'if-none-match', 294 | 'if-modified-since', 295 | 'if-unmodified-since' 296 | ]); 297 | 298 | const headerList = Object.entries(customHeaders).map(([name, value]) => { 299 | const lowerName = name.toLowerCase(); 300 | return safeHeaders.has(lowerName) ? 301 | `${name}(${value})` : 302 | name; 303 | }).join(', '); 304 | 305 | return `Custom headers defined: ${headerList} (see config resource for headers)`; 306 | })()} | The tool automatically: - Normalizes endpoints (adds leading slash, removes trailing slashes) - Handles authentication header injection - Applies custom headers from HEADER_* environment variables - Accepts any HTTP status code as valid - Limits response size to ${RESPONSE_SIZE_LIMIT} bytes (see config resource for size limit settings) - Returns detailed response information including: * Full URL called * Status code and text * Response headers * Response body * Request details (method, headers, body) * Response timing * Validation messages | Error Handling: - Network errors are caught and returned with descriptive messages - Invalid status codes are still returned with full response details - Authentication errors include the attempted auth method | See the config resource for all configuration options, including header configuration. 307 | `, 308 | inputSchema: { 309 | type: 'object', 310 | properties: { 311 | method: { 312 | type: 'string', 313 | enum: ['GET', 'POST', 'PUT', 'DELETE'], 314 | description: 'HTTP method to use', 315 | }, 316 | endpoint: { 317 | type: 'string', 318 | description: `Endpoint path (e.g. "/users"). Do not include full URLs - only the path. Example: "/api/users" will resolve to "${normalizeBaseUrl(process.env.REST_BASE_URL!)}/api/users"`, 319 | }, 320 | body: { 321 | type: 'object', 322 | description: 'Optional request body for POST/PUT requests', 323 | }, 324 | headers: { 325 | type: 'object', 326 | description: 'Optional request headers for one-time use. IMPORTANT: Do not use for sensitive data like API keys - those should be configured via environment variables. This parameter is intended for dynamic, non-sensitive headers that may be needed for specific requests.', 327 | additionalProperties: { 328 | type: 'string' 329 | } 330 | } 331 | }, 332 | required: ['method', 'endpoint'], 333 | }, 334 | }, 335 | ], 336 | })); 337 | 338 | this.server.setRequestHandler(CallToolRequestSchema, async (request) => { 339 | if (request.params.name !== 'test_request') { 340 | throw new McpError( 341 | ErrorCode.MethodNotFound, 342 | `Unknown tool: ${request.params.name}` 343 | ); 344 | } 345 | 346 | if (!isValidEndpointArgs(request.params.arguments)) { 347 | throw new McpError( 348 | ErrorCode.InvalidParams, 349 | 'Invalid test endpoint arguments' 350 | ); 351 | } 352 | 353 | // Ensure endpoint starts with / and remove any trailing slashes 354 | const normalizedEndpoint = `/${request.params.arguments.endpoint.replace(/^\/+|\/+$/g, '')}`; 355 | 356 | // Initialize request config 357 | const config: AxiosRequestConfig = { 358 | method: request.params.arguments.method as Method, 359 | url: normalizedEndpoint, 360 | headers: {}, 361 | }; 362 | 363 | // Add request body for POST/PUT 364 | if (['POST', 'PUT'].includes(request.params.arguments.method) && request.params.arguments.body) { 365 | config.data = request.params.arguments.body; 366 | } 367 | 368 | // Apply headers in order of priority (lowest to highest) 369 | 370 | // 1. Custom global headers (lowest priority) 371 | const customHeaders = getCustomHeaders(); 372 | config.headers = { 373 | ...customHeaders, 374 | ...config.headers, 375 | ...(request.params.arguments.headers || {}) // Request-specific headers (middle priority) 376 | }; 377 | 378 | // 3. Authentication headers (highest priority) 379 | if (hasBasicAuth()) { 380 | const base64Credentials = Buffer.from(`${AUTH_BASIC_USERNAME}:${AUTH_BASIC_PASSWORD}`).toString('base64'); 381 | config.headers = { 382 | ...config.headers, 383 | 'Authorization': `Basic ${base64Credentials}` 384 | }; 385 | } else if (hasBearerAuth()) { 386 | config.headers = { 387 | ...config.headers, 388 | 'Authorization': `Bearer ${AUTH_BEARER}` 389 | }; 390 | } else if (hasApiKeyAuth()) { 391 | config.headers = { 392 | ...config.headers, 393 | [AUTH_APIKEY_HEADER_NAME as string]: AUTH_APIKEY_VALUE 394 | }; 395 | } 396 | 397 | try { 398 | const startTime = Date.now(); 399 | const response = await this.axiosInstance.request(config); 400 | const endTime = Date.now(); 401 | const fullUrl = `${process.env.REST_BASE_URL}${normalizedEndpoint}`; 402 | 403 | // Determine auth method used 404 | let authMethod = 'none'; 405 | if (hasBasicAuth()) authMethod = 'basic'; 406 | else if (hasBearerAuth()) authMethod = 'bearer'; 407 | else if (hasApiKeyAuth()) authMethod = 'apikey'; 408 | 409 | // Prepare response object 410 | const responseObj: ResponseObject = { 411 | request: { 412 | url: fullUrl, 413 | method: config.method || 'GET', 414 | headers: { 415 | ...sanitizeHeaders(config.headers as Record, false), 416 | ...sanitizeHeaders(request.params.arguments.headers || {}, true) 417 | }, 418 | body: config.data, 419 | authMethod 420 | }, 421 | response: { 422 | statusCode: response.status, 423 | statusText: response.statusText, 424 | timing: `${endTime - startTime}ms`, 425 | headers: sanitizeHeaders(response.headers as Record, false), 426 | body: response.data, 427 | }, 428 | validation: { 429 | isError: response.status >= 400, 430 | messages: response.status >= 400 ? 431 | [`Request failed with status ${response.status}`] : 432 | ['Request completed successfully'] 433 | } 434 | }; 435 | 436 | // Check response body size independently 437 | const bodyStr = typeof response.data === 'string' 438 | ? response.data 439 | : JSON.stringify(response.data); 440 | const bodySize = Buffer.from(bodyStr).length; 441 | 442 | if (bodySize > RESPONSE_SIZE_LIMIT) { 443 | // Simply truncate to the size limit 444 | responseObj.response.body = bodyStr.slice(0, RESPONSE_SIZE_LIMIT); 445 | responseObj.validation.messages.push( 446 | `Response truncated: ${RESPONSE_SIZE_LIMIT} of ${bodySize} bytes returned due to size limit (${RESPONSE_SIZE_LIMIT} bytes)` 447 | ); 448 | responseObj.validation.truncated = { 449 | originalSize: bodySize, 450 | returnedSize: RESPONSE_SIZE_LIMIT, 451 | truncationPoint: RESPONSE_SIZE_LIMIT, 452 | sizeLimit: RESPONSE_SIZE_LIMIT 453 | }; 454 | } 455 | 456 | return { 457 | content: [ 458 | { 459 | type: 'text', 460 | text: JSON.stringify(responseObj, null, 2), 461 | }, 462 | ], 463 | }; 464 | } catch (error) { 465 | if (axios.isAxiosError(error)) { 466 | return { 467 | content: [ 468 | { 469 | type: 'text', 470 | text: JSON.stringify({ 471 | error: { 472 | message: error.message, 473 | code: error.code, 474 | request: { 475 | url: `${process.env.REST_BASE_URL}${normalizedEndpoint}`, 476 | method: config.method, 477 | headers: { 478 | ...sanitizeHeaders(config.headers as Record, false), 479 | ...sanitizeHeaders(request.params.arguments.headers || {}, true) 480 | }, 481 | body: config.data 482 | } 483 | } 484 | }, null, 2), 485 | }, 486 | ], 487 | isError: true, 488 | }; 489 | } 490 | throw error; 491 | } 492 | }); 493 | } 494 | 495 | async run() { 496 | await this.setupServer(); 497 | const transport = new StdioServerTransport(); 498 | await this.server.connect(transport); 499 | console.error('REST API Tester MCP server running on stdio'); 500 | } 501 | } 502 | 503 | const server = new RestTester(); 504 | server.run().catch(console.error); 505 | -------------------------------------------------------------------------------- /src/resources/config.md: -------------------------------------------------------------------------------- 1 | # REST API Tester Configuration 2 | 3 | This document describes all available configuration options for the REST API testing tool. 4 | 5 | ## Core Configuration 6 | 7 | ### REST_BASE_URL (Required) 8 | - Description: The base URL that all endpoint paths will be resolved against 9 | - Example: `http://localhost:3000` or `https://api.example.com` 10 | - Usage: All endpoint paths will be appended to this URL. For example, if REST_BASE_URL is `http://localhost:3000` and you use the endpoint `/api/users`, the full URL will be `http://localhost:3000/api/users` 11 | 12 | ### REST_RESPONSE_SIZE_LIMIT (Optional) 13 | - Description: Maximum size in bytes for response data 14 | - Default: 10000 (10KB) 15 | - Example: `50000` for 50KB limit 16 | - Usage: Helps prevent memory issues with large responses. If a response exceeds this size, it will be truncated and a warning message will be included 17 | 18 | ### REST_ENABLE_SSL_VERIFY (Optional) 19 | - Description: Controls SSL certificate verification 20 | - Default: `true` 21 | - Values: Set to `false` to disable SSL verification for self-signed certificates 22 | - Usage: Disable when testing APIs with self-signed certificates in development environments 23 | 24 | ## Custom Headers Configuration 25 | 26 | ### Custom Headers (Optional) 27 | - Description: Add custom headers to all requests using environment variables 28 | - Pattern: `HEADER_=` (prefix is case-insensitive) 29 | - Examples: 30 | ```bash 31 | HEADER_X-API-Version=2.0 32 | header_Custom-Client=my-client 33 | HeAdEr_Accept=application/json 34 | ``` 35 | - Usage: Headers are added to all requests. The header name after `HEADER_` preserves its exact case 36 | - Priority: Per-request headers > Authentication headers > Custom global headers 37 | 38 | ## Authentication Configuration 39 | 40 | The tool supports three authentication methods. Configure one based on your API's requirements. 41 | 42 | ### Basic Authentication 43 | - REST_BASIC_USERNAME: Username for Basic Auth 44 | - REST_BASIC_PASSWORD: Password for Basic Auth 45 | - Usage: When both are set, requests will include Basic Auth header 46 | 47 | ### Bearer Token 48 | - REST_BEARER: Bearer token value 49 | - Usage: When set, requests will include `Authorization: Bearer ` header 50 | 51 | ### API Key 52 | - REST_APIKEY_HEADER_NAME: Name of the header for API key 53 | - REST_APIKEY_VALUE: Value of the API key 54 | - Example: 55 | ``` 56 | REST_APIKEY_HEADER_NAME=X-API-Key 57 | REST_APIKEY_VALUE=your-api-key-here 58 | ``` 59 | - Usage: When both are set, requests will include the specified header with the API key 60 | 61 | ## Configuration Examples 62 | 63 | ### Local Development 64 | ```bash 65 | REST_BASE_URL=http://localhost:3000 66 | REST_ENABLE_SSL_VERIFY=false 67 | REST_RESPONSE_SIZE_LIMIT=50000 68 | ``` 69 | 70 | ### Production API with Bearer Token 71 | ```bash 72 | REST_BASE_URL=https://api.example.com 73 | REST_BEARER=your-bearer-token 74 | ``` 75 | 76 | ### API with Basic Auth 77 | ```bash 78 | REST_BASE_URL=https://api.example.com 79 | REST_BASIC_USERNAME=admin 80 | REST_BASIC_PASSWORD=secret 81 | ``` 82 | 83 | ### API with API Key 84 | ```bash 85 | REST_BASE_URL=https://api.example.com 86 | REST_APIKEY_HEADER_NAME=X-API-Key 87 | REST_APIKEY_VALUE=your-api-key 88 | ``` 89 | 90 | ### API with Custom Headers 91 | ```bash 92 | REST_BASE_URL=https://api.example.com 93 | HEADER_X-API-Version=2.0 94 | HEADER_Custom-Client=my-client 95 | HEADER_Accept=application/json 96 | ``` 97 | 98 | ## Changing Configuration 99 | 100 | Configuration can be updated by: 101 | 1. Setting environment variables before starting the server 102 | 2. Modifying the MCP server configuration file 103 | 3. Using environment variable commands in your terminal 104 | 105 | Remember to restart the server after changing configuration for the changes to take effect. 106 | -------------------------------------------------------------------------------- /src/resources/examples.md: -------------------------------------------------------------------------------- 1 | # REST API Testing Examples 2 | 3 | ⚠️ IMPORTANT: Only provide the endpoint path - do not include full URLs. Your path will be automatically resolved to the full URL. 4 | 5 | For example, if the base URL is `http://localhost:3000`: 6 | ✅ Correct: `"/api/users"` → Resolves to: `http://localhost:3000/api/users` 7 | ❌ Incorrect: `"http://localhost:3000/api/users"` or `"www.example.com/api/users"` 8 | 9 | ## Basic GET Request 10 | ```typescript 11 | use_mcp_tool('rest-api', 'test_request', { 12 | "method": "GET", 13 | "endpoint": "/users" // Will be appended to REST_BASE_URL 14 | }); 15 | ``` 16 | 17 | ## GET with Query Parameters 18 | ```typescript 19 | use_mcp_tool('rest-api', 'test_request', { 20 | "method": "GET", 21 | "endpoint": "/users?role=admin&status=active" 22 | }); 23 | ``` 24 | 25 | ## POST Request with Body 26 | ```typescript 27 | use_mcp_tool('rest-api', 'test_request', { 28 | "method": "POST", 29 | "endpoint": "/users", 30 | "body": { 31 | "name": "John Doe", 32 | "email": "john@example.com" 33 | } 34 | }); 35 | ``` 36 | 37 | ## Request with Custom Headers 38 | ```typescript 39 | use_mcp_tool('rest-api', 'test_request', { 40 | "method": "GET", 41 | "endpoint": "/secure-resource", 42 | "headers": { 43 | "Custom-Header": "value", 44 | "Another-Header": "another-value" 45 | } 46 | }); 47 | ``` 48 | 49 | ## PUT Request Example 50 | ```typescript 51 | use_mcp_tool('rest-api', 'test_request', { 52 | "method": "PUT", 53 | "endpoint": "/users/123", 54 | "body": { 55 | "name": "Updated Name", 56 | "status": "inactive" 57 | } 58 | }); 59 | ``` 60 | 61 | ## DELETE Request Example 62 | ```typescript 63 | use_mcp_tool('rest-api', 'test_request', { 64 | "method": "DELETE", 65 | "endpoint": "/users/123" 66 | }); 67 | ``` 68 | 69 | ## Changing Base URL 70 | If you need to test against a different base URL, update the base URL configuration rather than including the full URL in the endpoint parameter. 71 | 72 | Example: 73 | ```bash 74 | # Instead of this: 75 | ❌ "endpoint": "https://api.example.com/users" # Wrong - don't include the full URL 76 | 77 | # Do this: 78 | # 1. Update the base URL configuration to: https://api.example.com 79 | # 2. Then use just the path: 80 | ✅ "endpoint": "/users" # This will resolve to: https://api.example.com/users 81 | -------------------------------------------------------------------------------- /src/resources/response-format.md: -------------------------------------------------------------------------------- 1 | # Response Format Documentation 2 | 3 | The REST API testing tool returns a comprehensive JSON response containing request details, response information, and validation results. 4 | 5 | ## Response Structure 6 | 7 | ```json 8 | { 9 | "request": { 10 | "url": "http://api.example.com/users", 11 | "method": "GET", 12 | "headers": {}, 13 | "body": null, 14 | "authMethod": "none" 15 | }, 16 | "response": { 17 | "statusCode": 200, 18 | "statusText": "OK", 19 | "timing": "123ms", 20 | "headers": {}, 21 | "body": {} 22 | }, 23 | "validation": { 24 | "isError": false, 25 | "messages": ["Request completed successfully"] 26 | } 27 | } 28 | ``` 29 | 30 | ## Response Fields 31 | 32 | ### Request Details 33 | - `url`: Full URL including base URL and endpoint 34 | - `method`: HTTP method used 35 | - `headers`: Request headers sent 36 | - `body`: Request body (if applicable) 37 | - `authMethod`: Authentication method used (none, basic, bearer, or apikey) 38 | 39 | ### Response Details 40 | - `statusCode`: HTTP status code 41 | - `statusText`: Status message 42 | - `timing`: Request duration in milliseconds 43 | - `headers`: Response headers received 44 | - `body`: Response body content 45 | 46 | ### Validation 47 | - `isError`: true if status code >= 400 48 | - `messages`: Array of validation or error messages 49 | 50 | ## Error Response Example 51 | 52 | ```json 53 | { 54 | "error": { 55 | "message": "Connection refused", 56 | "code": "ECONNREFUSED", 57 | "request": { 58 | "url": "http://api.example.com/users", 59 | "method": "GET", 60 | "headers": {}, 61 | "body": null 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/version.ts.template: -------------------------------------------------------------------------------- 1 | // Template file for TypeScript during development 2 | // The actual version.ts will be generated during build 3 | 4 | export const VERSION = '0.0.0'; 5 | export const PACKAGE_NAME = 'dkmaker-mcp-rest-api'; 6 | export const SERVER_NAME = 'rest-api'; 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "Node16", 5 | "moduleResolution": "Node16", 6 | "outDir": "./build", 7 | "rootDir": "./src", 8 | "strict": true, 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true 12 | }, 13 | "include": ["src/**/*"], 14 | "exclude": ["node_modules"] 15 | } 16 | --------------------------------------------------------------------------------