@blackenedd18/planio-connector 2026.623.3 → 2026.702.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/package.json +1 -1
- package/src/modules/help/index.js +79 -0
- package/src/modules/issues/index.js +25 -0
- package/src/server.js +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blackenedd18/planio-connector",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.702.0",
|
|
4
4
|
"description": "MCP server exposing Planio/Redmine operations (users, issues, projects, hours, time entries) over stdio",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { logDebug, logError } from '../../shared/logger.js';
|
|
3
|
+
|
|
4
|
+
const WIKI_FORMATTING_HELP_URL =
|
|
5
|
+
'https://redmine.ameria.de/help/en/wiki_syntax_detailed_textile.html';
|
|
6
|
+
|
|
7
|
+
export const TOOLS = [
|
|
8
|
+
{
|
|
9
|
+
name: 'get_wiki_formatting_help',
|
|
10
|
+
description:
|
|
11
|
+
'Returns the HTML help page describing Textile/wiki formatting syntax used in issue notes and descriptions.',
|
|
12
|
+
inputSchema: {
|
|
13
|
+
type: 'object',
|
|
14
|
+
properties: {},
|
|
15
|
+
additionalProperties: false,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
function logToolStart(name, args) {
|
|
21
|
+
logDebug('[help.dispatch] Handling tool', {
|
|
22
|
+
toolName: name,
|
|
23
|
+
argumentKeys: Object.keys(args || {}),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function fetchWikiFormattingHelp() {
|
|
28
|
+
logDebug('[help.fetchWikiFormattingHelp] Fetching help page', {
|
|
29
|
+
url: WIKI_FORMATTING_HELP_URL,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const response = await fetch(WIKI_FORMATTING_HELP_URL);
|
|
33
|
+
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new McpError(
|
|
36
|
+
ErrorCode.InternalError,
|
|
37
|
+
`Failed to fetch wiki formatting help page (${response.status}). Verify the help page is reachable at ${WIKI_FORMATTING_HELP_URL}.`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const html = await response.text();
|
|
42
|
+
|
|
43
|
+
logDebug('[help.fetchWikiFormattingHelp] Help page fetched', {
|
|
44
|
+
status: response.status,
|
|
45
|
+
contentLength: html.length,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return html;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function dispatch(name, args = {}) {
|
|
52
|
+
try {
|
|
53
|
+
switch (name) {
|
|
54
|
+
case 'get_wiki_formatting_help': {
|
|
55
|
+
logToolStart(name, args);
|
|
56
|
+
const html = await fetchWikiFormattingHelp();
|
|
57
|
+
return {
|
|
58
|
+
content: [{ type: 'text', text: html }],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
default:
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
logError('[help.dispatch] Tool execution failed', {
|
|
66
|
+
toolName: name,
|
|
67
|
+
message: error?.message,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
if (error instanceof McpError) {
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
throw new McpError(
|
|
75
|
+
ErrorCode.InternalError,
|
|
76
|
+
`Wiki formatting help request failed: ${error?.message || 'Unknown error'}`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -141,6 +141,21 @@ export const TOOLS = [
|
|
|
141
141
|
additionalProperties: false,
|
|
142
142
|
},
|
|
143
143
|
},
|
|
144
|
+
{
|
|
145
|
+
name: 'add_note_to_issue_by_id',
|
|
146
|
+
description:
|
|
147
|
+
'Add a note (comment) to an existing issue by its ID via PUT /issues/{issue_id}.json. Set private_notes to true to add a private note.',
|
|
148
|
+
inputSchema: {
|
|
149
|
+
type: 'object',
|
|
150
|
+
properties: {
|
|
151
|
+
issue_id: { type: 'number' },
|
|
152
|
+
notes: { type: 'string', description: 'The comment text to add to the issue.' },
|
|
153
|
+
private_notes: { type: 'boolean', description: 'Optional. Mark the note as private.' },
|
|
154
|
+
},
|
|
155
|
+
required: ['issue_id', 'notes'],
|
|
156
|
+
additionalProperties: false,
|
|
157
|
+
},
|
|
158
|
+
},
|
|
144
159
|
];
|
|
145
160
|
|
|
146
161
|
function logToolStart(name, args) {
|
|
@@ -268,6 +283,16 @@ export async function dispatch(name, args = {}) {
|
|
|
268
283
|
};
|
|
269
284
|
return makeRequest('POST', 'issues', undefined, payload);
|
|
270
285
|
}
|
|
286
|
+
case 'add_note_to_issue_by_id': {
|
|
287
|
+
logToolStart(name, args);
|
|
288
|
+
ensureRequiredNumber(args, 'issue_id');
|
|
289
|
+
ensureRequiredString(args, 'notes');
|
|
290
|
+
const payload = { notes: args.notes };
|
|
291
|
+
if (args.private_notes !== undefined && args.private_notes !== null) {
|
|
292
|
+
payload.private_notes = args.private_notes;
|
|
293
|
+
}
|
|
294
|
+
return makeRequest('PUT', `issues/${args.issue_id}`, undefined, payload);
|
|
295
|
+
}
|
|
271
296
|
default:
|
|
272
297
|
return null;
|
|
273
298
|
}
|
package/src/server.js
CHANGED
|
@@ -15,10 +15,11 @@ import * as issues from './modules/issues/index.js';
|
|
|
15
15
|
import * as projects from './modules/projects/index.js';
|
|
16
16
|
import * as hours from './modules/hours/index.js';
|
|
17
17
|
import * as timeEntries from './modules/time-entries/index.js';
|
|
18
|
+
import * as help from './modules/help/index.js';
|
|
18
19
|
|
|
19
20
|
const { version: SERVER_VERSION } = createRequire(import.meta.url)('../package.json');
|
|
20
21
|
const SERVER_NAME = 'planio-connector-mcp';
|
|
21
|
-
const MODULES = [users, issues, projects, hours, timeEntries];
|
|
22
|
+
const MODULES = [users, issues, projects, hours, timeEntries, help];
|
|
22
23
|
|
|
23
24
|
export class RedmineServer {
|
|
24
25
|
constructor() {
|