@edicarlos.lds/businessmap-mcp 2.1.1 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,169 @@
1
+ # Logging System
2
+
3
+ ## Overview
4
+
5
+ The BusinessMap MCP Server uses a structured logging system that ensures compatibility with the Model Context Protocol (MCP) while providing clear, categorized log output.
6
+
7
+ ## Why STDERR?
8
+
9
+ The MCP protocol uses **STDOUT exclusively for JSON-RPC communication**. Any output to STDOUT that is not valid JSON-RPC will corrupt the protocol and cause errors like:
10
+
11
+ ```
12
+ MCP businessmap: Unexpected token '✅', "✅ Configur"... is not valid JSON
13
+ ```
14
+
15
+ Therefore, **all logging must go to STDERR** (`console.error` or `process.stderr.write`).
16
+
17
+ ## Logger Utility
18
+
19
+ Instead of using raw `console.error` for all messages (which can be misleading), we provide a `logger` utility that categorizes messages while still outputting to STDERR.
20
+
21
+ ### Log Levels
22
+
23
+ ```typescript
24
+ export enum LogLevel {
25
+ DEBUG = 0, // Detailed debugging information
26
+ INFO = 1, // Informational messages (default)
27
+ WARN = 2, // Warning messages
28
+ ERROR = 3, // Error messages
29
+ NONE = 4, // Disable all logging
30
+ }
31
+ ```
32
+
33
+ ### Usage Examples
34
+
35
+ ```typescript
36
+ import { logger } from './utils/logger.js';
37
+
38
+ // Success messages (shown at INFO level)
39
+ logger.success('Successfully connected to BusinessMap API');
40
+
41
+ // Informational messages (shown at INFO level)
42
+ logger.info('🚀 Starting BusinessMap MCP Server v1.0.0');
43
+ logger.info('📡 BusinessMap API: https://account.kanbanize.com/api/v2');
44
+
45
+ // Debug messages (shown at DEBUG level only)
46
+ logger.debug('Fetching effective cycle time columns for board 123');
47
+
48
+ // Warning messages (shown at WARN level and above)
49
+ logger.warn('Direct board lookup failed, trying fallback method');
50
+
51
+ // Error messages (shown at ERROR level and above)
52
+ logger.error('Failed to connect to API', errorObject);
53
+ ```
54
+
55
+ ### Output Format
56
+
57
+ All log messages include timestamps and clear prefixes:
58
+
59
+ ```
60
+ [2025-11-15T10:30:45.123Z] ✅ SUCCESS: Successfully connected to BusinessMap API
61
+ [2025-11-15T10:30:45.456Z] ℹ️ INFO: 🚀 Starting BusinessMap MCP Server v1.0.0
62
+ [2025-11-15T10:30:46.789Z] 🔍 DEBUG: Fetching effective cycle time columns for board 123
63
+ [2025-11-15T10:30:47.012Z] ⚠️ WARN: Direct board lookup failed, trying fallback method
64
+ [2025-11-15T10:30:47.345Z] ❌ ERROR: Failed to connect to API
65
+ ```
66
+
67
+ ## Configuration
68
+
69
+ Set the `LOG_LEVEL` environment variable to control verbosity:
70
+
71
+ ```bash
72
+ # Show all messages including debug
73
+ LOG_LEVEL=0 npx @edicarlos.lds/businessmap-mcp
74
+
75
+ # Show info, warnings, and errors (default)
76
+ LOG_LEVEL=1 npx @edicarlos.lds/businessmap-mcp
77
+
78
+ # Show only warnings and errors
79
+ LOG_LEVEL=2 npx @edicarlos.lds/businessmap-mcp
80
+
81
+ # Show only errors
82
+ LOG_LEVEL=3 npx @edicarlos.lds/businessmap-mcp
83
+
84
+ # Disable all logging
85
+ LOG_LEVEL=4 npx @edicarlos.lds/businessmap-mcp
86
+ ```
87
+
88
+ ### In Claude Desktop Config
89
+
90
+ ```json
91
+ {
92
+ "mcpServers": {
93
+ "Businessmap": {
94
+ "command": "npx",
95
+ "args": ["-y", "@edicarlos.lds/businessmap-mcp"],
96
+ "env": {
97
+ "BUSINESSMAP_API_TOKEN": "your_token",
98
+ "BUSINESSMAP_API_URL": "https://account.kanbanize.com/api/v2",
99
+ "LOG_LEVEL": "1"
100
+ }
101
+ }
102
+ }
103
+ }
104
+ ```
105
+
106
+ ## Benefits
107
+
108
+ ### ✅ Clear Message Categorization
109
+
110
+ Instead of everything being "errors" (when using `console.error`), messages are properly categorized:
111
+
112
+ - **SUCCESS**: Operations completed successfully
113
+ - **INFO**: General informational messages
114
+ - **DEBUG**: Detailed debugging information
115
+ - **WARN**: Non-critical issues or fallback scenarios
116
+ - **ERROR**: Actual errors and failures
117
+
118
+ ### ✅ MCP Protocol Compliance
119
+
120
+ All output goes to STDERR, keeping STDOUT clean for JSON-RPC:
121
+
122
+ ```typescript
123
+ // ❌ BAD - Breaks MCP protocol
124
+ console.log('Starting server...');
125
+
126
+ // ✅ GOOD - Uses STDERR
127
+ console.error('Starting server...');
128
+
129
+ // ✅ BETTER - Categorized and uses STDERR
130
+ logger.info('Starting server...');
131
+ ```
132
+
133
+ ### ✅ Configurable Verbosity
134
+
135
+ Control what gets logged without changing code:
136
+
137
+ ```bash
138
+ # Production: minimal logging
139
+ LOG_LEVEL=2
140
+
141
+ # Development: detailed logging
142
+ LOG_LEVEL=0
143
+ ```
144
+
145
+ ### ✅ Consistent Format
146
+
147
+ All messages follow the same format with timestamps and clear prefixes, making logs easier to read and parse.
148
+
149
+ ## Migration from console.error
150
+
151
+ When migrating from `console.error` to the logger utility, choose the appropriate method:
152
+
153
+ ```typescript
154
+ // Before
155
+ console.error('✅ Successfully connected');
156
+ console.error('🔄 Retrying connection...');
157
+ console.error('⚠️ Fallback method used');
158
+ console.error('❌ Connection failed');
159
+
160
+ // After
161
+ logger.success('Successfully connected');
162
+ logger.info('Retrying connection...');
163
+ logger.warn('Fallback method used');
164
+ logger.error('Connection failed');
165
+ ```
166
+
167
+ ## Implementation Details
168
+
169
+ The logger is implemented in `src/utils/logger.ts` and uses a singleton pattern. All methods internally call `console.error` to ensure output goes to STDERR, maintaining MCP protocol compatibility.
@@ -0,0 +1,215 @@
1
+ # MCP Client Configuration
2
+
3
+ This guide contains copy-and-paste examples for configuring the BusinessMap MCP Server in common MCP clients.
4
+
5
+ ## Required Values
6
+
7
+ Every client needs:
8
+
9
+ - `BUSINESSMAP_API_TOKEN`: your BusinessMap API token
10
+ - `BUSINESSMAP_API_URL`: your BusinessMap API URL, for example `https://your-account.kanbanize.com/api/v2`
11
+
12
+ Optional but commonly useful:
13
+
14
+ - `BUSINESSMAP_READ_ONLY_MODE`: set to `true` to expose only read-only tools
15
+ - `BUSINESSMAP_DEFAULT_WORKSPACE_ID`: default workspace ID
16
+ - `LOG_LEVEL`: `0` debug, `1` info, `2` warn, `3` error, `4` none
17
+
18
+ ## Claude Desktop
19
+
20
+ Config file location:
21
+
22
+ - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
23
+ - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
24
+
25
+ Open it through `Settings -> Developer -> Edit Config`, then add:
26
+
27
+ ```json
28
+ {
29
+ "mcpServers": {
30
+ "businessmap": {
31
+ "command": "npx",
32
+ "args": ["-y", "@edicarlos.lds/businessmap-mcp"],
33
+ "env": {
34
+ "BUSINESSMAP_API_TOKEN": "your_token_here",
35
+ "BUSINESSMAP_API_URL": "https://your-account.kanbanize.com/api/v2",
36
+ "BUSINESSMAP_READ_ONLY_MODE": "false",
37
+ "BUSINESSMAP_DEFAULT_WORKSPACE_ID": "1"
38
+ }
39
+ }
40
+ }
41
+ }
42
+ ```
43
+
44
+ Fully quit and restart Claude Desktop after editing. JSON does not support comments, so remove any comments before saving.
45
+
46
+ ## Claude Code
47
+
48
+ Add the server globally:
49
+
50
+ ```bash
51
+ claude mcp add --transport stdio --scope user businessmap -- npx -y @edicarlos.lds/businessmap-mcp
52
+ ```
53
+
54
+ Or add it to the current project:
55
+
56
+ ```bash
57
+ claude mcp add --transport stdio businessmap -- npx -y @edicarlos.lds/businessmap-mcp
58
+ ```
59
+
60
+ To pass environment variables directly:
61
+
62
+ ```bash
63
+ claude mcp add --transport stdio \
64
+ --env BUSINESSMAP_API_TOKEN=your_token_here \
65
+ --env BUSINESSMAP_API_URL=https://your-account.kanbanize.com/api/v2 \
66
+ businessmap -- npx -y @edicarlos.lds/businessmap-mcp
67
+ ```
68
+
69
+ You can also commit a `.mcp.json` file to your project root:
70
+
71
+ ```json
72
+ {
73
+ "mcpServers": {
74
+ "businessmap": {
75
+ "command": "npx",
76
+ "args": ["-y", "@edicarlos.lds/businessmap-mcp"],
77
+ "env": {
78
+ "BUSINESSMAP_API_TOKEN": "${BUSINESSMAP_API_TOKEN}",
79
+ "BUSINESSMAP_API_URL": "${BUSINESSMAP_API_URL}"
80
+ }
81
+ }
82
+ }
83
+ }
84
+ ```
85
+
86
+ Use environment variable expansion to avoid hardcoding secrets in source control.
87
+
88
+ ## Cursor
89
+
90
+ Create or edit `~/.cursor/mcp.json` for global configuration, or `.cursor/mcp.json` at the project root for project-specific configuration:
91
+
92
+ ```json
93
+ {
94
+ "mcpServers": {
95
+ "businessmap": {
96
+ "command": "npx",
97
+ "args": ["-y", "@edicarlos.lds/businessmap-mcp"],
98
+ "env": {
99
+ "BUSINESSMAP_API_TOKEN": "your_token_here",
100
+ "BUSINESSMAP_API_URL": "https://your-account.kanbanize.com/api/v2",
101
+ "BUSINESSMAP_READ_ONLY_MODE": "false",
102
+ "BUSINESSMAP_DEFAULT_WORKSPACE_ID": "1"
103
+ }
104
+ }
105
+ }
106
+ }
107
+ ```
108
+
109
+ You can also manage servers through `Settings -> Features -> MCP`.
110
+
111
+ ## VS Code
112
+
113
+ VS Code uses `servers` as the top-level key instead of `mcpServers`.
114
+
115
+ Config file locations:
116
+
117
+ - Workspace: `.vscode/mcp.json`
118
+ - macOS user config: `~/Library/Application Support/Code/User/mcp.json`
119
+ - Windows user config: `%APPDATA%\Code\User\mcp.json`
120
+
121
+ ```json
122
+ {
123
+ "inputs": [
124
+ {
125
+ "type": "promptString",
126
+ "id": "businessmap-token",
127
+ "description": "BusinessMap API Token",
128
+ "password": true
129
+ }
130
+ ],
131
+ "servers": {
132
+ "businessmap": {
133
+ "type": "stdio",
134
+ "command": "npx",
135
+ "args": ["-y", "@edicarlos.lds/businessmap-mcp"],
136
+ "env": {
137
+ "BUSINESSMAP_API_TOKEN": "${input:businessmap-token}",
138
+ "BUSINESSMAP_API_URL": "https://your-account.kanbanize.com/api/v2",
139
+ "BUSINESSMAP_READ_ONLY_MODE": "false",
140
+ "BUSINESSMAP_DEFAULT_WORKSPACE_ID": "1"
141
+ }
142
+ }
143
+ }
144
+ }
145
+ ```
146
+
147
+ The `inputs` block lets VS Code prompt for secrets at runtime. This requires the GitHub Copilot Chat extension. You can also add a server from the Command Palette with `MCP: Add Server`.
148
+
149
+ ## Windsurf
150
+
151
+ Edit `~/.codeium/windsurf/mcp_config.json`. You can open it from the Cascade panel's MCPs icon through `Configure`.
152
+
153
+ ```json
154
+ {
155
+ "mcpServers": {
156
+ "businessmap": {
157
+ "command": "npx",
158
+ "args": ["-y", "@edicarlos.lds/businessmap-mcp"],
159
+ "env": {
160
+ "BUSINESSMAP_API_TOKEN": "your_token_here",
161
+ "BUSINESSMAP_API_URL": "https://your-account.kanbanize.com/api/v2",
162
+ "BUSINESSMAP_READ_ONLY_MODE": "false",
163
+ "BUSINESSMAP_DEFAULT_WORKSPACE_ID": "1"
164
+ }
165
+ }
166
+ }
167
+ }
168
+ ```
169
+
170
+ Windsurf supports `${env:VARIABLE_NAME}` syntax inside `env` values.
171
+
172
+ ## Zed
173
+
174
+ Zed configures MCP servers in `~/.config/zed/settings.json` under `context_servers`.
175
+
176
+ ```json
177
+ {
178
+ "context_servers": {
179
+ "businessmap": {
180
+ "source": "custom",
181
+ "command": "npx",
182
+ "args": ["-y", "@edicarlos.lds/businessmap-mcp"],
183
+ "env": {
184
+ "BUSINESSMAP_API_TOKEN": "your_token_here",
185
+ "BUSINESSMAP_API_URL": "https://your-account.kanbanize.com/api/v2",
186
+ "BUSINESSMAP_READ_ONLY_MODE": "false",
187
+ "BUSINESSMAP_DEFAULT_WORKSPACE_ID": "1"
188
+ }
189
+ }
190
+ }
191
+ }
192
+ ```
193
+
194
+ You can also add servers through the Agent Panel settings with `Add Custom Server`. A green indicator in the Agent Panel confirms the server is running.
195
+
196
+ ## Other MCP Clients
197
+
198
+ For any MCP-compatible client, configure a `stdio` server with:
199
+
200
+ | Setting | Value |
201
+ | --- | --- |
202
+ | Command | `npx` |
203
+ | Args | `-y @edicarlos.lds/businessmap-mcp` |
204
+ | Required env | `BUSINESSMAP_API_TOKEN`, `BUSINESSMAP_API_URL` |
205
+ | Optional env | `BUSINESSMAP_READ_ONLY_MODE`, `BUSINESSMAP_DEFAULT_WORKSPACE_ID`, `LOG_LEVEL` |
206
+
207
+ ## Remote HTTP Clients
208
+
209
+ When running with `TRANSPORT=http`, configure the client to use:
210
+
211
+ ```text
212
+ http://your-server:3000/mcp
213
+ ```
214
+
215
+ For public or shared deployments, protect the endpoint with authentication or network controls. See [MIDDLEWARE.md](MIDDLEWARE.md) for programmatic middleware examples.
@@ -0,0 +1,141 @@
1
+ # Programmatic Usage & Custom Middleware Guide
2
+
3
+ This guide is designed for developers who want to embed the **BusinessMap MCP Server** programmatically into their own Node.js/TypeScript applications, and implement custom logic (such as authentication, authorization, logging, or rate-limiting) using Express middlewares.
4
+
5
+ ---
6
+
7
+ ## 🚀 Quick Start
8
+
9
+ Ensure you have installed the package:
10
+
11
+ ```bash
12
+ npm install @edicarlos.lds/businessmap-mcp
13
+ ```
14
+
15
+ You can import `startHttpServer` and launch the MCP server in HTTP mode programmatically:
16
+
17
+ ```typescript
18
+ import { startHttpServer } from '@edicarlos.lds/businessmap-mcp';
19
+
20
+ // Start HTTP server with default options
21
+ await startHttpServer();
22
+ ```
23
+
24
+ ---
25
+
26
+ ## 🔒 Implementing Custom Authentication
27
+
28
+ Since the HTTP transport does not enforce authentication by default, you can inject custom Express middlewares to secure the `/mcp` endpoints.
29
+
30
+ ### Example 1: Static API Key Authentication
31
+ This middleware checks for a pre-configured header (e.g. `Authorization` or `x-api-key`).
32
+
33
+ ```typescript
34
+ import { startHttpServer } from '@edicarlos.lds/businessmap-mcp';
35
+
36
+ const API_KEY = process.env.MCP_SERVER_KEY || 'your-secret-api-key';
37
+
38
+ await startHttpServer({
39
+ middlewares: [
40
+ (req, res, next) => {
41
+ // Allow health check to remain public
42
+ if (req.path === '/health') {
43
+ return next();
44
+ }
45
+
46
+ const clientKey = req.headers['x-api-key'] || req.headers['authorization'];
47
+
48
+ if (clientKey === API_KEY || clientKey === `Bearer ${API_KEY}`) {
49
+ return next(); // Authenticated
50
+ }
51
+
52
+ res.status(401).json({ error: 'Unauthorized: Invalid or missing API key' });
53
+ }
54
+ ]
55
+ });
56
+ ```
57
+
58
+ ### Example 2: Integration with third-party Identity Providers (JWT/OAuth)
59
+ You can use standard Express ecosystem libraries (like `express-oauth2-jwt-bearer` or custom JWT verification) to authenticate users remotely.
60
+
61
+ ```typescript
62
+ import { startHttpServer } from '@edicarlos.lds/businessmap-mcp';
63
+ import jwt from 'jsonwebtoken';
64
+
65
+ const JWT_SECRET = process.env.JWT_SECRET!;
66
+
67
+ await startHttpServer({
68
+ middlewares: [
69
+ (req, res, next) => {
70
+ if (req.path === '/health') return next();
71
+
72
+ const authHeader = req.headers['authorization'];
73
+ if (!authHeader?.startsWith('Bearer ')) {
74
+ return res.status(401).json({ error: 'Missing token' });
75
+ }
76
+
77
+ const token = authHeader.split(' ')[1];
78
+
79
+ try {
80
+ const decoded = jwt.verify(token, JWT_SECRET);
81
+ // Inject user info into request if needed
82
+ req.user = decoded;
83
+ next();
84
+ } catch (err) {
85
+ res.status(403).json({ error: 'Invalid or expired token' });
86
+ }
87
+ }
88
+ ]
89
+ });
90
+ ```
91
+
92
+ ---
93
+
94
+ ## 🛡️ Adding Security and Rate-Limiting
95
+
96
+ You can pair authentication with popular security headers and rate-limiting packages from the npm ecosystem.
97
+
98
+ ```typescript
99
+ import { startHttpServer } from '@edicarlos.lds/businessmap-mcp';
100
+ import rateLimit from 'express-rate-limit';
101
+ import helmet from 'helmet';
102
+
103
+ // Limit clients to 100 requests per 15 minutes
104
+ const limiter = rateLimit({
105
+ windowMs: 15 * 60 * 1000,
106
+ max: 100,
107
+ message: { error: 'Too many requests, please try again later.' },
108
+ standardHeaders: true,
109
+ legacyHeaders: false,
110
+ });
111
+
112
+ await startHttpServer({
113
+ middlewares: [
114
+ helmet(), // Secure Express HTTP headers
115
+ limiter, // Limit rate
116
+ ],
117
+ });
118
+ ```
119
+
120
+ ---
121
+
122
+ ## ⚙️ Middleware Execution Order
123
+
124
+ Middlewares are executed sequentially in the order they are passed in the `middlewares` array.
125
+ 1. **JSON Parser & CORS** (Default built-in middlewares run first).
126
+ 2. **Custom Middlewares** (Your injected middlewares run next, allowing you to intercept and reject requests early).
127
+ 3. **Session Logging & Session Resolution** (Built-in MCP routing middleware matches the `/mcp` endpoints last).
128
+
129
+ ---
130
+
131
+ ## 🧪 Testing Your Middleware
132
+
133
+ You can test HTTP requests using `curl` or any API client (like Postman):
134
+
135
+ ```bash
136
+ # Testing request with header authorization
137
+ curl -X POST http://localhost:3000/mcp \
138
+ -H "Content-Type: application/json" \
139
+ -H "x-api-key: your-secret-api-key" \
140
+ -d '{"jsonrpc": "2.0", "method": "tools/list", "id": 1}'
141
+ ```
@@ -0,0 +1,146 @@
1
+ # Release Process
2
+
3
+ This document describes the automated release process for the BusinessMap MCP Server.
4
+
5
+ ## 🚀 Automated Process
6
+
7
+ The release process has been fully automated and includes:
8
+
9
+ 1. **Version bump** (patch, minor, major)
10
+ 2. **Automatic release notes generation** based on commits
11
+ 3. **Git tag creation**
12
+ 4. **Push tag to GitHub**
13
+ 5. **GitHub release creation** with release notes
14
+ 6. **NPM publication**
15
+
16
+ ## 📝 How to Make a Release
17
+
18
+ ### 1. Preparation
19
+
20
+ Before making a release, ensure that:
21
+
22
+ - [ ] All changes are committed
23
+ - [ ] You are authenticated to NPM: `npm whoami` or make logging via `npm login`
24
+ - [ ] You are authenticated to GitHub CLI: `gh auth status`
25
+ - [ ] Working directory is clean
26
+
27
+ ### 2. Release Notes Preview
28
+
29
+ To see how the release notes will look before publishing:
30
+
31
+ ```bash
32
+ npm run preview:release
33
+ # or for a specific version:
34
+ npm run preview:release 1.2.3
35
+ ```
36
+
37
+ ### 3. Publication
38
+
39
+ Execute the publish npm command:
40
+
41
+ ```bash
42
+ npm run publish:npm
43
+ ```
44
+
45
+ The script will:
46
+
47
+ 1. Verify authentications
48
+ 2. Build and test
49
+ 3. Show version options (patch/minor/major)
50
+ 4. Generate release notes preview
51
+ 5. Confirm publication
52
+ 6. Execute the entire process automatically
53
+
54
+ ## 📋 Release Notes Format
55
+
56
+ Release notes are automatically generated based on commits since the last tag and organized by category:
57
+
58
+ ### 🚀 New Features
59
+
60
+ - Commits starting with `feat:`, `feature:` or `FEAT:`
61
+
62
+ ### 🐛 Bug Fixes
63
+
64
+ - Commits starting with `fix:` or `FIX:`
65
+
66
+ ### ♻️ Code Refactoring
67
+
68
+ - Commits starting with `refactor:` or `REFACTOR:`
69
+
70
+ ### 📚 Documentation
71
+
72
+ - Commits starting with `docs:`, `doc:` or `DOCS:`
73
+
74
+ ### 🔧 Other Changes
75
+
76
+ - All other commits
77
+
78
+ ## 🏷️ Commit Convention
79
+
80
+ To maximize release notes quality, it's recommended to use the following prefixes:
81
+
82
+ ```bash
83
+ feat: add new functionality
84
+ fix: fix bug
85
+ docs: update documentation
86
+ refactor: refactor code
87
+ test: add or update tests
88
+ chore: maintenance tasks
89
+ ```
90
+
91
+ ## 🔧 Available Scripts
92
+
93
+ - `npm run publish:npm` - Publish to NPM only
94
+ - `npm run publish:github` - Create GitHub release only
95
+ - `npm run preview:release` - Preview release notes
96
+ - `scripts/generate-release-notes.sh` - Generate release notes for specific version
97
+
98
+ ## 🎯 Example of Generated Release Notes
99
+
100
+ ```markdown
101
+ ## What's Changed
102
+
103
+ ### 🚀 New Features
104
+ - add user authentication support by @username
105
+ - implement card filtering by @username
106
+
107
+ ### 🐛 Bug Fixes
108
+ - fix memory leak in client by @username
109
+ - resolve API timeout issues by @username
110
+
111
+ ### 📚 Documentation
112
+ - update README with new examples by @username
113
+
114
+ **Full Changelog**: https://github.com/edicarloslds/businessmap-mcp/compare/v1.0.0...v1.1.0
115
+ ```
116
+
117
+ ## 🚨 Troubleshooting
118
+
119
+ ### NPM Authentication Error
120
+
121
+ ```bash
122
+ npm login
123
+ ```
124
+
125
+ ### GitHub Authentication Error
126
+
127
+ ```bash
128
+ gh auth login
129
+ ```
130
+
131
+ ### Working Directory not clean
132
+
133
+ ```bash
134
+ git status
135
+ git add .
136
+ git commit -m "prepare for release"
137
+ ```
138
+
139
+ ### Tag already exists
140
+
141
+ If something goes wrong during the process, you can remove the created tag:
142
+
143
+ ```bash
144
+ git tag -d v1.2.3
145
+ git push origin :refs/tags/v1.2.3
146
+ ```