pocketsmith-mcp
Version:
MCP server for managing budgets via PocketSmith API
119 lines (118 loc) • 5.37 kB
JavaScript
/**
* @fileoverview Delete a transaction from PocketSmith
*/
import { z } from "zod";
import { BaseErrorCode, McpError } from "../../../types-global/errors.js";
import { ErrorHandler, logger, requestContextService, } from "../../../utils/index.js";
import { PocketSmithService } from "../../../services/pocketsmith.js";
export const DeleteTransactionInputSchema = z.object({
apiKey: z.string().optional().describe("PocketSmith API key (if not set via environment)"),
accessToken: z.string().optional().describe("OAuth access token (if not using API key)"),
transactionId: z.number().int().describe("ID of the transaction to delete"),
confirm: z.boolean().optional().default(false).describe("Confirm deletion (required to be true)"),
});
export const DeleteTransactionResponseSchema = z.object({
deletedTransaction: z.object({
id: z.number(),
payee: z.string(),
amount: z.number(),
date: z.string(),
category: z.string().optional(),
account: z.string(),
}).describe("Details of the deleted transaction"),
success: z.boolean().describe("Whether the transaction was deleted successfully"),
message: z.string().describe("Confirmation message"),
});
export async function deleteTransactionLogic(params, context) {
logger.debug("Processing delete transaction request", {
...context,
toolInput: { ...params, apiKey: "[REDACTED]", accessToken: "[REDACTED]" },
});
if (!params.confirm) {
throw new McpError(BaseErrorCode.VALIDATION_ERROR, "Transaction deletion must be confirmed by setting 'confirm' to true. This action cannot be undone.");
}
const apiKey = params.apiKey || process.env.POCKETSMITH_API_KEY;
const accessToken = params.accessToken || process.env.POCKETSMITH_ACCESS_TOKEN;
const service = new PocketSmithService(apiKey, accessToken);
// Get the transaction details before deleting for the response
const transaction = await service.getTransaction(params.transactionId, context);
// Delete the transaction
await service.deleteTransaction(params.transactionId, context);
const response = {
deletedTransaction: {
id: transaction.id ?? 0,
payee: transaction.payee ?? '',
amount: transaction.amount ?? 0,
date: transaction.date ?? '',
category: transaction.category?.title,
account: transaction.transaction_account?.name ?? '',
},
success: true,
message: `Transaction "${transaction.payee}" for ${transaction.amount} on ${transaction.date} has been permanently deleted.`,
};
logger.debug("Delete transaction processed successfully", {
...context,
transactionId: params.transactionId,
payee: transaction.payee,
});
return response;
}
export const registerDeleteTransactionTool = async (server) => {
const toolName = "delete_transaction";
const toolDescription = "Delete a transaction from PocketSmith (permanent action)";
const registrationContext = requestContextService.createRequestContext({
operation: "RegisterTool",
toolName: toolName,
});
logger.info(`Registering tool: '${toolName}'`, registrationContext);
await ErrorHandler.tryCatch(async () => {
server.registerTool(toolName, {
title: "Delete PocketSmith Transaction",
description: toolDescription,
inputSchema: DeleteTransactionInputSchema.shape,
outputSchema: DeleteTransactionResponseSchema.shape,
annotations: {
readOnlyHint: false,
openWorldHint: false,
},
}, async (params) => {
const handlerContext = requestContextService.createRequestContext({
parentRequestId: registrationContext.requestId,
operation: "HandleToolRequest",
toolName: toolName,
input: { ...params, apiKey: "[REDACTED]", accessToken: "[REDACTED]" },
});
try {
const result = await deleteTransactionLogic(params, handlerContext);
return {
structuredContent: result,
content: [
{ type: "text", text: JSON.stringify(result, null, 2) },
],
};
}
catch (error) {
const mcpError = ErrorHandler.handleError(error, {
operation: "deleteTransactionHandler",
context: handlerContext,
input: { ...params, apiKey: "[REDACTED]", accessToken: "[REDACTED]" },
});
return {
isError: true,
content: [{ type: "text", text: `Error: ${mcpError.message}` }],
structuredContent: {
code: mcpError.code,
message: mcpError.message,
details: mcpError.details,
},
};
}
});
logger.info(`Tool '${toolName}' registered successfully.`, registrationContext);
}, {
operation: `RegisteringTool_${toolName}`,
context: registrationContext,
errorCode: BaseErrorCode.INITIALIZATION_FAILED,
critical: true,
});
};