pulsemcp-cms-admin-mcp-server 0.9.11 → 0.9.13

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.
@@ -21,7 +21,8 @@ export function extractExamId(line) {
21
21
  */
22
22
  export function extractStatus(line) {
23
23
  const data = line.data;
24
- return data?.status || line.status || 'unknown';
24
+ const result = data?.result;
25
+ return (result?.status || data?.status || line.status || 'unknown');
25
26
  }
26
27
  /**
27
28
  * Maximum number of results to keep on disk. Oldest results are evicted
@@ -3,7 +3,7 @@ export async function uploadImage(apiKey, baseUrl, postSlug, fileName, fileData)
3
3
  // Create form data for multipart upload
4
4
  const formData = new FormData();
5
5
  // Create a blob from the buffer
6
- const blob = new Blob([fileData], { type: 'image/png' }); // Default to PNG, adjust as needed
6
+ const blob = new Blob([new Uint8Array(fileData)], { type: 'image/png' });
7
7
  // Add file to form data
8
8
  formData.append('file', blob, fileName);
9
9
  // Add folder and filepath as documented in the API
@@ -67,9 +67,16 @@ Typical usage:
67
67
  const targetType = typeMap[validatedArgs.section];
68
68
  lines = lines.filter((line) => line.type === targetType);
69
69
  }
70
- // Filter by mirror_id
70
+ // Filter by mirror_id — check both top-level and data.mirror_id
71
+ // since the backend nests mirror_id inside the data payload.
71
72
  if (validatedArgs.mirror_id !== undefined) {
72
- lines = lines.filter((line) => line.type !== 'exam_result' || line.mirror_id === validatedArgs.mirror_id);
73
+ lines = lines.filter((line) => {
74
+ if (line.type !== 'exam_result')
75
+ return true;
76
+ const data = line.data;
77
+ const mirrorId = line.mirror_id ?? data?.mirror_id;
78
+ return mirrorId === validatedArgs.mirror_id;
79
+ });
73
80
  }
74
81
  let content = `**Exam Result Details**\n\n`;
75
82
  content += `Result ID: ${stored.result_id}\n`;
@@ -24,7 +24,6 @@ function truncateExamResultData(data) {
24
24
  const truncated = {};
25
25
  for (const [key, value] of Object.entries(data)) {
26
26
  if (key === 'tools' && Array.isArray(value)) {
27
- // For tool listings, include only name and description, omit inputSchema
28
27
  truncated[key] = value.map((tool) => ({
29
28
  name: tool.name,
30
29
  ...(tool.description ? { description: String(tool.description).slice(0, 100) } : {}),
@@ -33,20 +32,18 @@ function truncateExamResultData(data) {
33
32
  truncated['tools_truncated'] = true;
34
33
  }
35
34
  else if (key === 'inputSchema' || key === 'input_schema') {
36
- // Omit full input schemas
37
35
  truncated[key] = '(truncated — use get_exam_result to see full data)';
38
36
  }
39
- else if (typeof value === 'string' && value.length > 500) {
40
- truncated[key] = value.slice(0, 500) + '... (truncated)';
37
+ else if (typeof value === 'string' && value.length > 2000) {
38
+ truncated[key] = value.slice(0, 2000) + '... (truncated)';
39
+ }
40
+ else if (Array.isArray(value)) {
41
+ truncated[key] = value.map((item) => typeof item === 'object' && item !== null
42
+ ? truncateExamResultData(item)
43
+ : item);
41
44
  }
42
45
  else if (typeof value === 'object' && value !== null) {
43
- const serialized = JSON.stringify(value);
44
- if (serialized.length > 1000) {
45
- truncated[key] = '(truncated — use get_exam_result to see full data)';
46
- }
47
- else {
48
- truncated[key] = value;
49
- }
46
+ truncated[key] = truncateExamResultData(value);
50
47
  }
51
48
  else {
52
49
  truncated[key] = value;
@@ -131,13 +128,15 @@ Use cases:
131
128
  }
132
129
  break;
133
130
  }
134
- case 'summary':
131
+ case 'summary': {
132
+ const summaryData = line.data;
135
133
  content += `\n**Summary**\n`;
136
- content += ` Total: ${line.total || 0}\n`;
137
- content += ` Passed: ${line.passed || 0}\n`;
138
- content += ` Failed: ${line.failed || 0}\n`;
139
- content += ` Skipped: ${line.skipped || 0}\n`;
134
+ content += ` Total: ${summaryData?.total_exams ?? line.total ?? 0}\n`;
135
+ content += ` Passed: ${summaryData?.successful ?? line.passed ?? 0}\n`;
136
+ content += ` Failed: ${summaryData?.failed ?? line.failed ?? 0}\n`;
137
+ content += ` Skipped: ${summaryData?.skipped ?? line.skipped ?? 0}\n`;
140
138
  break;
139
+ }
141
140
  case 'error':
142
141
  content += `\n**Error**: ${line.message || line.error || JSON.stringify(line)}\n`;
143
142
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pulsemcp-cms-admin-mcp-server",
3
- "version": "0.9.11",
3
+ "version": "0.9.13",
4
4
  "description": "Local implementation of PulseMCP CMS Admin MCP server",
5
5
  "mcpName": "com.pulsemcp.servers/pulsemcp-cms-admin",
6
6
  "main": "build/index.js",
@@ -21,7 +21,8 @@ export function extractExamId(line) {
21
21
  */
22
22
  export function extractStatus(line) {
23
23
  const data = line.data;
24
- return data?.status || line.status || 'unknown';
24
+ const result = data?.result;
25
+ return (result?.status || data?.status || line.status || 'unknown');
25
26
  }
26
27
  /**
27
28
  * Maximum number of results to keep on disk. Oldest results are evicted
@@ -3,7 +3,7 @@ export async function uploadImage(apiKey, baseUrl, postSlug, fileName, fileData)
3
3
  // Create form data for multipart upload
4
4
  const formData = new FormData();
5
5
  // Create a blob from the buffer
6
- const blob = new Blob([fileData], { type: 'image/png' }); // Default to PNG, adjust as needed
6
+ const blob = new Blob([new Uint8Array(fileData)], { type: 'image/png' });
7
7
  // Add file to form data
8
8
  formData.append('file', blob, fileName);
9
9
  // Add folder and filepath as documented in the API
@@ -67,9 +67,16 @@ Typical usage:
67
67
  const targetType = typeMap[validatedArgs.section];
68
68
  lines = lines.filter((line) => line.type === targetType);
69
69
  }
70
- // Filter by mirror_id
70
+ // Filter by mirror_id — check both top-level and data.mirror_id
71
+ // since the backend nests mirror_id inside the data payload.
71
72
  if (validatedArgs.mirror_id !== undefined) {
72
- lines = lines.filter((line) => line.type !== 'exam_result' || line.mirror_id === validatedArgs.mirror_id);
73
+ lines = lines.filter((line) => {
74
+ if (line.type !== 'exam_result')
75
+ return true;
76
+ const data = line.data;
77
+ const mirrorId = line.mirror_id ?? data?.mirror_id;
78
+ return mirrorId === validatedArgs.mirror_id;
79
+ });
73
80
  }
74
81
  let content = `**Exam Result Details**\n\n`;
75
82
  content += `Result ID: ${stored.result_id}\n`;
@@ -24,7 +24,6 @@ function truncateExamResultData(data) {
24
24
  const truncated = {};
25
25
  for (const [key, value] of Object.entries(data)) {
26
26
  if (key === 'tools' && Array.isArray(value)) {
27
- // For tool listings, include only name and description, omit inputSchema
28
27
  truncated[key] = value.map((tool) => ({
29
28
  name: tool.name,
30
29
  ...(tool.description ? { description: String(tool.description).slice(0, 100) } : {}),
@@ -33,20 +32,18 @@ function truncateExamResultData(data) {
33
32
  truncated['tools_truncated'] = true;
34
33
  }
35
34
  else if (key === 'inputSchema' || key === 'input_schema') {
36
- // Omit full input schemas
37
35
  truncated[key] = '(truncated — use get_exam_result to see full data)';
38
36
  }
39
- else if (typeof value === 'string' && value.length > 500) {
40
- truncated[key] = value.slice(0, 500) + '... (truncated)';
37
+ else if (typeof value === 'string' && value.length > 2000) {
38
+ truncated[key] = value.slice(0, 2000) + '... (truncated)';
39
+ }
40
+ else if (Array.isArray(value)) {
41
+ truncated[key] = value.map((item) => typeof item === 'object' && item !== null
42
+ ? truncateExamResultData(item)
43
+ : item);
41
44
  }
42
45
  else if (typeof value === 'object' && value !== null) {
43
- const serialized = JSON.stringify(value);
44
- if (serialized.length > 1000) {
45
- truncated[key] = '(truncated — use get_exam_result to see full data)';
46
- }
47
- else {
48
- truncated[key] = value;
49
- }
46
+ truncated[key] = truncateExamResultData(value);
50
47
  }
51
48
  else {
52
49
  truncated[key] = value;
@@ -131,13 +128,15 @@ Use cases:
131
128
  }
132
129
  break;
133
130
  }
134
- case 'summary':
131
+ case 'summary': {
132
+ const summaryData = line.data;
135
133
  content += `\n**Summary**\n`;
136
- content += ` Total: ${line.total || 0}\n`;
137
- content += ` Passed: ${line.passed || 0}\n`;
138
- content += ` Failed: ${line.failed || 0}\n`;
139
- content += ` Skipped: ${line.skipped || 0}\n`;
134
+ content += ` Total: ${summaryData?.total_exams ?? line.total ?? 0}\n`;
135
+ content += ` Passed: ${summaryData?.successful ?? line.passed ?? 0}\n`;
136
+ content += ` Failed: ${summaryData?.failed ?? line.failed ?? 0}\n`;
137
+ content += ` Skipped: ${summaryData?.skipped ?? line.skipped ?? 0}\n`;
140
138
  break;
139
+ }
141
140
  case 'error':
142
141
  content += `\n**Error**: ${line.message || line.error || JSON.stringify(line)}\n`;
143
142
  break;