@mindstone-engineering/mcp-server-quickbooks 0.1.0 → 0.2.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 ADDED
@@ -0,0 +1,97 @@
1
+ # Functional Source License, Version 1.1, MIT Future License
2
+
3
+ ## Abbreviation
4
+
5
+ FSL-1.1-MIT
6
+
7
+ ## Notice
8
+
9
+ Copyright 2026 Mindstone Engineering
10
+
11
+ ## Terms and Conditions
12
+
13
+ ### Licensor ("We")
14
+
15
+ The party offering the Software under these Terms and Conditions.
16
+
17
+ **Licensor**: Mindstone Engineering
18
+
19
+ ### The Software
20
+
21
+ The "Software" is each version of the software that we make available under
22
+ these Terms and Conditions, as indicated by our inclusion of these Terms and
23
+ Conditions with the Software.
24
+
25
+ **Software**: QuickBooks MCP Server
26
+
27
+ ### License Grant
28
+
29
+ Subject to your compliance with this License Grant and the Patents,
30
+ Redistribution and Trademark clauses below, we hereby grant you the right to
31
+ use, copy, modify, create derivative works, publicly perform, publicly display
32
+ and redistribute the Software for any Permitted Purpose identified below.
33
+
34
+ ### Permitted Purpose
35
+
36
+ A Permitted Purpose is any purpose other than a Competing Use. A "Competing
37
+ Use" means making the Software available to third parties as a commercial
38
+ hosted service that directly competes with any product or service provided by
39
+ the Licensor.
40
+
41
+ ### Patents
42
+
43
+ To the extent your use for a Permitted Purpose would necessarily infringe our
44
+ patents, the license grant above includes a license under our patents. If you
45
+ make a claim against any party that the Software infringes or contributes to
46
+ the infringement of any patent, then your patent license to the Software ends
47
+ immediately.
48
+
49
+ ### Redistribution
50
+
51
+ The Terms and Conditions apply to all copies, modifications and derivatives of
52
+ the Software.
53
+
54
+ If you redistribute any copies, modifications or derivatives of the Software,
55
+ you must include a copy of or a link to these Terms and Conditions and not
56
+ remove any copyright notices provided in or with the Software.
57
+
58
+ ### Disclaimer
59
+
60
+ THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
61
+ IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
62
+ PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
63
+
64
+ IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
65
+ SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, OF
66
+ ANY CHARACTER INCLUDING DAMAGES FOR LOSS OF GOODWILL, LOST PROFITS, LOST SALES
67
+ OR BUSINESS, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, LOST CONTENT,
68
+ DATA OR DATA USE, BREACH OF DUTY OF GOOD FAITH, OR ANY AND ALL OTHER DAMAGES
69
+ OR LOSSES OF ANY KIND OR NATURE WHATSOEVER (WHETHER DIRECT, INDIRECT, SPECIAL,
70
+ COLLATERAL, INCIDENTAL, CONSEQUENTIAL OR OTHERWISE) ARISING OUT OF OR IN
71
+ CONNECTION WITH THE SOFTWARE OR THIS LICENSE, EVEN IF SUCH PARTY SHALL HAVE
72
+ BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.
73
+
74
+ ### Trademark
75
+
76
+ Except for displaying the License Details and identifying us as the origin of
77
+ the Software, you have no right under these Terms and Conditions to use our
78
+ trademarks, trade names, service marks or product names.
79
+
80
+ ## Change Date
81
+
82
+ Four years from the date the Software is made available under these Terms and
83
+ Conditions: **2030-04-08**
84
+
85
+ ## Change License
86
+
87
+ MIT License
88
+
89
+ ## License Details
90
+
91
+ | Parameter | Value |
92
+ |---|---|
93
+ | Licensor | Mindstone Engineering |
94
+ | Software | QuickBooks MCP Server |
95
+ | Use Limitation | Competing Use |
96
+ | Change Date | 2030-04-08 |
97
+ | Change License | MIT |
package/README.md ADDED
@@ -0,0 +1,120 @@
1
+ # @mindstone-engineering/mcp-server-quickbooks
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@mindstone-engineering/mcp-server-quickbooks.svg)](https://www.npmjs.com/package/@mindstone-engineering/mcp-server-quickbooks)
4
+ [![License: FSL-1.1-MIT](https://img.shields.io/badge/License-FSL--1.1--MIT-blue.svg)](./LICENSE)
5
+
6
+ QuickBooks Online MCP server for Model Context Protocol hosts. Manage invoices, bills, customers, vendors, employees, and accounts in QuickBooks Online through a standardised MCP interface.
7
+
8
+ ## Requirements
9
+
10
+ - Node.js 20+
11
+ - npm
12
+
13
+ ## Quick Start
14
+
15
+ ### Install & build
16
+
17
+ ```bash
18
+ cd <path-to-repo>/connectors/quickbooks
19
+ npm install
20
+ npm run build
21
+ ```
22
+
23
+ ### npx (once published)
24
+
25
+ ```bash
26
+ npx -y @mindstone-engineering/mcp-server-quickbooks
27
+ ```
28
+
29
+ ### Local
30
+
31
+ ```bash
32
+ node dist/index.js
33
+ ```
34
+
35
+ ## Configuration
36
+
37
+ ### Environment variables
38
+
39
+ - `QUICKBOOKS_CLIENT_ID` — Intuit Developer app client ID
40
+ - `QUICKBOOKS_CLIENT_SECRET` — Intuit Developer app client secret
41
+ - `QUICKBOOKS_REFRESH_TOKEN` — OAuth 2.0 refresh token
42
+ - `QUICKBOOKS_REALM_ID` — QuickBooks company (realm) ID
43
+ - `QUICKBOOKS_ENVIRONMENT` — `sandbox` or `production` (default: `production`)
44
+ - `MCP_HOST_BRIDGE_STATE` — optional path to a host bridge state file used for credential management
45
+ - `MINDSTONE_REBEL_BRIDGE_STATE` — backwards-compatible alias for `MCP_HOST_BRIDGE_STATE`
46
+
47
+ ## Host configuration examples
48
+
49
+ ### Claude Desktop / Cursor
50
+
51
+ ```json
52
+ {
53
+ "mcpServers": {
54
+ "QuickBooks": {
55
+ "command": "npx",
56
+ "args": ["-y", "@mindstone-engineering/mcp-server-quickbooks"],
57
+ "env": {
58
+ "QUICKBOOKS_CLIENT_ID": "your-client-id",
59
+ "QUICKBOOKS_CLIENT_SECRET": "your-client-secret",
60
+ "QUICKBOOKS_REFRESH_TOKEN": "your-refresh-token",
61
+ "QUICKBOOKS_REALM_ID": "your-realm-id"
62
+ }
63
+ }
64
+ }
65
+ }
66
+ ```
67
+
68
+ ### Local development (no npm publish needed)
69
+
70
+ ```json
71
+ {
72
+ "mcpServers": {
73
+ "QuickBooks": {
74
+ "command": "node",
75
+ "args": ["<path-to-repo>/connectors/quickbooks/dist/index.js"],
76
+ "env": {
77
+ "QUICKBOOKS_CLIENT_ID": "your-client-id",
78
+ "QUICKBOOKS_CLIENT_SECRET": "your-client-secret",
79
+ "QUICKBOOKS_REFRESH_TOKEN": "your-refresh-token",
80
+ "QUICKBOOKS_REALM_ID": "your-realm-id"
81
+ }
82
+ }
83
+ }
84
+ }
85
+ ```
86
+
87
+ ## Tools (13)
88
+
89
+ ### Configuration
90
+ - `configure_quickbooks` — Configure QuickBooks Online OAuth credentials
91
+
92
+ ### Query
93
+ - `query_quickbooks` — Run a QuickBooks query using QuickBooks Query Language
94
+ - `get_quickbooks_entity` — Get a single entity by type and ID
95
+
96
+ ### Customers
97
+ - `list_quickbooks_customers` — List customers
98
+ - `create_quickbooks_customer` — Create a new customer
99
+
100
+ ### Vendors
101
+ - `list_quickbooks_vendors` — List vendors
102
+ - `create_quickbooks_vendor` — Create a new vendor
103
+
104
+ ### Invoices
105
+ - `list_quickbooks_invoices` — List invoices
106
+ - `create_quickbooks_invoice` — Create a new invoice
107
+
108
+ ### Bills
109
+ - `list_quickbooks_bills` — List bills (accounts payable)
110
+ - `create_quickbooks_bill` — Create a new bill
111
+
112
+ ### Employees
113
+ - `list_quickbooks_employees` — List employees
114
+
115
+ ### Accounts
116
+ - `list_quickbooks_accounts` — List chart of accounts
117
+
118
+ ## Licence
119
+
120
+ [FSL-1.1-MIT](./LICENSE) — Functional Source License, Version 1.1, with MIT future licence. The software converts to MIT licence on 2030-04-08.
package/dist/bridge.d.ts CHANGED
@@ -5,7 +5,7 @@ export declare const BRIDGE_STATE_PATH: string;
5
5
  /**
6
6
  * Send a request to the host app bridge.
7
7
  *
8
- * The bridge is an HTTP server running inside the host app (e.g. Rebel)
8
+ * The bridge is an HTTP server running inside the host app (e.g. the host application)
9
9
  * that handles credential management and other cross-process operations.
10
10
  */
11
11
  export declare const bridgeRequest: (urlPath: string, body: Record<string, unknown>) => Promise<{
package/dist/bridge.js CHANGED
@@ -18,7 +18,7 @@ const loadBridgeState = () => {
18
18
  /**
19
19
  * Send a request to the host app bridge.
20
20
  *
21
- * The bridge is an HTTP server running inside the host app (e.g. Rebel)
21
+ * The bridge is an HTTP server running inside the host app (e.g. the host application)
22
22
  * that handles credential management and other cross-process operations.
23
23
  */
24
24
  export const bridgeRequest = async (urlPath, body) => {
package/dist/index.d.ts CHANGED
@@ -15,8 +15,8 @@
15
15
  * - QUICKBOOKS_REFRESH_TOKEN: OAuth2 refresh token
16
16
  * - QUICKBOOKS_REALM_ID: QuickBooks company ID (Realm ID)
17
17
  * - QUICKBOOKS_ENVIRONMENT: "sandbox" or "production" (default: "production")
18
- * - MCP_HOST_BRIDGE_STATE: Path to bridge state file for app communication
19
- * - MINDSTONE_REBEL_BRIDGE_STATE: Legacy bridge state path
18
+ * - MCP_HOST_BRIDGE_STATE: Path to bridge state file for app communication (primary)
19
+ * - MINDSTONE_REBEL_BRIDGE_STATE: Legacy/deprecated bridge state path
20
20
  */
21
21
  export {};
22
22
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -15,8 +15,8 @@
15
15
  * - QUICKBOOKS_REFRESH_TOKEN: OAuth2 refresh token
16
16
  * - QUICKBOOKS_REALM_ID: QuickBooks company ID (Realm ID)
17
17
  * - QUICKBOOKS_ENVIRONMENT: "sandbox" or "production" (default: "production")
18
- * - MCP_HOST_BRIDGE_STATE: Path to bridge state file for app communication
19
- * - MINDSTONE_REBEL_BRIDGE_STATE: Legacy bridge state path
18
+ * - MCP_HOST_BRIDGE_STATE: Path to bridge state file for app communication (primary)
19
+ * - MINDSTONE_REBEL_BRIDGE_STATE: Legacy/deprecated bridge state path
20
20
  */
21
21
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
22
22
  import { createServer } from './server.js';
@@ -2,7 +2,7 @@
2
2
  * QuickBooks account (chart of accounts) tools.
3
3
  */
4
4
  import { z } from 'zod';
5
- import { withErrorHandling } from '../utils.js';
5
+ import { withErrorHandling, escapeQboql } from '../utils.js';
6
6
  import { qboQuery } from '../client.js';
7
7
  export function registerAccountTools(server) {
8
8
  server.registerTool('list_quickbooks_accounts', {
@@ -24,7 +24,7 @@ Account types: Bank, Accounts Receivable, Other Current Asset, Fixed Asset, Othe
24
24
  const limit = Math.min(args.limit ?? 100, 1000);
25
25
  const conditions = [];
26
26
  if (args.accountType)
27
- conditions.push(`AccountType = '${args.accountType}'`);
27
+ conditions.push(`AccountType = '${escapeQboql(args.accountType)}'`);
28
28
  if (args.active !== undefined)
29
29
  conditions.push(`Active = ${args.active}`);
30
30
  const where = conditions.length > 0 ? ` WHERE ${conditions.join(' AND ')}` : '';
@@ -2,7 +2,7 @@
2
2
  * QuickBooks bill tools.
3
3
  */
4
4
  import { z } from 'zod';
5
- import { withErrorHandling } from '../utils.js';
5
+ import { withErrorHandling, escapeQboql, validateAlphanumericId } from '../utils.js';
6
6
  import { qboFetch, qboQuery } from '../client.js';
7
7
  export function registerBillTools(server) {
8
8
  server.registerTool('list_quickbooks_bills', {
@@ -19,7 +19,9 @@ Example: { "vendorId": "123" }`,
19
19
  annotations: { readOnlyHint: true },
20
20
  }, withErrorHandling(async (args) => {
21
21
  const limit = Math.min(args.limit ?? 50, 1000);
22
- const where = args.vendorId ? ` WHERE VendorRef = '${args.vendorId}'` : '';
22
+ if (args.vendorId)
23
+ validateAlphanumericId(args.vendorId, 'vendorId');
24
+ const where = args.vendorId ? ` WHERE VendorRef = '${escapeQboql(args.vendorId)}'` : '';
23
25
  const query = `SELECT * FROM Bill${where} ORDERBY TxnDate DESC`;
24
26
  const bills = await qboQuery('Bill', query, limit);
25
27
  return JSON.stringify({ ok: true, bills, count: bills.length });
@@ -2,7 +2,7 @@
2
2
  * QuickBooks customer tools.
3
3
  */
4
4
  import { z } from 'zod';
5
- import { withErrorHandling } from '../utils.js';
5
+ import { withErrorHandling, escapeQboql } from '../utils.js';
6
6
  import { qboFetch, qboQuery } from '../client.js';
7
7
  export function registerCustomerTools(server) {
8
8
  server.registerTool('list_quickbooks_customers', {
@@ -25,7 +25,7 @@ Example: { "searchTerm": "Smith" }`,
25
25
  if (args.active !== undefined)
26
26
  conditions.push(`Active = ${args.active}`);
27
27
  if (args.searchTerm) {
28
- conditions.push(`DisplayName LIKE '%${args.searchTerm.replace(/'/g, "\\'")}%'`);
28
+ conditions.push(`DisplayName LIKE '%${escapeQboql(args.searchTerm)}%'`);
29
29
  }
30
30
  const where = conditions.length > 0 ? ` WHERE ${conditions.join(' AND ')}` : '';
31
31
  const query = `SELECT * FROM Customer${where} ORDERBY DisplayName`;
@@ -2,7 +2,7 @@
2
2
  * QuickBooks invoice tools.
3
3
  */
4
4
  import { z } from 'zod';
5
- import { withErrorHandling } from '../utils.js';
5
+ import { withErrorHandling, escapeQboql, validateAlphanumericId } from '../utils.js';
6
6
  import { qboFetch, qboQuery } from '../client.js';
7
7
  export function registerInvoiceTools(server) {
8
8
  server.registerTool('list_quickbooks_invoices', {
@@ -35,8 +35,10 @@ WORKFLOW:
35
35
  else if (args.status === 'overdue') {
36
36
  conditions.push(`Balance > '0' AND DueDate < '${new Date().toISOString().split('T')[0]}'`);
37
37
  }
38
- if (args.customerId)
39
- conditions.push(`CustomerRef = '${args.customerId}'`);
38
+ if (args.customerId) {
39
+ validateAlphanumericId(args.customerId, 'customerId');
40
+ conditions.push(`CustomerRef = '${escapeQboql(args.customerId)}'`);
41
+ }
40
42
  const where = conditions.length > 0 ? ` WHERE ${conditions.join(' AND ')}` : '';
41
43
  const query = `SELECT * FROM Invoice${where} ORDERBY TxnDate DESC`;
42
44
  const invoices = await qboQuery('Invoice', query, limit);
@@ -2,7 +2,7 @@
2
2
  * QuickBooks vendor tools.
3
3
  */
4
4
  import { z } from 'zod';
5
- import { withErrorHandling } from '../utils.js';
5
+ import { withErrorHandling, escapeQboql } from '../utils.js';
6
6
  import { qboFetch, qboQuery } from '../client.js';
7
7
  export function registerVendorTools(server) {
8
8
  server.registerTool('list_quickbooks_vendors', {
@@ -24,7 +24,7 @@ Example: { "searchTerm": "Office" }`,
24
24
  if (args.active !== undefined)
25
25
  conditions.push(`Active = ${args.active}`);
26
26
  if (args.searchTerm) {
27
- conditions.push(`DisplayName LIKE '%${args.searchTerm.replace(/'/g, "\\'")}%'`);
27
+ conditions.push(`DisplayName LIKE '%${escapeQboql(args.searchTerm)}%'`);
28
28
  }
29
29
  const where = conditions.length > 0 ? ` WHERE ${conditions.join(' AND ')}` : '';
30
30
  const query = `SELECT * FROM Vendor${where} ORDERBY DisplayName`;
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export declare const REQUEST_TIMEOUT_MS = 30000;
2
- export declare const USER_AGENT = "MindstoneRebel/1.0 (QuickBooks-MCP)";
2
+ export declare const USER_AGENT = "mcp-server-quickbooks/0.1.0";
3
3
  export declare const TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
4
4
  export interface BridgeState {
5
5
  port: number;
package/dist/types.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export const REQUEST_TIMEOUT_MS = 30_000;
2
- export const USER_AGENT = 'MindstoneRebel/1.0 (QuickBooks-MCP)';
2
+ export const USER_AGENT = 'mcp-server-quickbooks/0.1.0';
3
3
  export const TOKEN_URL = 'https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer';
4
4
  export class QuickBooksError extends Error {
5
5
  code;
package/dist/utils.d.ts CHANGED
@@ -1,5 +1,15 @@
1
1
  import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
2
2
  type ToolHandler<T> = (args: T, extra: unknown) => Promise<CallToolResult>;
3
+ /**
4
+ * Escape a user-supplied string value for safe interpolation into a QBOQL query.
5
+ * Escapes backslashes and single quotes to prevent injection.
6
+ */
7
+ export declare function escapeQboql(value: string): string;
8
+ /**
9
+ * Validate that an ID value contains only alphanumeric characters, hyphens, and underscores.
10
+ * Throws QuickBooksError if the value contains unexpected characters.
11
+ */
12
+ export declare function validateAlphanumericId(value: string, fieldName: string): void;
3
13
  /**
4
14
  * Wraps a tool handler with standard error handling.
5
15
  *
package/dist/utils.js CHANGED
@@ -1,4 +1,20 @@
1
1
  import { QuickBooksError } from './types.js';
2
+ /**
3
+ * Escape a user-supplied string value for safe interpolation into a QBOQL query.
4
+ * Escapes backslashes and single quotes to prevent injection.
5
+ */
6
+ export function escapeQboql(value) {
7
+ return value.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
8
+ }
9
+ /**
10
+ * Validate that an ID value contains only alphanumeric characters, hyphens, and underscores.
11
+ * Throws QuickBooksError if the value contains unexpected characters.
12
+ */
13
+ export function validateAlphanumericId(value, fieldName) {
14
+ if (!/^[a-zA-Z0-9_-]+$/.test(value)) {
15
+ throw new QuickBooksError(`Invalid ${fieldName}: must contain only alphanumeric characters, hyphens, and underscores.`, 'INVALID_INPUT', `Provide a valid ${fieldName} containing only letters, numbers, hyphens, and underscores.`);
16
+ }
17
+ }
2
18
  /**
3
19
  * Wraps a tool handler with standard error handling.
4
20
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindstone-engineering/mcp-server-quickbooks",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "QuickBooks Online MCP server for Model Context Protocol hosts — invoices, bills, customers, vendors, accounts",
5
5
  "license": "FSL-1.1-MIT",
6
6
  "type": "module",