@baruchiro/actual-mcp
Version:
Actual Budget MCP server exposing API functionality
120 lines • 4.12 kB
JavaScript
// ----------------------------
// RESPONSE UTILITIES
// ----------------------------
/**
* Create a successful plain text response
* @param text - The text message
* @returns A success response object with text content
*/
export function success(text) {
return {
content: [{ type: 'text', text }],
};
}
/**
* Create a success response with structured content
* @param content - Array of content items
* @returns A success response object with provided content
*/
export function successWithContent(content) {
return {
content: [content],
};
}
/**
* Create a success response with JSON data
* @param data - Any data object that can be JSON-stringified
* @returns A success response with JSON data wrapped as a resource
*/
export function successWithJson(data) {
return {
content: [
{
type: 'text',
text: JSON.stringify(data),
},
],
};
}
/**
* Create an error response
* @param message - The error message
* @param context - Optional tool name and stable error code
* @returns An error response object
*/
export function error(message, context = {}) {
const prefix = context.toolName ? `Error in ${context.toolName}` : 'Error';
const codeSuffix = context.code ? ` [${context.code}]` : '';
const result = {
isError: true,
content: [{ type: 'text', text: `${prefix}${codeSuffix}: ${message}` }],
};
if (context.code || context.toolName) {
result._meta = {
...(context.code ? { code: context.code } : {}),
...(context.toolName ? { tool: context.toolName } : {}),
};
}
return result;
}
/**
* Best-effort extraction of a useful message and code from any thrown value.
* Handles `Error` instances, plain objects with `message`/`error`/`reason`
* properties, strings, and falls back to JSON for unknown shapes.
*/
export function normalizeError(err) {
if (err instanceof Error) {
const codeValue = err.code;
return {
message: err.message || err.name || 'Unknown error',
name: err.name,
stack: err.stack,
...(typeof codeValue === 'string' ? { code: codeValue } : {}),
};
}
if (typeof err === 'string') {
return { message: err };
}
if (err === null || err === undefined) {
return { message: String(err) };
}
if (typeof err === 'object') {
const record = err;
const messageCandidates = [record.message, record.error, record.reason, record.description, record.detail];
const message = messageCandidates.find((value) => typeof value === 'string' && value.length > 0);
const code = typeof record.code === 'string' ? record.code : undefined;
if (message) {
return { message, ...(code ? { code } : {}) };
}
// No usable string field — fall through to JSON serialization so the
// client at least sees the shape of the object instead of "[object Object]".
try {
const serialized = JSON.stringify(err);
if (serialized && serialized !== '{}') {
return { message: serialized, ...(code ? { code } : {}) };
}
}
catch {
// circular or otherwise unserializable
}
return { message: 'Unknown error (non-serializable object thrown)', ...(code ? { code } : {}) };
}
return { message: String(err) };
}
/**
* Create an error response from an Error object or any thrown value.
* Extracts a usable message even from non-Error rejections (plain objects,
* strings, etc.) so clients never see "[object Object]".
*
* @param err - The error object or value
* @param context - Optional tool name and stable error code for the response
* @returns An error response object
*/
export function errorFromCatch(err, context = {}) {
const normalized = normalizeError(err);
return error(normalized.message, {
...context,
code: context.code ?? normalized.code,
});
}
//# sourceMappingURL=response.js.map