@edicarlos.lds/businessmap-mcp 2.1.1 ā 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -16
- package/dist/index.js.map +1 -1
- package/dist/server/http.d.ts +6 -1
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +73 -56
- package/dist/server/http.js.map +1 -1
- package/docs/LOGGING.md +169 -0
- package/docs/MIDDLEWARE.md +141 -0
- package/docs/RELEASE_PROCESS.md +146 -0
- package/docs/TOOLS.md +281 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -249,11 +249,28 @@ You can run the server as a remote MCP endpoint over Streamable HTTP. This is us
|
|
|
249
249
|
npm start
|
|
250
250
|
```
|
|
251
251
|
|
|
252
|
-
2. **Connect your client:**
|
|
253
|
-
|
|
254
252
|
Configure your MCP client to connect to the Streamable HTTP endpoint:
|
|
255
253
|
- **URL**: `http://your-server:3000/mcp`
|
|
256
254
|
|
|
255
|
+
### Programmatic & Middleware Usage
|
|
256
|
+
|
|
257
|
+
If you import this package programmatically or want to add authentication/security (like rate-limiting) to your HTTP endpoint, you can inject custom Express middlewares:
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
import { startHttpServer } from '@edicarlos.lds/businessmap-mcp';
|
|
261
|
+
|
|
262
|
+
await startHttpServer({
|
|
263
|
+
middlewares: [
|
|
264
|
+
(req, res, next) => {
|
|
265
|
+
// Your custom authentication/authorization logic here
|
|
266
|
+
next();
|
|
267
|
+
}
|
|
268
|
+
]
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
For detailed examples (including static API Keys, JWT verification, and rate limiting), see the [Programmatic Middleware Guide](docs/MIDDLEWARE.md).
|
|
273
|
+
|
|
257
274
|
### Manual Setup
|
|
258
275
|
|
|
259
276
|
1. Clone this repository:
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AASA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import fs from 'node:fs';
|
|
2
4
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
5
|
import { config, validateConfig } from './config/environment.js';
|
|
4
6
|
import { BusinessMapMcpServer } from './server/mcp-server.js';
|
|
5
7
|
import { logger } from './utils/logger.js';
|
|
8
|
+
export { startHttpServer } from './server/http.js';
|
|
9
|
+
export { BusinessMapMcpServer } from './server/mcp-server.js';
|
|
6
10
|
async function initializeWithRetry(server) {
|
|
7
11
|
logger.info('š Initializing connection to BusinessMap API...');
|
|
8
12
|
let retryCount = 0;
|
|
@@ -61,21 +65,34 @@ async function main() {
|
|
|
61
65
|
process.exit(1);
|
|
62
66
|
}
|
|
63
67
|
}
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
68
|
+
// Check if run directly
|
|
69
|
+
const getRealpath = (p) => {
|
|
70
|
+
try {
|
|
71
|
+
return fs.realpathSync(p);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return p;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const isMain = process.argv[1] && (getRealpath(process.argv[1]) === fileURLToPath(import.meta.url) ||
|
|
78
|
+
getRealpath(process.argv[1]).replace(/\.[jt]s$/, '') === fileURLToPath(import.meta.url).replace(/\.[jt]s$/, ''));
|
|
79
|
+
if (isMain) {
|
|
80
|
+
// Handle graceful shutdown
|
|
81
|
+
process.on('SIGINT', () => {
|
|
82
|
+
logger.info('\nš Shutting down BusinessMap MCP Server...');
|
|
83
|
+
process.exit(0);
|
|
84
|
+
});
|
|
85
|
+
process.on('SIGTERM', () => {
|
|
86
|
+
logger.info('\nš Shutting down BusinessMap MCP Server...');
|
|
87
|
+
process.exit(0);
|
|
88
|
+
});
|
|
89
|
+
// Start the server
|
|
90
|
+
try {
|
|
91
|
+
await main();
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
console.error('š„ Unhandled error:', error);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
80
97
|
}
|
|
81
98
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/server/http.d.ts
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import { Server } from 'node:http';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
export interface HttpServerOptions {
|
|
4
|
+
middlewares?: express.RequestHandler[];
|
|
5
|
+
}
|
|
6
|
+
export declare function startHttpServer(options?: HttpServerOptions): Promise<Server>;
|
|
2
7
|
//# sourceMappingURL=http.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/server/http.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/server/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,OAAO,OAAO,MAAM,SAAS,CAAC;AAwB9B,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC;CACxC;AAED,wBAAsB,eAAe,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4KtF"}
|
package/dist/server/http.js
CHANGED
|
@@ -15,8 +15,10 @@ async function closeSession(id, session) {
|
|
|
15
15
|
}
|
|
16
16
|
logger.info(`MCP session closed: ${id}`);
|
|
17
17
|
}
|
|
18
|
-
export async function startHttpServer() {
|
|
18
|
+
export async function startHttpServer(options = {}) {
|
|
19
19
|
const app = express();
|
|
20
|
+
// Disable X-Powered-By header to prevent disclosing version/framework info
|
|
21
|
+
app.disable('x-powered-by');
|
|
20
22
|
// Parse JSON bodies (required for StreamableHTTP transport)
|
|
21
23
|
app.use(express.json());
|
|
22
24
|
// Enable CORS with configured allowed origins
|
|
@@ -26,10 +28,17 @@ export async function startHttpServer() {
|
|
|
26
28
|
allowedHeaders: ['Content-Type', 'mcp-session-id', 'last-event-id'],
|
|
27
29
|
exposedHeaders: ['mcp-session-id'],
|
|
28
30
|
}));
|
|
31
|
+
// Apply custom middlewares (e.g. for authentication/authorization)
|
|
32
|
+
if (options.middlewares && options.middlewares.length > 0) {
|
|
33
|
+
options.middlewares.forEach((middleware) => {
|
|
34
|
+
app.use(middleware);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
29
37
|
// Request logging middleware
|
|
30
38
|
app.use((req, _res, next) => {
|
|
31
39
|
const sessionId = req.headers['mcp-session-id'];
|
|
32
|
-
|
|
40
|
+
const sessionSuffix = sessionId ? ` [session: ${sessionId}]` : '';
|
|
41
|
+
logger.debug(`${req.method} ${req.path}${sessionSuffix}`);
|
|
33
42
|
next();
|
|
34
43
|
});
|
|
35
44
|
const sessions = new Map();
|
|
@@ -46,74 +55,82 @@ export async function startHttpServer() {
|
|
|
46
55
|
}, 60_000); // check every minute
|
|
47
56
|
// Prevent the interval from blocking process exit
|
|
48
57
|
cleanupInterval.unref();
|
|
58
|
+
const handleNewSession = async (req, res, logResponse, sendError) => {
|
|
59
|
+
const sessionServer = new BusinessMapMcpServer();
|
|
60
|
+
// New session: create a fresh transport
|
|
61
|
+
const transport = new StreamableHTTPServerTransport({
|
|
62
|
+
sessionIdGenerator: () => randomUUID(),
|
|
63
|
+
onsessioninitialized: (id) => {
|
|
64
|
+
sessions.set(id, { transport, server: sessionServer, lastActivityAt: Date.now() });
|
|
65
|
+
logger.info(`New MCP session initialized: ${id}`);
|
|
66
|
+
},
|
|
67
|
+
onsessionclosed: async (id) => {
|
|
68
|
+
const session = sessions.get(id);
|
|
69
|
+
sessions.delete(id);
|
|
70
|
+
if (session) {
|
|
71
|
+
await closeSession(id, session);
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
allowedHosts: config.server.allowedHosts,
|
|
75
|
+
allowedOrigins: config.server.allowedOrigins,
|
|
76
|
+
enableDnsRebindingProtection: true,
|
|
77
|
+
});
|
|
78
|
+
try {
|
|
79
|
+
await sessionServer.server.connect(transport);
|
|
80
|
+
await transport.handleRequest(req, res, req.body);
|
|
81
|
+
logResponse(res.statusCode);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
logger.error('Failed to handle new MCP session:', error);
|
|
85
|
+
try {
|
|
86
|
+
await sessionServer.server.close();
|
|
87
|
+
}
|
|
88
|
+
catch (closeError) {
|
|
89
|
+
logger.warn('Error while cleaning up failed session:', closeError);
|
|
90
|
+
}
|
|
91
|
+
if (!res.headersSent) {
|
|
92
|
+
sendError(500, 'Failed to initialize MCP session');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
const handleExistingSession = async (req, res, sessionId, logResponse, sendError) => {
|
|
97
|
+
const session = sessions.get(sessionId);
|
|
98
|
+
if (!session) {
|
|
99
|
+
sendError(404, `Session not found: ${sessionId}`);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
session.lastActivityAt = Date.now();
|
|
103
|
+
try {
|
|
104
|
+
await session.transport.handleRequest(req, res, req.body);
|
|
105
|
+
logResponse(res.statusCode);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
logger.error(`Error handling request for session ${sessionId}:`, error);
|
|
109
|
+
if (!res.headersSent) {
|
|
110
|
+
sendError(500, 'Internal server error');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
49
114
|
// Single /mcp endpoint handles GET, POST and DELETE (Streamable HTTP spec 2025-03-26)
|
|
50
115
|
const handleMcpRequest = async (req, res) => {
|
|
51
116
|
const start = Date.now();
|
|
52
117
|
const sessionId = req.headers['mcp-session-id'];
|
|
53
118
|
const logResponse = (statusCode) => {
|
|
54
|
-
|
|
119
|
+
const duration = Date.now() - start;
|
|
120
|
+
const sessionSuffix = sessionId ? ` [session: ${sessionId}]` : '';
|
|
121
|
+
logger.debug(`${req.method} ${req.path} -> ${statusCode} (${duration}ms)${sessionSuffix}`);
|
|
55
122
|
};
|
|
56
123
|
const sendError = (statusCode, message) => {
|
|
57
124
|
logResponse(statusCode);
|
|
58
125
|
res.status(statusCode).json({ error: message });
|
|
59
126
|
};
|
|
60
127
|
if (req.method === 'POST' && !sessionId) {
|
|
61
|
-
|
|
62
|
-
// New session: create a fresh transport
|
|
63
|
-
const transport = new StreamableHTTPServerTransport({
|
|
64
|
-
sessionIdGenerator: () => randomUUID(),
|
|
65
|
-
onsessioninitialized: (id) => {
|
|
66
|
-
sessions.set(id, { transport, server: sessionServer, lastActivityAt: Date.now() });
|
|
67
|
-
logger.info(`New MCP session initialized: ${id}`);
|
|
68
|
-
},
|
|
69
|
-
onsessionclosed: async (id) => {
|
|
70
|
-
const session = sessions.get(id);
|
|
71
|
-
sessions.delete(id);
|
|
72
|
-
if (session) {
|
|
73
|
-
await closeSession(id, session);
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
allowedHosts: config.server.allowedHosts,
|
|
77
|
-
allowedOrigins: config.server.allowedOrigins,
|
|
78
|
-
enableDnsRebindingProtection: true,
|
|
79
|
-
});
|
|
80
|
-
try {
|
|
81
|
-
await sessionServer.server.connect(transport);
|
|
82
|
-
await transport.handleRequest(req, res, req.body);
|
|
83
|
-
logResponse(res.statusCode);
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
logger.error('Failed to handle new MCP session:', error);
|
|
87
|
-
try {
|
|
88
|
-
await sessionServer.server.close();
|
|
89
|
-
}
|
|
90
|
-
catch (closeError) {
|
|
91
|
-
logger.warn('Error while cleaning up failed session:', closeError);
|
|
92
|
-
}
|
|
93
|
-
if (!res.headersSent) {
|
|
94
|
-
sendError(500, 'Failed to initialize MCP session');
|
|
95
|
-
}
|
|
96
|
-
}
|
|
128
|
+
await handleNewSession(req, res, logResponse, sendError);
|
|
97
129
|
return;
|
|
98
130
|
}
|
|
99
131
|
// Existing session
|
|
100
132
|
if (sessionId) {
|
|
101
|
-
|
|
102
|
-
if (!session) {
|
|
103
|
-
sendError(404, `Session not found: ${sessionId}`);
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
session.lastActivityAt = Date.now();
|
|
107
|
-
try {
|
|
108
|
-
await session.transport.handleRequest(req, res, req.body);
|
|
109
|
-
logResponse(res.statusCode);
|
|
110
|
-
}
|
|
111
|
-
catch (error) {
|
|
112
|
-
logger.error(`Error handling request for session ${sessionId}:`, error);
|
|
113
|
-
if (!res.headersSent) {
|
|
114
|
-
sendError(500, 'Internal server error');
|
|
115
|
-
}
|
|
116
|
-
}
|
|
133
|
+
await handleExistingSession(req, res, sessionId, logResponse, sendError);
|
|
117
134
|
return;
|
|
118
135
|
}
|
|
119
136
|
sendError(400, 'Missing mcp-session-id header');
|
|
@@ -126,7 +143,7 @@ export async function startHttpServer() {
|
|
|
126
143
|
res.json({ status: 'ok', version: config.server.version });
|
|
127
144
|
});
|
|
128
145
|
const port = config.server.port;
|
|
129
|
-
app.listen(port, () => {
|
|
146
|
+
return app.listen(port, () => {
|
|
130
147
|
logger.success(`HTTP Server running on port ${port}`);
|
|
131
148
|
logger.info(`MCP Endpoint: http://localhost:${port}/mcp`);
|
|
132
149
|
logger.info(`Health Check: http://localhost:${port}/health`);
|
package/dist/server/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/server/http.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/server/http.ts"],"names":[],"mappings":"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"}
|
package/docs/LOGGING.md
ADDED
|
@@ -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,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
|
+
```
|
package/docs/TOOLS.md
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# Tools, Resources & Prompts Reference
|
|
2
|
+
|
|
3
|
+
Complete reference for all tools, resources, and prompts provided by the BusinessMap MCP Server.
|
|
4
|
+
|
|
5
|
+
## Summary
|
|
6
|
+
|
|
7
|
+
| Category | Count |
|
|
8
|
+
| --------- | :---: |
|
|
9
|
+
| Tools | 56 |
|
|
10
|
+
| Resources | 5 |
|
|
11
|
+
| Prompts | 4 |
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Tools
|
|
16
|
+
|
|
17
|
+
### Workspace Management (3 tools)
|
|
18
|
+
|
|
19
|
+
| Tool | Description | Read-Only Safe |
|
|
20
|
+
| :----------------- | :---------------------------------- | :------------: |
|
|
21
|
+
| `list_workspaces` | Get a list of all workspaces | ā
|
|
|
22
|
+
| `get_workspace` | Get details of a specific workspace | ā
|
|
|
23
|
+
| `create_workspace` | Create a new workspace | ā |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
### Board Management (11 tools)
|
|
28
|
+
|
|
29
|
+
| Tool | Description | Read-Only Safe |
|
|
30
|
+
| :---------------------------- | :--------------------------------------------------------------------------------------------- | :------------: |
|
|
31
|
+
| `list_boards` | Get a list of boards with optional workspace filter | ā
|
|
|
32
|
+
| `search_board` | Search for a board by ID or name, with fallback to list | ā
|
|
|
33
|
+
| `get_columns` | Get all columns for a board | ā
|
|
|
34
|
+
| `get_lanes` | Get all lanes/swimlanes for a board | ā
|
|
|
35
|
+
| `get_lane` | Get details of a specific lane/swimlane | ā
|
|
|
36
|
+
| `get_current_board_structure` | Get the complete structure of a board (workflows, columns, lanes, configs) | ā
|
|
|
37
|
+
| `create_board` | Create a new board in a workspace | ā |
|
|
38
|
+
| `create_lane` | Create a new lane/swimlane in a board | ā |
|
|
39
|
+
| `create_column` | Create a new column (main or sub-column). Section: 1=Backlog, 2=Requested, 3=Progress, 4=Done | ā |
|
|
40
|
+
| `update_column` | Update the details of a specific column | ā |
|
|
41
|
+
| `delete_column` | Delete a column from a board | ā ā ļø |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
### Card Management (36 tools)
|
|
46
|
+
|
|
47
|
+
#### Basic Operations
|
|
48
|
+
|
|
49
|
+
| Tool | Description | Read-Only Safe |
|
|
50
|
+
| :--------------- | :------------------------------------------- | :------------: |
|
|
51
|
+
| `list_cards` | Get cards from a board with optional filters | ā
|
|
|
52
|
+
| `get_card` | Get detailed card information | ā
|
|
|
53
|
+
| `get_card_size` | Get the size/points of a specific card | ā
|
|
|
54
|
+
| `get_card_types` | Get all available card types | ā
|
|
|
55
|
+
| `create_card` | Create a new card in a board | ā |
|
|
56
|
+
| `move_card` | Move a card to a different column or lane | ā |
|
|
57
|
+
| `update_card` | Update card properties | ā |
|
|
58
|
+
| `set_card_size` | Set the size/points of a specific card | ā |
|
|
59
|
+
| `delete_card` | Permanently delete a card (irreversible) | ā ā ļø |
|
|
60
|
+
|
|
61
|
+
#### Comments
|
|
62
|
+
|
|
63
|
+
| Tool | Description | Read-Only Safe |
|
|
64
|
+
| :------------------ | :------------------------------------- | :------------: |
|
|
65
|
+
| `get_card_comments` | Get all comments for a specific card | ā
|
|
|
66
|
+
| `get_card_comment` | Get details of a specific comment | ā
|
|
|
67
|
+
| `create_comment` | Add a new comment to a card | ā |
|
|
68
|
+
| `update_comment` | Update the text of an existing comment | ā |
|
|
69
|
+
| `delete_comment` | Delete a comment from a card | ā ā ļø |
|
|
70
|
+
|
|
71
|
+
#### Custom Fields
|
|
72
|
+
|
|
73
|
+
| Tool | Description | Read-Only Safe |
|
|
74
|
+
| :----------------------- | :---------------------------------------- | :------------: |
|
|
75
|
+
| `get_card_custom_fields` | Get all custom fields for a specific card | ā
|
|
|
76
|
+
|
|
77
|
+
#### Outcomes & History
|
|
78
|
+
|
|
79
|
+
| Tool | Description | Read-Only Safe |
|
|
80
|
+
| :------------------ | :----------------------------------------- | :------------: |
|
|
81
|
+
| `get_card_outcomes` | Get all outcomes for a specific card | ā
|
|
|
82
|
+
| `get_card_history` | Get the history of a specific card outcome | ā
|
|
|
83
|
+
|
|
84
|
+
#### Relationships
|
|
85
|
+
|
|
86
|
+
| Tool | Description | Read-Only Safe |
|
|
87
|
+
| :---------------------- | :--------------------------------------- | :------------: |
|
|
88
|
+
| `get_card_linked_cards` | Get all linked cards for a specific card | ā
|
|
|
89
|
+
|
|
90
|
+
#### Subtasks
|
|
91
|
+
|
|
92
|
+
| Tool | Description | Read-Only Safe |
|
|
93
|
+
| :-------------------- | :----------------------------------- | :------------: |
|
|
94
|
+
| `get_card_subtasks` | Get all subtasks for a specific card | ā
|
|
|
95
|
+
| `get_card_subtask` | Get details of a specific subtask | ā
|
|
|
96
|
+
| `create_card_subtask` | Create a new subtask for a card | ā |
|
|
97
|
+
|
|
98
|
+
#### Parent-Child Relationships
|
|
99
|
+
|
|
100
|
+
| Tool | Description | Read-Only Safe |
|
|
101
|
+
| :---------------------- | :----------------------------------------------------- | :------------: |
|
|
102
|
+
| `get_card_parents` | Get a list of parent cards for a specific card | ā
|
|
|
103
|
+
| `get_card_parent` | Check if a card is a parent of a given card | ā
|
|
|
104
|
+
| `get_card_parent_graph` | Get parent cards including their parents (full graph) | ā
|
|
|
105
|
+
| `get_card_children` | Get a list of child cards of a specified parent card | ā
|
|
|
106
|
+
| `add_card_parent` | Make a card a parent of a given card | ā |
|
|
107
|
+
| `remove_card_parent` | Remove the link between a child card and a parent card | ā |
|
|
108
|
+
|
|
109
|
+
#### Blocking
|
|
110
|
+
|
|
111
|
+
| Tool | Description | Read-Only Safe |
|
|
112
|
+
| :------------- | :------------------------------------------ | :------------: |
|
|
113
|
+
| `block_card` | Block a card and set a reason/comment | ā |
|
|
114
|
+
| `unblock_card` | Unblock a card by removing its block reason | ā |
|
|
115
|
+
|
|
116
|
+
#### Tags
|
|
117
|
+
|
|
118
|
+
| Tool | Description | Read-Only Safe |
|
|
119
|
+
| :--------------------- | :-------------------------------- | :------------: |
|
|
120
|
+
| `create_tag` | Create a new tag in the workspace | ā |
|
|
121
|
+
| `add_tag_to_card` | Add an existing tag to a card | ā |
|
|
122
|
+
| `remove_tag_from_card` | Remove a tag from a card | ā |
|
|
123
|
+
|
|
124
|
+
#### Stickers
|
|
125
|
+
|
|
126
|
+
| Tool | Description | Read-Only Safe |
|
|
127
|
+
| :------------------------- | :----------------------------------------------------------------- | :------------: |
|
|
128
|
+
| `add_sticker_to_card` | Add a sticker to a card | ā |
|
|
129
|
+
| `remove_sticker_from_card` | Remove a sticker from a card using the sticker-card association ID | ā |
|
|
130
|
+
|
|
131
|
+
#### Predecessors
|
|
132
|
+
|
|
133
|
+
| Tool | Description | Read-Only Safe |
|
|
134
|
+
| :------------------- | :------------------------------------------------------------------------- | :------------: |
|
|
135
|
+
| `add_predecessor` | Establish or update a predecessor-successor relationship between two cards | ā |
|
|
136
|
+
| `remove_predecessor` | Remove the predecessor-successor relationship between two cards | ā |
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
### Custom Field Management (1 tool)
|
|
141
|
+
|
|
142
|
+
| Tool | Description | Read-Only Safe |
|
|
143
|
+
| :----------------- | :------------------------------------------- | :------------: |
|
|
144
|
+
| `get_custom_field` | Get details of a specific custom field by ID | ā
|
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
### Workflow & Cycle Time Analysis (2 tools)
|
|
149
|
+
|
|
150
|
+
| Tool | Description | Read-Only Safe |
|
|
151
|
+
| :------------------------------------------ | :------------------------------------------ | :------------: |
|
|
152
|
+
| `get_workflow_cycle_time_columns` | Get workflow's cycle time columns | ā
|
|
|
153
|
+
| `get_workflow_effective_cycle_time_columns` | Get workflow's effective cycle time columns | ā
|
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
### User Management (4 tools)
|
|
158
|
+
|
|
159
|
+
| Tool | Description | Read-Only Safe |
|
|
160
|
+
| :----------------- | :------------------------------------- | :------------: |
|
|
161
|
+
| `list_users` | Get a list of all users | ā
|
|
|
162
|
+
| `get_user` | Get details of a specific user | ā
|
|
|
163
|
+
| `get_current_user` | Get details of the current logged user | ā
|
|
|
164
|
+
| `invite_user` | Add and invite a new user by email | ā |
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
### System (2 tools)
|
|
169
|
+
|
|
170
|
+
| Tool | Description | Read-Only Safe |
|
|
171
|
+
| :------------- | :---------------------------------------- | :------------: |
|
|
172
|
+
| `health_check` | Check the connection to BusinessMap API | ā
|
|
|
173
|
+
| `get_api_info` | Get information about the BusinessMap API | ā
|
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Resources
|
|
178
|
+
|
|
179
|
+
MCP resources provide structured data access via URI. Clients can read resources directly without invoking tools.
|
|
180
|
+
|
|
181
|
+
| URI | Name | Description | Listable |
|
|
182
|
+
| :-------------------------------------- | :----------- | :---------------------------------- | :------: |
|
|
183
|
+
| `businessmap://workspaces` | `workspaces` | List all workspaces | ā
|
|
|
184
|
+
| `businessmap://boards` | `boards` | List all boards | ā
|
|
|
185
|
+
| `businessmap://boards/{board_id}` | `board` | Get details of a specific board | ā |
|
|
186
|
+
| `businessmap://boards/{board_id}/cards` | `cards` | List all cards for a specific board | ā
|
|
|
187
|
+
| `businessmap://cards/{card_id}` | `card` | Get details of a specific card | ā |
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Prompts
|
|
192
|
+
|
|
193
|
+
MCP prompts provide guided, multi-step workflows for common AI-assisted tasks.
|
|
194
|
+
|
|
195
|
+
### `analyze-board-performance`
|
|
196
|
+
|
|
197
|
+
**Title:** Analyze Board Performance
|
|
198
|
+
|
|
199
|
+
Analyze a board's performance: flow efficiency, bottlenecks, cycle time, and workload distribution across columns and lanes.
|
|
200
|
+
|
|
201
|
+
**Arguments:**
|
|
202
|
+
|
|
203
|
+
- `board_id` (required) ā The board ID to analyze
|
|
204
|
+
|
|
205
|
+
**Workflow:**
|
|
206
|
+
|
|
207
|
+
1. Uses `get_current_board_structure` to retrieve the full board structure
|
|
208
|
+
2. Uses `list_cards` to retrieve all active cards
|
|
209
|
+
3. Uses `get_workflow_cycle_time_columns` for each workflow
|
|
210
|
+
4. Delivers a structured analysis covering flow efficiency, cycle time, workload distribution, and actionable recommendations
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
### `generate-board-report`
|
|
215
|
+
|
|
216
|
+
**Title:** Generate Board Report
|
|
217
|
+
|
|
218
|
+
Generate a comprehensive status report for a board, including cards summary, progress, and highlights.
|
|
219
|
+
|
|
220
|
+
**Arguments:**
|
|
221
|
+
|
|
222
|
+
- `board_id` (required) ā The board ID to report on
|
|
223
|
+
|
|
224
|
+
**Workflow:**
|
|
225
|
+
|
|
226
|
+
1. Uses `get_current_board_structure` to get the board structure
|
|
227
|
+
2. Uses `list_cards` to get all cards
|
|
228
|
+
3. Uses `get_card` for detailed info on a sample of cards
|
|
229
|
+
4. Generates a structured report with: Executive Summary, Column Breakdown, Recently Updated Cards, Risks & Blockers, and Next Steps
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
### `create-card-from-description`
|
|
234
|
+
|
|
235
|
+
**Title:** Create Card from Description
|
|
236
|
+
|
|
237
|
+
Guide the creation of a well-structured card from a natural language description.
|
|
238
|
+
|
|
239
|
+
**Arguments:**
|
|
240
|
+
|
|
241
|
+
- `description` (required) ā Natural language description of what the card should be
|
|
242
|
+
- `board_id` (required) ā The board ID where the card should be created
|
|
243
|
+
|
|
244
|
+
**Workflow:**
|
|
245
|
+
|
|
246
|
+
1. Uses `get_current_board_structure` to understand available columns, lanes, and workflows
|
|
247
|
+
2. Uses `get_card_types` to list available card types
|
|
248
|
+
3. Determines the best card title, description, type, target column, lane, and size/priority
|
|
249
|
+
4. Uses `create_card` to create the card and confirms creation with ID and summary
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
### `workspace-status-overview`
|
|
254
|
+
|
|
255
|
+
**Title:** Workspace Status Overview
|
|
256
|
+
|
|
257
|
+
Generate a high-level status overview of a workspace, including all boards and their key metrics.
|
|
258
|
+
|
|
259
|
+
**Arguments:**
|
|
260
|
+
|
|
261
|
+
- `workspace_id` (required) ā The workspace ID to generate an overview for
|
|
262
|
+
|
|
263
|
+
**Workflow:**
|
|
264
|
+
|
|
265
|
+
1. Uses `get_workspace` to get workspace details
|
|
266
|
+
2. Uses `list_boards` with `workspace_id` filter to list all boards
|
|
267
|
+
3. Uses `list_cards` for each board to get active card counts
|
|
268
|
+
4. Uses `get_current_board_structure` for up to 3 boards
|
|
269
|
+
5. Delivers a structured overview with: Workspace Summary, Board Summaries, Highlights, and Recommendations
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Read-Only Mode
|
|
274
|
+
|
|
275
|
+
When `BUSINESSMAP_READ_ONLY_MODE=true`, only tools marked ā
in the "Read-Only Safe" column are registered. Write operations (ā) are not available. This is useful for:
|
|
276
|
+
|
|
277
|
+
- Safe data exploration without risk of modifications
|
|
278
|
+
- Granting read-only access to AI assistants
|
|
279
|
+
- Auditing and reporting use cases
|
|
280
|
+
|
|
281
|
+
> Note: All 5 resources and all 4 prompts are available regardless of read-only mode setting.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edicarlos.lds/businessmap-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Model Context Protocol server for BusinessMap (Kanbanize) integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
|
12
|
+
"docs",
|
|
12
13
|
"README.md",
|
|
13
14
|
"LICENSE"
|
|
14
15
|
],
|