@blackenedd18/planio-connector 2026.623.2
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/.env.example +9 -0
- package/LICENSE +15 -0
- package/README.md +101 -0
- package/Redmine-functions/README.md +14 -0
- package/Redmine-functions/index.js +648 -0
- package/Redmine-functions/package.json +5 -0
- package/package.json +48 -0
- package/src/index.js +16 -0
- package/src/modules/hours/index.js +195 -0
- package/src/modules/issues/index.js +281 -0
- package/src/modules/projects/index.js +62 -0
- package/src/modules/time-entries/index.js +267 -0
- package/src/modules/users/index.js +87 -0
- package/src/server.js +87 -0
- package/src/shared/config.js +84 -0
- package/src/shared/date-validation.js +45 -0
- package/src/shared/logger.js +48 -0
- package/src/shared/redmine-functions-adapter.js +58 -0
- package/src/shared/redmine-functions-contract.js +4 -0
- package/src/shared/redmine-functions-entry.js +3 -0
- package/src/shared/request.js +97 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { logDebug, logError } from './logger.js';
|
|
3
|
+
import { getRuntimeConfig } from './config.js';
|
|
4
|
+
import { callRedmineFunctionAdapter } from './redmine-functions-adapter.js';
|
|
5
|
+
|
|
6
|
+
function buildResponsePayload(_method, data) {
|
|
7
|
+
const text =
|
|
8
|
+
typeof data === 'string' ? data :
|
|
9
|
+
data == null ? '' :
|
|
10
|
+
JSON.stringify(data);
|
|
11
|
+
|
|
12
|
+
let structuredContent;
|
|
13
|
+
if (Array.isArray(data)) {
|
|
14
|
+
structuredContent = { items: data };
|
|
15
|
+
} else if (typeof data === 'object' && data !== null) {
|
|
16
|
+
structuredContent = data;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const response = {
|
|
20
|
+
content: [{ type: 'text', text }],
|
|
21
|
+
};
|
|
22
|
+
if (structuredContent !== undefined) {
|
|
23
|
+
response.structuredContent = structuredContent;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
logDebug('[request.buildResponsePayload] Response shape normalized', {
|
|
27
|
+
contentTextLength: text.length,
|
|
28
|
+
hasStructuredContent: structuredContent !== undefined,
|
|
29
|
+
structuredKind: Array.isArray(data) ? 'array_as_items' : (typeof data),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return response;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function makeRequest(method, endpoint, params = undefined, body = undefined) {
|
|
36
|
+
const config = getRuntimeConfig();
|
|
37
|
+
|
|
38
|
+
logDebug('[request.makeRequest] Auth header strategy selected', {
|
|
39
|
+
headerName: 'X-Redmine-API-Key',
|
|
40
|
+
authSource: 'CLI_OR_ENV',
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
logDebug('[request.makeRequest] Sending request', {
|
|
44
|
+
method,
|
|
45
|
+
endpoint,
|
|
46
|
+
paramKeys: params ? Object.keys(params) : [],
|
|
47
|
+
transport: 'local-redmine-functions',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const data = await callRedmineFunctionAdapter({
|
|
52
|
+
method,
|
|
53
|
+
endpoint,
|
|
54
|
+
params,
|
|
55
|
+
body,
|
|
56
|
+
apiKey: config.redmineApiKey,
|
|
57
|
+
redmineUrl: config.redmineUrl,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
logDebug('[request.makeRequest] Request success', {
|
|
61
|
+
method,
|
|
62
|
+
endpoint,
|
|
63
|
+
transport: 'local-redmine-functions',
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return buildResponsePayload(method, data);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if (error instanceof McpError) {
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const status = error?.status;
|
|
73
|
+
const detail = error?.message || 'Unknown local function error';
|
|
74
|
+
const remediation =
|
|
75
|
+
status === 401 || status === 403
|
|
76
|
+
? 'Verify REDMINE_API_KEY is set and accepted by Redmine API.'
|
|
77
|
+
: status === 422
|
|
78
|
+
? 'Verify request parameters match Redmine controller validation rules (types, enums, and date formats).'
|
|
79
|
+
: status === 501
|
|
80
|
+
? 'Required local Redmine-function handler is missing. Ensure Redmine-functions exports requested endpoint handlers.'
|
|
81
|
+
: undefined;
|
|
82
|
+
|
|
83
|
+
logError('[request.makeRequest] Request failed', {
|
|
84
|
+
method,
|
|
85
|
+
endpoint,
|
|
86
|
+
status,
|
|
87
|
+
detail,
|
|
88
|
+
remediation,
|
|
89
|
+
transport: 'local-redmine-functions',
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
throw new McpError(
|
|
93
|
+
ErrorCode.InternalError,
|
|
94
|
+
`Redmine API request failed${status ? ` (${status})` : ''}: ${detail}${remediation ? ` ${remediation}` : ''}`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}
|