@infamousendeavors/lunchmoney-mcp 0.3.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/LICENSE +25 -0
- package/README.md +288 -0
- package/SECURITY.md +130 -0
- package/dist/api/client.d.ts +11 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +82 -0
- package/dist/api/client.js.map +1 -0
- package/dist/auth-provider.d.ts +47 -0
- package/dist/auth-provider.d.ts.map +1 -0
- package/dist/auth-provider.js +111 -0
- package/dist/auth-provider.js.map +1 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +103 -0
- package/dist/cli.js.map +1 -0
- package/dist/credential-store.d.ts +25 -0
- package/dist/credential-store.d.ts.map +1 -0
- package/dist/credential-store.js +90 -0
- package/dist/credential-store.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/schemas/index.d.ts +189 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +178 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/server.d.ts +32 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +116 -0
- package/dist/server.js.map +1 -0
- package/dist/session-store.d.ts +28 -0
- package/dist/session-store.d.ts.map +1 -0
- package/dist/session-store.js +50 -0
- package/dist/session-store.js.map +1 -0
- package/dist/setup.d.ts +21 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +104 -0
- package/dist/setup.js.map +1 -0
- package/dist/tools/assets.d.ts +4 -0
- package/dist/tools/assets.d.ts.map +1 -0
- package/dist/tools/assets.js +63 -0
- package/dist/tools/assets.js.map +1 -0
- package/dist/tools/budgets.d.ts +4 -0
- package/dist/tools/budgets.d.ts.map +1 -0
- package/dist/tools/budgets.js +63 -0
- package/dist/tools/budgets.js.map +1 -0
- package/dist/tools/categories.d.ts +4 -0
- package/dist/tools/categories.d.ts.map +1 -0
- package/dist/tools/categories.js +105 -0
- package/dist/tools/categories.js.map +1 -0
- package/dist/tools/plaid.d.ts +4 -0
- package/dist/tools/plaid.d.ts.map +1 -0
- package/dist/tools/plaid.js +33 -0
- package/dist/tools/plaid.js.map +1 -0
- package/dist/tools/recurring.d.ts +4 -0
- package/dist/tools/recurring.d.ts.map +1 -0
- package/dist/tools/recurring.js +63 -0
- package/dist/tools/recurring.js.map +1 -0
- package/dist/tools/tags.d.ts +4 -0
- package/dist/tools/tags.d.ts.map +1 -0
- package/dist/tools/tags.js +63 -0
- package/dist/tools/tags.js.map +1 -0
- package/dist/tools/transactions.d.ts +4 -0
- package/dist/tools/transactions.d.ts.map +1 -0
- package/dist/tools/transactions.js +146 -0
- package/dist/tools/transactions.js.map +1 -0
- package/dist/tools/user.d.ts +4 -0
- package/dist/tools/user.d.ts.map +1 -0
- package/dist/tools/user.js +19 -0
- package/dist/tools/user.js.map +1 -0
- package/dist/types/index.d.ts +164 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/errors.d.ts +8 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +29 -0
- package/dist/utils/errors.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// Lunch Money calendar-date fields are always YYYY-MM-DD. Constrain them once
|
|
3
|
+
// and reuse, so malformed input fails fast here instead of as a confusing
|
|
4
|
+
// upstream API error. (balance_as_of is intentionally NOT this -- LM accepts a
|
|
5
|
+
// full ISO 8601 datetime there.)
|
|
6
|
+
const dateString = z
|
|
7
|
+
.string()
|
|
8
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/, "expected YYYY-MM-DD");
|
|
9
|
+
// Transaction filter schema
|
|
10
|
+
export const transactionFilterSchema = z.object({
|
|
11
|
+
start_date: dateString.optional(),
|
|
12
|
+
end_date: dateString.optional(),
|
|
13
|
+
category_id: z.number().optional(),
|
|
14
|
+
tag_id: z.number().optional(),
|
|
15
|
+
account_id: z.number().optional(),
|
|
16
|
+
debit_as_negative: z.boolean().optional(),
|
|
17
|
+
pending: z.boolean().optional(),
|
|
18
|
+
status: z.enum(["cleared", "uncleared", "recurring", "recurring_suggested"]).optional(),
|
|
19
|
+
offset: z.number().int().min(0).optional(),
|
|
20
|
+
limit: z.number().int().min(1).max(1000).optional(),
|
|
21
|
+
});
|
|
22
|
+
// Category schemas
|
|
23
|
+
export const createCategorySchema = z.object({
|
|
24
|
+
name: z.string().min(1),
|
|
25
|
+
description: z.string().optional(),
|
|
26
|
+
is_income: z.boolean().optional(),
|
|
27
|
+
exclude_budget: z.boolean().optional(),
|
|
28
|
+
exclude_from_totals: z.boolean().optional(),
|
|
29
|
+
category_group_id: z.number().optional(),
|
|
30
|
+
parent_category_id: z.number().optional(),
|
|
31
|
+
});
|
|
32
|
+
export const updateCategorySchema = z.object({
|
|
33
|
+
name: z.string().min(1).optional(),
|
|
34
|
+
description: z.string().optional(),
|
|
35
|
+
is_income: z.boolean().optional(),
|
|
36
|
+
exclude_budget: z.boolean().optional(),
|
|
37
|
+
exclude_from_totals: z.boolean().optional(),
|
|
38
|
+
archived: z.boolean().optional(),
|
|
39
|
+
category_group_id: z.number().optional(),
|
|
40
|
+
parent_category_id: z.number().optional(),
|
|
41
|
+
});
|
|
42
|
+
// Tag schemas
|
|
43
|
+
export const createTagSchema = z.object({
|
|
44
|
+
name: z.string().min(1),
|
|
45
|
+
});
|
|
46
|
+
export const updateTagSchema = z.object({
|
|
47
|
+
name: z.string().min(1),
|
|
48
|
+
});
|
|
49
|
+
// Transaction schemas
|
|
50
|
+
export const createTransactionSchema = z.object({
|
|
51
|
+
date: dateString,
|
|
52
|
+
amount: z.string(),
|
|
53
|
+
payee: z.string().optional(),
|
|
54
|
+
currency: z.string().optional(),
|
|
55
|
+
notes: z.string().optional(),
|
|
56
|
+
category_id: z.number().optional(),
|
|
57
|
+
account_id: z.number(),
|
|
58
|
+
tags: z.array(z.number()).optional(),
|
|
59
|
+
status: z.enum(["cleared", "uncleared"]).optional(),
|
|
60
|
+
external_id: z.string().optional(),
|
|
61
|
+
original_name: z.string().optional(),
|
|
62
|
+
type: z.enum(["expense", "income", "transfer"]).optional(),
|
|
63
|
+
});
|
|
64
|
+
export const updateTransactionSchema = z.object({
|
|
65
|
+
date: dateString.optional(),
|
|
66
|
+
amount: z.string().optional(),
|
|
67
|
+
payee: z.string().optional(),
|
|
68
|
+
currency: z.string().optional(),
|
|
69
|
+
notes: z.string().optional(),
|
|
70
|
+
category_id: z.number().nullable().optional(),
|
|
71
|
+
account_id: z.number().optional(),
|
|
72
|
+
tags: z.array(z.number()).optional(),
|
|
73
|
+
status: z.enum(["cleared", "uncleared"]).optional(),
|
|
74
|
+
external_id: z.string().optional(),
|
|
75
|
+
original_name: z.string().optional(),
|
|
76
|
+
type: z.enum(["expense", "income", "transfer"]).optional(),
|
|
77
|
+
});
|
|
78
|
+
export const bulkUpdateTransactionsSchema = z.object({
|
|
79
|
+
transaction_ids: z.array(z.number()).min(1),
|
|
80
|
+
category_id: z.number().nullable().optional(),
|
|
81
|
+
tags: z.array(z.number()).optional(),
|
|
82
|
+
notes: z.string().optional(),
|
|
83
|
+
status: z.enum(["cleared", "uncleared"]).optional(),
|
|
84
|
+
});
|
|
85
|
+
// Recurring item schemas
|
|
86
|
+
export const createRecurringItemSchema = z.object({
|
|
87
|
+
payee: z.string().optional(),
|
|
88
|
+
amount: z.string(),
|
|
89
|
+
currency: z.string().optional(),
|
|
90
|
+
category_id: z.number().optional(),
|
|
91
|
+
notes: z.string().optional(),
|
|
92
|
+
account_id: z.number().optional(),
|
|
93
|
+
tag_id: z.number().optional(),
|
|
94
|
+
frequency: z.string().optional(),
|
|
95
|
+
flow: z.enum(["inflow", "outflow"]).optional(),
|
|
96
|
+
start_date: dateString.optional(),
|
|
97
|
+
end_date: dateString.optional(),
|
|
98
|
+
});
|
|
99
|
+
export const updateRecurringItemSchema = z.object({
|
|
100
|
+
payee: z.string().optional(),
|
|
101
|
+
amount: z.string().optional(),
|
|
102
|
+
currency: z.string().optional(),
|
|
103
|
+
category_id: z.number().nullable().optional(),
|
|
104
|
+
notes: z.string().optional(),
|
|
105
|
+
account_id: z.number().optional(),
|
|
106
|
+
tag_id: z.number().nullable().optional(),
|
|
107
|
+
frequency: z.string().optional(),
|
|
108
|
+
flow: z.enum(["inflow", "outflow"]).optional(),
|
|
109
|
+
start_date: dateString.optional(),
|
|
110
|
+
end_date: dateString.optional(),
|
|
111
|
+
});
|
|
112
|
+
// Budget schemas
|
|
113
|
+
export const createBudgetSchema = z.object({
|
|
114
|
+
category_id: z.number().optional(),
|
|
115
|
+
amount: z.string(),
|
|
116
|
+
currency: z.string().optional(),
|
|
117
|
+
start_date: dateString,
|
|
118
|
+
end_date: dateString,
|
|
119
|
+
});
|
|
120
|
+
export const updateBudgetSchema = z.object({
|
|
121
|
+
category_id: z.number().nullable().optional(),
|
|
122
|
+
amount: z.string().optional(),
|
|
123
|
+
currency: z.string().optional(),
|
|
124
|
+
start_date: dateString.optional(),
|
|
125
|
+
end_date: dateString.optional(),
|
|
126
|
+
});
|
|
127
|
+
// Asset schemas
|
|
128
|
+
export const createAssetSchema = z.object({
|
|
129
|
+
type_name: z.string().min(1),
|
|
130
|
+
type_name_override: z.string().optional(),
|
|
131
|
+
name: z.string().min(1),
|
|
132
|
+
balance: z.string(),
|
|
133
|
+
balance_as_of: z.string().optional(),
|
|
134
|
+
currency: z.string().optional(),
|
|
135
|
+
institution_name: z.string().optional(),
|
|
136
|
+
});
|
|
137
|
+
export const updateAssetSchema = z.object({
|
|
138
|
+
type_name: z.string().optional(),
|
|
139
|
+
type_name_override: z.string().optional(),
|
|
140
|
+
name: z.string().optional(),
|
|
141
|
+
balance: z.string().optional(),
|
|
142
|
+
balance_as_of: z.string().optional(),
|
|
143
|
+
currency: z.string().optional(),
|
|
144
|
+
institution_name: z.string().optional(),
|
|
145
|
+
});
|
|
146
|
+
// Transaction group schemas
|
|
147
|
+
export const createTransactionGroupSchema = z.object({
|
|
148
|
+
date: dateString,
|
|
149
|
+
payee: z.string(),
|
|
150
|
+
transactions: z.array(z.number()).min(2),
|
|
151
|
+
category_id: z.number().optional(),
|
|
152
|
+
notes: z.string().optional(),
|
|
153
|
+
tags: z.array(z.number()).optional(),
|
|
154
|
+
});
|
|
155
|
+
export const unsplitTransactionsSchema = z.object({
|
|
156
|
+
parent_ids: z.array(z.number()).min(1),
|
|
157
|
+
remove_parents: z.boolean().optional(),
|
|
158
|
+
});
|
|
159
|
+
// Category group schemas
|
|
160
|
+
export const createCategoryGroupSchema = z.object({
|
|
161
|
+
name: z.string().min(1),
|
|
162
|
+
description: z.string().optional(),
|
|
163
|
+
is_income: z.boolean().optional(),
|
|
164
|
+
exclude_from_budget: z.boolean().optional(),
|
|
165
|
+
exclude_from_totals: z.boolean().optional(),
|
|
166
|
+
category_ids: z.array(z.number()).optional(),
|
|
167
|
+
new_categories: z.array(z.string()).optional(),
|
|
168
|
+
});
|
|
169
|
+
export const addToGroupSchema = z.object({
|
|
170
|
+
group_id: z.number().int().positive(),
|
|
171
|
+
category_ids: z.array(z.number()).optional(),
|
|
172
|
+
new_categories: z.array(z.string()).optional(),
|
|
173
|
+
});
|
|
174
|
+
// ID parameter schemas
|
|
175
|
+
export const idSchema = z.object({
|
|
176
|
+
id: z.number().int().positive(),
|
|
177
|
+
});
|
|
178
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
import { FastMCP, GoogleProvider, GitHubProvider, OAuthProvider } from "fastmcp";
|
|
3
|
+
import { CredentialStore } from "./credential-store.js";
|
|
4
|
+
/** Union type for supported auth provider instances */
|
|
5
|
+
export type AuthProviderInstance = InstanceType<typeof GoogleProvider> | InstanceType<typeof GitHubProvider> | InstanceType<typeof OAuthProvider>;
|
|
6
|
+
export interface CreateServerOptions {
|
|
7
|
+
/** OAuth auth provider for HTTP transport mode */
|
|
8
|
+
auth?: AuthProviderInstance;
|
|
9
|
+
/** Enable health endpoint (default: true when using HTTP transport) */
|
|
10
|
+
health?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare const TOKEN_NOT_CONFIGURED_MSG = "Lunch Money API token not configured. Use the configureLunchMoneyToken tool to set your token, or run: npx lunchmoney-mcp setup";
|
|
13
|
+
/**
|
|
14
|
+
* Execute logic for the configureLunchMoneyToken tool.
|
|
15
|
+
* Exported for testing.
|
|
16
|
+
*/
|
|
17
|
+
export declare function executeConfigureToken(args: {
|
|
18
|
+
token: string;
|
|
19
|
+
}, credentialStore: CredentialStore): Promise<string>;
|
|
20
|
+
/**
|
|
21
|
+
* Execute logic for the stub getUser tool (when no token is configured).
|
|
22
|
+
* Exported for testing.
|
|
23
|
+
*/
|
|
24
|
+
export declare function executeStubGetUser(): Promise<string>;
|
|
25
|
+
export declare function createServer(options?: CreateServerOptions): Promise<FastMCP>;
|
|
26
|
+
export interface StartServerOptions {
|
|
27
|
+
transportType: "stdio" | "httpStream";
|
|
28
|
+
port?: number;
|
|
29
|
+
authProvider?: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function startServer(server: FastMCP, transportType: "stdio" | "httpStream", port?: number, authProvider?: string): Promise<void>;
|
|
32
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAGjF,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAYxD,uDAAuD;AACvD,MAAM,MAAM,oBAAoB,GAAG,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC;AAElJ,MAAM,WAAW,mBAAmB;IAClC,kDAAkD;IAClD,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,uEAAuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,wBAAwB,oIAC8F,CAAC;AAEpI;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EACvB,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAE1D;AAED,wBAAsB,YAAY,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CA0DlF;AAED,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,OAAO,GAAG,YAAY,CAAC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAsB,WAAW,CAC/B,MAAM,EAAE,OAAO,EACf,aAAa,EAAE,OAAO,GAAG,YAAY,EACrC,IAAI,CAAC,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAoBf"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
import { FastMCP } from "fastmcp";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { LunchMoneyClient } from "./api/client.js";
|
|
5
|
+
import { CredentialStore } from "./credential-store.js";
|
|
6
|
+
import { registerUserTools } from "./tools/user.js";
|
|
7
|
+
import { registerCategoryTools } from "./tools/categories.js";
|
|
8
|
+
import { registerTagTools } from "./tools/tags.js";
|
|
9
|
+
import { registerTransactionTools } from "./tools/transactions.js";
|
|
10
|
+
import { registerRecurringTools } from "./tools/recurring.js";
|
|
11
|
+
import { registerBudgetTools } from "./tools/budgets.js";
|
|
12
|
+
import { registerAssetTools } from "./tools/assets.js";
|
|
13
|
+
import { registerPlaidTools } from "./tools/plaid.js";
|
|
14
|
+
import { formatErrorForMCP } from "./utils/errors.js";
|
|
15
|
+
export const TOKEN_NOT_CONFIGURED_MSG = "Lunch Money API token not configured. Use the configureLunchMoneyToken tool to set your token, or run: npx lunchmoney-mcp setup";
|
|
16
|
+
/**
|
|
17
|
+
* Execute logic for the configureLunchMoneyToken tool.
|
|
18
|
+
* Exported for testing.
|
|
19
|
+
*/
|
|
20
|
+
export async function executeConfigureToken(args, credentialStore) {
|
|
21
|
+
try {
|
|
22
|
+
// Validate the token by calling GET /me
|
|
23
|
+
const testClient = new LunchMoneyClient(args.token);
|
|
24
|
+
const user = await testClient.get("/me");
|
|
25
|
+
// Token is valid — store it
|
|
26
|
+
await credentialStore.setApiToken(args.token);
|
|
27
|
+
return `Token validated and stored successfully! Welcome, ${user.name} (${user.email}). Restart the MCP server to use the new token.`;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
if (error instanceof Error && error.message === "Lunch Money API token is required") {
|
|
31
|
+
return "Error: Token cannot be empty.";
|
|
32
|
+
}
|
|
33
|
+
return `Failed to validate token: ${formatErrorForMCP(error)}. Please check your token and try again. Get a token at https://my.lunchmoney.app/developers`;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Execute logic for the stub getUser tool (when no token is configured).
|
|
38
|
+
* Exported for testing.
|
|
39
|
+
*/
|
|
40
|
+
export async function executeStubGetUser() {
|
|
41
|
+
return TOKEN_NOT_CONFIGURED_MSG;
|
|
42
|
+
}
|
|
43
|
+
export async function createServer(options) {
|
|
44
|
+
const credentialStore = new CredentialStore();
|
|
45
|
+
const token = await credentialStore.getApiToken();
|
|
46
|
+
const serverConfig = {
|
|
47
|
+
name: "Lunch Money MCP",
|
|
48
|
+
version: "0.1.0",
|
|
49
|
+
instructions: "This MCP server provides full integration with the Lunch Money API. " +
|
|
50
|
+
"You can manage user accounts, categories, tags, transactions, recurring items, budgets, and assets. " +
|
|
51
|
+
"All operations support full CRUD capabilities with proper validation.",
|
|
52
|
+
};
|
|
53
|
+
// Add auth provider if specified (for HTTP transport with OAuth)
|
|
54
|
+
if (options?.auth) {
|
|
55
|
+
serverConfig.auth = options.auth;
|
|
56
|
+
}
|
|
57
|
+
// Enable health endpoint (useful for HTTP transport)
|
|
58
|
+
if (options?.health !== false) {
|
|
59
|
+
serverConfig.health = { enabled: true };
|
|
60
|
+
}
|
|
61
|
+
const server = new FastMCP(serverConfig);
|
|
62
|
+
// Register the configureLunchMoneyToken tool — works without a token
|
|
63
|
+
server.addTool({
|
|
64
|
+
name: "configureLunchMoneyToken",
|
|
65
|
+
description: "Configure your Lunch Money API token. Validates the token by checking your account, then stores it securely in the system keychain.",
|
|
66
|
+
parameters: z.object({
|
|
67
|
+
token: z.string().min(1, "API token is required"),
|
|
68
|
+
}),
|
|
69
|
+
execute: async (args) => executeConfigureToken(args, credentialStore),
|
|
70
|
+
});
|
|
71
|
+
// Only register API tools if we have a token
|
|
72
|
+
if (token) {
|
|
73
|
+
const client = new LunchMoneyClient(token);
|
|
74
|
+
registerUserTools(server, client);
|
|
75
|
+
registerCategoryTools(server, client);
|
|
76
|
+
registerTagTools(server, client);
|
|
77
|
+
registerTransactionTools(server, client);
|
|
78
|
+
registerRecurringTools(server, client);
|
|
79
|
+
registerBudgetTools(server, client);
|
|
80
|
+
registerAssetTools(server, client);
|
|
81
|
+
registerPlaidTools(server, client);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
// Register a stub getUser tool that tells the user to configure their token
|
|
85
|
+
server.addTool({
|
|
86
|
+
name: "getUser",
|
|
87
|
+
description: "Get the current user's account details (requires API token to be configured)",
|
|
88
|
+
parameters: z.object({}),
|
|
89
|
+
execute: executeStubGetUser,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return server;
|
|
93
|
+
}
|
|
94
|
+
export async function startServer(server, transportType, port, authProvider) {
|
|
95
|
+
if (transportType === "httpStream") {
|
|
96
|
+
const effectivePort = port || 8080;
|
|
97
|
+
server.start({
|
|
98
|
+
transportType: "httpStream",
|
|
99
|
+
httpStream: {
|
|
100
|
+
port: effectivePort,
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
console.log(`Lunch Money MCP server started on port ${effectivePort} (HTTP)`);
|
|
104
|
+
if (authProvider) {
|
|
105
|
+
console.log(`OAuth provider: ${authProvider}`);
|
|
106
|
+
}
|
|
107
|
+
console.log(`Health check: http://localhost:${effectivePort}/health`);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
server.start({
|
|
111
|
+
transportType: "stdio",
|
|
112
|
+
});
|
|
113
|
+
// Don't log to stdout in stdio mode — it would interfere with the protocol
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type TokenStorage } from "fastmcp/auth";
|
|
2
|
+
import type { CredentialStore } from "./credential-store.js";
|
|
3
|
+
/**
|
|
4
|
+
* Get the platform-native data directory for session storage.
|
|
5
|
+
* - macOS: ~/Library/Application Support/lunchmoney-mcp
|
|
6
|
+
* - Linux: ~/.local/share/lunchmoney-mcp
|
|
7
|
+
* - Windows: %LOCALAPPDATA%/lunchmoney-mcp/Data
|
|
8
|
+
*/
|
|
9
|
+
export declare function getDataDirectory(): string;
|
|
10
|
+
export interface CreateSessionStoreOptions {
|
|
11
|
+
/** Override the data directory (useful for testing) */
|
|
12
|
+
directory?: string;
|
|
13
|
+
/** Cleanup interval in milliseconds (default: 60000) */
|
|
14
|
+
cleanupIntervalMs?: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Create an encrypted, disk-backed session store for OAuth tokens.
|
|
18
|
+
*
|
|
19
|
+
* Sessions are persisted to the platform-native data directory as JSON files,
|
|
20
|
+
* encrypted at rest with AES-256-GCM. The encryption key is stored in the
|
|
21
|
+
* OS keychain via the credential store, never on the filesystem.
|
|
22
|
+
*
|
|
23
|
+
* @param credentialStore - Used to retrieve the encryption key from the OS keychain
|
|
24
|
+
* @param options - Optional overrides for directory and cleanup interval
|
|
25
|
+
* @returns An EncryptedTokenStorage wrapping a DiskStore
|
|
26
|
+
*/
|
|
27
|
+
export declare function createSessionStore(credentialStore: CredentialStore, options?: CreateSessionStoreOptions): Promise<TokenStorage>;
|
|
28
|
+
//# sourceMappingURL=session-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAS7D;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,MAAM,WAAW,yBAAyB;IACxC,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACtC,eAAe,EAAE,eAAe,EAChC,OAAO,CAAC,EAAE,yBAAyB,GAClC,OAAO,CAAC,YAAY,CAAC,CAyBvB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { mkdirSync } from "fs";
|
|
2
|
+
import envPaths from "env-paths";
|
|
3
|
+
import { DiskStore, EncryptedTokenStorage } from "fastmcp/auth";
|
|
4
|
+
const APP_NAME = "lunchmoney-mcp";
|
|
5
|
+
/**
|
|
6
|
+
* Default cleanup interval for expired tokens (60 seconds).
|
|
7
|
+
*/
|
|
8
|
+
const DEFAULT_CLEANUP_INTERVAL_MS = 60_000;
|
|
9
|
+
/**
|
|
10
|
+
* Get the platform-native data directory for session storage.
|
|
11
|
+
* - macOS: ~/Library/Application Support/lunchmoney-mcp
|
|
12
|
+
* - Linux: ~/.local/share/lunchmoney-mcp
|
|
13
|
+
* - Windows: %LOCALAPPDATA%/lunchmoney-mcp/Data
|
|
14
|
+
*/
|
|
15
|
+
export function getDataDirectory() {
|
|
16
|
+
return envPaths(APP_NAME).data;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create an encrypted, disk-backed session store for OAuth tokens.
|
|
20
|
+
*
|
|
21
|
+
* Sessions are persisted to the platform-native data directory as JSON files,
|
|
22
|
+
* encrypted at rest with AES-256-GCM. The encryption key is stored in the
|
|
23
|
+
* OS keychain via the credential store, never on the filesystem.
|
|
24
|
+
*
|
|
25
|
+
* @param credentialStore - Used to retrieve the encryption key from the OS keychain
|
|
26
|
+
* @param options - Optional overrides for directory and cleanup interval
|
|
27
|
+
* @returns An EncryptedTokenStorage wrapping a DiskStore
|
|
28
|
+
*/
|
|
29
|
+
export async function createSessionStore(credentialStore, options) {
|
|
30
|
+
const directory = options?.directory ?? getDataDirectory();
|
|
31
|
+
const cleanupIntervalMs = options?.cleanupIntervalMs ?? DEFAULT_CLEANUP_INTERVAL_MS;
|
|
32
|
+
// Ensure the data directory exists
|
|
33
|
+
mkdirSync(directory, { recursive: true });
|
|
34
|
+
// Retrieve the encryption key. This store persists OAuth sessions to disk,
|
|
35
|
+
// so an ephemeral key is not acceptable: require a stable key (keychain or
|
|
36
|
+
// a valid ENCRYPTION_KEY), and refuse to start otherwise.
|
|
37
|
+
const encryptionKey = await credentialStore.getEncryptionKey({
|
|
38
|
+
requirePersistent: true,
|
|
39
|
+
});
|
|
40
|
+
// Create the disk-backed store
|
|
41
|
+
const diskStore = new DiskStore({
|
|
42
|
+
directory,
|
|
43
|
+
cleanupIntervalMs,
|
|
44
|
+
fileExtension: ".json",
|
|
45
|
+
});
|
|
46
|
+
// Wrap with AES-256-GCM encryption
|
|
47
|
+
const encryptedStore = new EncryptedTokenStorage(diskStore, encryptionKey);
|
|
48
|
+
return encryptedStore;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=session-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-store.js","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,QAAQ,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAqB,MAAM,cAAc,CAAC;AAGnF,MAAM,QAAQ,GAAG,gBAAgB,CAAC;AAElC;;GAEG;AACH,MAAM,2BAA2B,GAAG,MAAM,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;AACjC,CAAC;AASD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,eAAgC,EAChC,OAAmC;IAEnC,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,gBAAgB,EAAE,CAAC;IAC3D,MAAM,iBAAiB,GAAG,OAAO,EAAE,iBAAiB,IAAI,2BAA2B,CAAC;IAEpF,mCAAmC;IACnC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1C,2EAA2E;IAC3E,2EAA2E;IAC3E,0DAA0D;IAC1D,MAAM,aAAa,GAAG,MAAM,eAAe,CAAC,gBAAgB,CAAC;QAC3D,iBAAiB,EAAE,IAAI;KACxB,CAAC,CAAC;IAEH,+BAA+B;IAC/B,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC;QAC9B,SAAS;QACT,iBAAiB;QACjB,aAAa,EAAE,OAAO;KACvB,CAAC,CAAC;IAEH,mCAAmC;IACnC,MAAM,cAAc,GAAG,IAAI,qBAAqB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IAE3E,OAAO,cAAc,CAAC;AACxB,CAAC"}
|
package/dist/setup.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CredentialStore } from "./credential-store.js";
|
|
2
|
+
import type { User } from "./types/index.js";
|
|
3
|
+
export interface ReadlineInterface {
|
|
4
|
+
question(query: string, callback: (answer: string) => void): void;
|
|
5
|
+
close(): void;
|
|
6
|
+
}
|
|
7
|
+
export declare function createReadlineInterface(): ReadlineInterface;
|
|
8
|
+
/**
|
|
9
|
+
* Suppress the terminal echo of typed input on a readline interface, so a
|
|
10
|
+
* secret (the API token) is not printed as it is typed. Returns an `unmask`
|
|
11
|
+
* function that restores the original behavior.
|
|
12
|
+
*
|
|
13
|
+
* Works by swapping the interface's internal `_writeToOutput`: while masked,
|
|
14
|
+
* only newlines pass through (so Enter still breaks the line) and every echoed
|
|
15
|
+
* keystroke is swallowed. If the interface does not expose `_writeToOutput`
|
|
16
|
+
* (a test mock, or a non-TTY stream), this is a no-op.
|
|
17
|
+
*/
|
|
18
|
+
export declare function installInputMask(rl: ReadlineInterface): () => void;
|
|
19
|
+
export declare function validateToken(token: string): Promise<User>;
|
|
20
|
+
export declare function runSetupWizard(rlFactory?: () => ReadlineInterface, credentialStore?: CredentialStore, log?: (msg: string) => void): Promise<void>;
|
|
21
|
+
//# sourceMappingURL=setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAClE,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wBAAgB,uBAAuB,IAAI,iBAAiB,CAK3D;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAelE;AAqBD,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhE;AAED,wBAAsB,cAAc,CAClC,SAAS,CAAC,EAAE,MAAM,iBAAiB,EACnC,eAAe,CAAC,EAAE,eAAe,EACjC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAC1B,OAAO,CAAC,IAAI,CAAC,CAoDf"}
|
package/dist/setup.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import * as readline from "readline";
|
|
2
|
+
import { LunchMoneyClient } from "./api/client.js";
|
|
3
|
+
import { CredentialStore } from "./credential-store.js";
|
|
4
|
+
export function createReadlineInterface() {
|
|
5
|
+
return readline.createInterface({
|
|
6
|
+
input: process.stdin,
|
|
7
|
+
output: process.stdout,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Suppress the terminal echo of typed input on a readline interface, so a
|
|
12
|
+
* secret (the API token) is not printed as it is typed. Returns an `unmask`
|
|
13
|
+
* function that restores the original behavior.
|
|
14
|
+
*
|
|
15
|
+
* Works by swapping the interface's internal `_writeToOutput`: while masked,
|
|
16
|
+
* only newlines pass through (so Enter still breaks the line) and every echoed
|
|
17
|
+
* keystroke is swallowed. If the interface does not expose `_writeToOutput`
|
|
18
|
+
* (a test mock, or a non-TTY stream), this is a no-op.
|
|
19
|
+
*/
|
|
20
|
+
export function installInputMask(rl) {
|
|
21
|
+
const internal = rl;
|
|
22
|
+
const original = internal._writeToOutput;
|
|
23
|
+
if (typeof original !== "function") {
|
|
24
|
+
return () => { };
|
|
25
|
+
}
|
|
26
|
+
internal._writeToOutput = (stringToWrite) => {
|
|
27
|
+
if (stringToWrite === "\n" || stringToWrite === "\r\n" || stringToWrite === "\r") {
|
|
28
|
+
original.call(internal, stringToWrite);
|
|
29
|
+
}
|
|
30
|
+
// otherwise: swallow the echoed character
|
|
31
|
+
};
|
|
32
|
+
return () => {
|
|
33
|
+
internal._writeToOutput = original;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function askQuestion(rl, query, options = {}) {
|
|
37
|
+
return new Promise((resolve) => {
|
|
38
|
+
let unmask;
|
|
39
|
+
rl.question(query, (answer) => {
|
|
40
|
+
unmask?.();
|
|
41
|
+
resolve(answer.trim());
|
|
42
|
+
});
|
|
43
|
+
// Install the mask after the prompt is written so the prompt stays visible
|
|
44
|
+
// but the typed token does not echo.
|
|
45
|
+
if (options.mask) {
|
|
46
|
+
unmask = installInputMask(rl);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export async function validateToken(token) {
|
|
51
|
+
const client = new LunchMoneyClient(token);
|
|
52
|
+
return client.get("/me");
|
|
53
|
+
}
|
|
54
|
+
export async function runSetupWizard(rlFactory, credentialStore, log) {
|
|
55
|
+
const print = log || console.log;
|
|
56
|
+
const store = credentialStore || new CredentialStore();
|
|
57
|
+
const rl = rlFactory ? rlFactory() : createReadlineInterface();
|
|
58
|
+
try {
|
|
59
|
+
print("");
|
|
60
|
+
print("=== Lunch Money MCP Server Setup ===");
|
|
61
|
+
print("");
|
|
62
|
+
print("This wizard will help you configure your Lunch Money API token.");
|
|
63
|
+
print("You can get a token at: https://my.lunchmoney.app/developers");
|
|
64
|
+
print("");
|
|
65
|
+
const token = await askQuestion(rl, "Enter your Lunch Money API token (input hidden): ", {
|
|
66
|
+
mask: true,
|
|
67
|
+
});
|
|
68
|
+
if (!token) {
|
|
69
|
+
print("No token provided. Setup cancelled.");
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
print("");
|
|
73
|
+
print("Validating token...");
|
|
74
|
+
try {
|
|
75
|
+
const user = await validateToken(token);
|
|
76
|
+
await store.setApiToken(token);
|
|
77
|
+
print("");
|
|
78
|
+
print(`Token validated and stored successfully!`);
|
|
79
|
+
print(` Name: ${user.name}`);
|
|
80
|
+
print(` Email: ${user.email}`);
|
|
81
|
+
print(` Currency: ${user.currency}`);
|
|
82
|
+
print("");
|
|
83
|
+
print("You can now start the MCP server:");
|
|
84
|
+
print(" npx lunchmoney-mcp (stdio mode)");
|
|
85
|
+
print(" npx lunchmoney-mcp --http (HTTP mode)");
|
|
86
|
+
print("");
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
print("");
|
|
90
|
+
if (error instanceof Error) {
|
|
91
|
+
print(`Token validation failed: ${error.message}`);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
print("Token validation failed. Please check your token and try again.");
|
|
95
|
+
}
|
|
96
|
+
print("Get a new token at: https://my.lunchmoney.app/developers");
|
|
97
|
+
print("");
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
rl.close();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../src/tools/assets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AASpD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,gBAAgB,QA6DzB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatErrorForMCP } from "../utils/errors.js";
|
|
3
|
+
import { createAssetSchema, updateAssetSchema, idSchema, } from "../schemas/index.js";
|
|
4
|
+
export function registerAssetTools(server, client) {
|
|
5
|
+
server.addTool({
|
|
6
|
+
name: "getAssets",
|
|
7
|
+
description: "List all manually-managed assets",
|
|
8
|
+
parameters: z.object({}),
|
|
9
|
+
execute: async () => {
|
|
10
|
+
try {
|
|
11
|
+
const response = await client.get("/assets");
|
|
12
|
+
return JSON.stringify(response, null, 2);
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
return formatErrorForMCP(error);
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
server.addTool({
|
|
20
|
+
name: "createAsset",
|
|
21
|
+
description: "Create a new manually-managed asset",
|
|
22
|
+
parameters: createAssetSchema,
|
|
23
|
+
execute: async (args) => {
|
|
24
|
+
try {
|
|
25
|
+
const asset = await client.post("/assets", args);
|
|
26
|
+
return JSON.stringify(asset, null, 2);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
return formatErrorForMCP(error);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
server.addTool({
|
|
34
|
+
name: "updateAsset",
|
|
35
|
+
description: "Update an existing asset's properties including balance and metadata",
|
|
36
|
+
parameters: idSchema.merge(updateAssetSchema),
|
|
37
|
+
execute: async (args) => {
|
|
38
|
+
try {
|
|
39
|
+
const { id, ...updateData } = args;
|
|
40
|
+
const asset = await client.put(`/assets/${id}`, updateData);
|
|
41
|
+
return JSON.stringify(asset, null, 2);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
return formatErrorForMCP(error);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
server.addTool({
|
|
49
|
+
name: "deleteAsset",
|
|
50
|
+
description: "Delete an asset by ID",
|
|
51
|
+
parameters: idSchema,
|
|
52
|
+
execute: async (args) => {
|
|
53
|
+
try {
|
|
54
|
+
await client.delete(`/assets/${args.id}`);
|
|
55
|
+
return `Asset ${args.id} deleted successfully`;
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
return formatErrorForMCP(error);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=assets.js.map
|