@mindstone/mcp-server-salesforce 0.1.2

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 Learning Limited
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 Learning Limited
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**: Salesforce 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 Learning Limited |
94
+ | Software | Salesforce MCP Server |
95
+ | Use Limitation | Competing Use |
96
+ | Change Date | 2030-04-08 |
97
+ | Change License | MIT |
package/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # @mindstone/mcp-server-salesforce
2
+
3
+ Salesforce CRM MCP server — accounts, contacts, opportunities, leads, tasks, users, and custom objects via the Salesforce API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npx -y @mindstone/mcp-server-salesforce
9
+ ```
10
+
11
+ ## Configuration
12
+
13
+ ### OAuth (Recommended)
14
+
15
+ Set these environment variables:
16
+
17
+ - `SALESFORCE_CLIENT_ID` — Your Salesforce Connected App client ID
18
+ - `SALESFORCE_CLIENT_SECRET` — Your Salesforce Connected App client secret
19
+ - `SALESFORCE_SANDBOX` — Set to `"true"` for sandbox environments (optional)
20
+
21
+ Then call `salesforce_connect_account` to start the OAuth flow.
22
+
23
+ ### Manual Token
24
+
25
+ - `SALESFORCE_ACCESS_TOKEN` — A valid Salesforce access token
26
+ - `SALESFORCE_INSTANCE_URL` — Your Salesforce instance URL (e.g., `https://mycompany.my.salesforce.com`)
27
+
28
+ ### Additional Options
29
+
30
+ - `SALESFORCE_CONFIG_DIR` — Custom config directory (default: `~/.mcp/salesforce`)
31
+
32
+ ## Available Tools (26)
33
+
34
+ ### Account Management
35
+ - `salesforce_connect_account` — Connect a Salesforce account via OAuth
36
+ - `salesforce_list_connected_accounts` — List connected accounts
37
+ - `salesforce_disconnect_account` — Disconnect an account
38
+
39
+ ### CRM Accounts
40
+ - `salesforce_get_accounts` — Get CRM accounts with filters
41
+ - `salesforce_create_account` — Create a CRM account
42
+ - `salesforce_update_account` — Update a CRM account
43
+
44
+ ### Contacts
45
+ - `salesforce_get_contacts` — Get contacts with filters
46
+ - `salesforce_create_contact` — Create a contact
47
+ - `salesforce_update_contact` — Update a contact
48
+
49
+ ### Opportunities
50
+ - `salesforce_get_opportunities` — Get opportunities with filters
51
+ - `salesforce_create_opportunity` — Create an opportunity
52
+ - `salesforce_update_opportunity` — Update an opportunity
53
+
54
+ ### Leads
55
+ - `salesforce_get_leads` — Get leads with filters
56
+ - `salesforce_create_lead` — Create a lead
57
+ - `salesforce_convert_lead` — Convert a lead to Account + Contact
58
+ - `salesforce_update_lead` — Update a lead
59
+
60
+ ### Tasks
61
+ - `salesforce_get_tasks` — Get tasks with filters
62
+ - `salesforce_create_task` — Create a task
63
+ - `salesforce_update_task` — Update a task
64
+
65
+ ### Users
66
+ - `salesforce_get_users` — Get Salesforce users
67
+
68
+ ### Query & Schema
69
+ - `salesforce_query` — Execute raw SOQL queries
70
+ - `salesforce_describe_object` — Get object metadata and fields
71
+ - `salesforce_list_objects` — List available Salesforce objects
72
+
73
+ ### Generic CRUD
74
+ - `salesforce_create_record` — Create any Salesforce record
75
+ - `salesforce_update_record` — Update any Salesforce record
76
+ - `salesforce_get_records` — Query any Salesforce object
77
+
78
+ ## License
79
+
80
+ FSL-1.1-MIT
package/dist/auth.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import { type AuthMode, type SalesforceTokenData, type SalesforceAccountsConfig } from './types.js';
2
+ export declare function resolveAuthMode(): AuthMode;
3
+ export declare function getAuthMode(): AuthMode;
4
+ export declare function _resetAuthMode(): void;
5
+ export declare function loadAccounts(): SalesforceAccountsConfig;
6
+ export declare function saveAccounts(config: SalesforceAccountsConfig): void;
7
+ export declare function loadToken(accountId: string): SalesforceTokenData | null;
8
+ export declare function saveToken(accountId: string, token: SalesforceTokenData): void;
9
+ export declare function deleteToken(accountId: string): void;
10
+ export declare function getActiveToken(): {
11
+ accountId: string;
12
+ token: SalesforceTokenData;
13
+ };
14
+ export declare function startStandaloneOAuth(): Promise<{
15
+ success: boolean;
16
+ username?: string;
17
+ error?: string;
18
+ }>;
19
+ //# sourceMappingURL=auth.d.ts.map
package/dist/auth.js ADDED
@@ -0,0 +1,331 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import * as os from 'node:os';
4
+ import * as crypto from 'node:crypto';
5
+ import * as http from 'node:http';
6
+ import { ConnectorError, } from './types.js';
7
+ import { BRIDGE_STATE_PATH } from './bridge.js';
8
+ // ---------------------------------------------------------------------------
9
+ // Auth Mode Detection (resolved ONCE at startup)
10
+ // ---------------------------------------------------------------------------
11
+ let resolvedMode = null;
12
+ export function resolveAuthMode() {
13
+ if (resolvedMode !== null)
14
+ return resolvedMode;
15
+ const hasBridge = !!BRIDGE_STATE_PATH;
16
+ const hasClientId = !!process.env.SALESFORCE_CLIENT_ID;
17
+ const hasClientSecret = !!process.env.SALESFORCE_CLIENT_SECRET;
18
+ const hasManualToken = !!process.env.SALESFORCE_ACCESS_TOKEN;
19
+ if (hasBridge) {
20
+ resolvedMode = 'bridge';
21
+ if (hasClientId || hasManualToken) {
22
+ console.error('[Salesforce MCP] WARNING: Bridge state detected alongside other auth env vars. Using bridge mode (highest precedence).');
23
+ }
24
+ }
25
+ else if (hasClientId && hasClientSecret) {
26
+ resolvedMode = 'standalone_oauth';
27
+ }
28
+ else if (hasManualToken) {
29
+ resolvedMode = 'manual_token';
30
+ }
31
+ else {
32
+ resolvedMode = 'unconfigured';
33
+ }
34
+ console.error(`[Salesforce MCP] Auth mode: ${resolvedMode}`);
35
+ return resolvedMode;
36
+ }
37
+ export function getAuthMode() {
38
+ if (resolvedMode === null)
39
+ return resolveAuthMode();
40
+ return resolvedMode;
41
+ }
42
+ export function _resetAuthMode() {
43
+ resolvedMode = null;
44
+ }
45
+ // ---------------------------------------------------------------------------
46
+ // Config Directory & Token Persistence
47
+ // ---------------------------------------------------------------------------
48
+ function getConfigDir() {
49
+ return process.env.SALESFORCE_CONFIG_DIR || path.join(os.homedir(), '.mcp', 'salesforce');
50
+ }
51
+ function getCredentialsDir() {
52
+ return path.join(getConfigDir(), 'credentials');
53
+ }
54
+ function sanitizeFilename(name) {
55
+ return name.replace(/[^a-zA-Z0-9._-]/g, '-');
56
+ }
57
+ function ensureDirectories() {
58
+ const configDir = getConfigDir();
59
+ const credDir = getCredentialsDir();
60
+ if (!fs.existsSync(configDir)) {
61
+ fs.mkdirSync(configDir, { recursive: true, mode: 0o700 });
62
+ }
63
+ if (!fs.existsSync(credDir)) {
64
+ fs.mkdirSync(credDir, { recursive: true, mode: 0o700 });
65
+ }
66
+ }
67
+ function getAccountsPath() {
68
+ return path.join(getConfigDir(), 'accounts.json');
69
+ }
70
+ function getTokenPath(accountId) {
71
+ return path.join(getCredentialsDir(), `${sanitizeFilename(accountId)}.token.json`);
72
+ }
73
+ function atomicWriteFile(filePath, data) {
74
+ const dir = path.dirname(filePath);
75
+ if (!fs.existsSync(dir)) {
76
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
77
+ }
78
+ const tmpPath = `${filePath}.${crypto.randomBytes(6).toString('hex')}.tmp`;
79
+ const fd = fs.openSync(tmpPath, 'w', 0o600);
80
+ try {
81
+ fs.writeSync(fd, data);
82
+ fs.fsyncSync(fd);
83
+ }
84
+ finally {
85
+ fs.closeSync(fd);
86
+ }
87
+ fs.renameSync(tmpPath, filePath);
88
+ }
89
+ // ---------------------------------------------------------------------------
90
+ // Account Management
91
+ // ---------------------------------------------------------------------------
92
+ export function loadAccounts() {
93
+ ensureDirectories();
94
+ try {
95
+ const data = fs.readFileSync(getAccountsPath(), 'utf-8');
96
+ return JSON.parse(data);
97
+ }
98
+ catch {
99
+ return { accounts: [] };
100
+ }
101
+ }
102
+ export function saveAccounts(config) {
103
+ ensureDirectories();
104
+ atomicWriteFile(getAccountsPath(), JSON.stringify(config, null, 2));
105
+ }
106
+ export function loadToken(accountId) {
107
+ try {
108
+ const data = fs.readFileSync(getTokenPath(accountId), 'utf-8');
109
+ return JSON.parse(data);
110
+ }
111
+ catch {
112
+ return null;
113
+ }
114
+ }
115
+ export function saveToken(accountId, token) {
116
+ ensureDirectories();
117
+ atomicWriteFile(getTokenPath(accountId), JSON.stringify(token, null, 2));
118
+ }
119
+ export function deleteToken(accountId) {
120
+ try {
121
+ fs.unlinkSync(getTokenPath(accountId));
122
+ }
123
+ catch {
124
+ // Token file may not exist
125
+ }
126
+ }
127
+ // ---------------------------------------------------------------------------
128
+ // Active Token Resolution
129
+ // ---------------------------------------------------------------------------
130
+ export function getActiveToken() {
131
+ const mode = getAuthMode();
132
+ if (mode === 'manual_token') {
133
+ const accessToken = process.env.SALESFORCE_ACCESS_TOKEN || '';
134
+ const instanceUrl = process.env.SALESFORCE_INSTANCE_URL || 'https://login.salesforce.com';
135
+ return {
136
+ accountId: 'manual',
137
+ token: {
138
+ access_token: accessToken,
139
+ instance_url: instanceUrl,
140
+ expires_at: Number.MAX_SAFE_INTEGER,
141
+ username: 'manual-token',
142
+ },
143
+ };
144
+ }
145
+ if (mode === 'unconfigured') {
146
+ throw new ConnectorError('No Salesforce authentication configured', 'UNCONFIGURED', 'Set up authentication: (1) Set SALESFORCE_CLIENT_ID and SALESFORCE_CLIENT_SECRET for OAuth, or (2) Set SALESFORCE_ACCESS_TOKEN and SALESFORCE_INSTANCE_URL for manual token mode. See README for details.');
147
+ }
148
+ const config = loadAccounts();
149
+ if (config.accounts.length === 0) {
150
+ throw new ConnectorError('No Salesforce accounts connected', 'NO_ACCOUNT', 'Call salesforce_connect_account to connect your Salesforce account.');
151
+ }
152
+ const accountId = config.accounts[0].id;
153
+ const token = loadToken(accountId);
154
+ if (!token) {
155
+ throw new ConnectorError('Salesforce credentials not found', 'NO_CREDENTIALS', 'Call salesforce_connect_account to reconnect.');
156
+ }
157
+ return { accountId, token };
158
+ }
159
+ // ---------------------------------------------------------------------------
160
+ // Standalone OAuth Flow
161
+ // ---------------------------------------------------------------------------
162
+ let authInProgress = false;
163
+ export async function startStandaloneOAuth() {
164
+ if (authInProgress) {
165
+ return { success: false, error: 'Authentication already in progress. Please complete the current flow first.' };
166
+ }
167
+ const clientId = process.env.SALESFORCE_CLIENT_ID;
168
+ const clientSecret = process.env.SALESFORCE_CLIENT_SECRET;
169
+ if (!clientId || !clientSecret) {
170
+ return {
171
+ success: false,
172
+ error: 'SALESFORCE_CLIENT_ID and SALESFORCE_CLIENT_SECRET must be set for standalone OAuth.',
173
+ };
174
+ }
175
+ authInProgress = true;
176
+ try {
177
+ const result = await runOAuthCallbackServer(clientId, clientSecret);
178
+ return result;
179
+ }
180
+ finally {
181
+ authInProgress = false;
182
+ }
183
+ }
184
+ async function runOAuthCallbackServer(clientId, clientSecret) {
185
+ const state = crypto.randomBytes(32).toString('hex');
186
+ const codeVerifier = crypto.randomBytes(32).toString('base64url');
187
+ const codeChallenge = crypto.createHash('sha256').update(codeVerifier).digest('base64url');
188
+ const port = parseInt(process.env.SALESFORCE_OAUTH_PORT || '0', 10);
189
+ // Hard-coded loopback bind. We deliberately do NOT honour an env override
190
+ // (previously `MCP_OAUTH_BIND_HOST`): an OAuth callback server with a
191
+ // short-lived auth code is a privilege-bearing local service and must
192
+ // never be exposed beyond loopback. (M3.2 — VAL-SALESFORCE-017..019.)
193
+ const bindHost = '127.0.0.1';
194
+ const isSandbox = process.env.SALESFORCE_SANDBOX === 'true';
195
+ const loginBase = isSandbox ? 'https://test.salesforce.com' : 'https://login.salesforce.com';
196
+ const timeoutMs = 5 * 60 * 1000;
197
+ return new Promise((resolve) => {
198
+ const server = http.createServer(async (req, res) => {
199
+ if (!req.url?.startsWith('/callback')) {
200
+ res.writeHead(404);
201
+ res.end('Not found');
202
+ return;
203
+ }
204
+ const url = new URL(req.url, `http://${bindHost}:${actualPort}`);
205
+ const code = url.searchParams.get('code');
206
+ const returnedState = url.searchParams.get('state');
207
+ const error = url.searchParams.get('error');
208
+ if (error) {
209
+ res.writeHead(200, { 'Content-Type': 'text/html' });
210
+ res.end('<html><body><h2>Authentication failed</h2><p>You can close this window.</p></body></html>');
211
+ cleanup();
212
+ resolve({ success: false, error: `OAuth error: ${error}` });
213
+ return;
214
+ }
215
+ if (returnedState !== state) {
216
+ res.writeHead(400, { 'Content-Type': 'text/html' });
217
+ res.end('<html><body><h2>Invalid state parameter</h2><p>Please try again.</p></body></html>');
218
+ cleanup();
219
+ resolve({ success: false, error: 'OAuth state mismatch — possible CSRF attack.' });
220
+ return;
221
+ }
222
+ if (!code) {
223
+ res.writeHead(400, { 'Content-Type': 'text/html' });
224
+ res.end('<html><body><h2>Missing authorization code</h2><p>Please try again.</p></body></html>');
225
+ cleanup();
226
+ resolve({ success: false, error: 'No authorization code received.' });
227
+ return;
228
+ }
229
+ try {
230
+ const redirectUri = `http://localhost:${actualPort}/callback`;
231
+ const tokenResponse = await fetch(`${loginBase}/services/oauth2/token`, {
232
+ method: 'POST',
233
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
234
+ body: new URLSearchParams({
235
+ grant_type: 'authorization_code',
236
+ client_id: clientId,
237
+ client_secret: clientSecret,
238
+ redirect_uri: redirectUri,
239
+ code,
240
+ code_verifier: codeVerifier,
241
+ }).toString(),
242
+ });
243
+ if (!tokenResponse.ok) {
244
+ const errText = await tokenResponse.text();
245
+ res.writeHead(200, { 'Content-Type': 'text/html' });
246
+ res.end('<html><body><h2>Token exchange failed</h2><p>You can close this window.</p></body></html>');
247
+ cleanup();
248
+ resolve({ success: false, error: `Token exchange failed: ${errText}` });
249
+ return;
250
+ }
251
+ const tokenData = (await tokenResponse.json());
252
+ const username = tokenData.id?.split('/').pop() || `user-${Date.now()}`;
253
+ const accountId = sanitizeFilename(username);
254
+ const instanceUrl = tokenData.instance_url;
255
+ const token = {
256
+ access_token: tokenData.access_token,
257
+ refresh_token: tokenData.refresh_token,
258
+ instance_url: instanceUrl,
259
+ issued_at: tokenData.issued_at,
260
+ username,
261
+ expires_at: Date.now() + 2 * 60 * 60 * 1000,
262
+ login_url: loginBase,
263
+ };
264
+ saveToken(accountId, token);
265
+ const config = loadAccounts();
266
+ const existingIdx = config.accounts.findIndex((a) => a.id === accountId);
267
+ const account = {
268
+ id: accountId,
269
+ username,
270
+ instance_url: instanceUrl,
271
+ is_sandbox: isSandbox,
272
+ connected_at: new Date().toISOString(),
273
+ };
274
+ if (existingIdx >= 0) {
275
+ config.accounts[existingIdx] = account;
276
+ }
277
+ else {
278
+ config.accounts.push(account);
279
+ }
280
+ saveAccounts(config);
281
+ res.writeHead(200, { 'Content-Type': 'text/html' });
282
+ res.end('<html><body><h2>Authentication successful!</h2><p>You can close this window.</p></body></html>');
283
+ cleanup();
284
+ resolve({ success: true, username });
285
+ }
286
+ catch (err) {
287
+ res.writeHead(500, { 'Content-Type': 'text/html' });
288
+ res.end('<html><body><h2>Authentication error</h2><p>You can close this window.</p></body></html>');
289
+ cleanup();
290
+ resolve({
291
+ success: false,
292
+ error: `Token exchange error: ${err instanceof Error ? err.message : String(err)}`,
293
+ });
294
+ }
295
+ });
296
+ let actualPort = port;
297
+ let timeoutHandle;
298
+ const cleanup = () => {
299
+ clearTimeout(timeoutHandle);
300
+ server.close();
301
+ };
302
+ server.listen(port, bindHost, () => {
303
+ const addr = server.address();
304
+ if (addr && typeof addr !== 'string') {
305
+ actualPort = addr.port;
306
+ }
307
+ const redirectUri = `http://localhost:${actualPort}/callback`;
308
+ const scopes = process.env.SALESFORCE_OAUTH_SCOPES || 'api refresh_token';
309
+ const authorizeUrl = `${loginBase}/services/oauth2/authorize?` +
310
+ new URLSearchParams({
311
+ client_id: clientId,
312
+ redirect_uri: redirectUri,
313
+ response_type: 'code',
314
+ scope: scopes,
315
+ state,
316
+ code_challenge: codeChallenge,
317
+ code_challenge_method: 'S256',
318
+ }).toString();
319
+ console.error(`[Salesforce MCP] Open this URL to authenticate:\n${authorizeUrl}`);
320
+ });
321
+ timeoutHandle = setTimeout(() => {
322
+ cleanup();
323
+ resolve({ success: false, error: 'OAuth flow timed out after 5 minutes.' });
324
+ }, timeoutMs);
325
+ server.on('error', (err) => {
326
+ cleanup();
327
+ resolve({ success: false, error: `OAuth server error: ${err.message}` });
328
+ });
329
+ });
330
+ }
331
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Path to bridge state file, supporting both current and legacy env vars.
3
+ */
4
+ export declare const BRIDGE_STATE_PATH: string;
5
+ /**
6
+ * Send a request to the host app bridge.
7
+ */
8
+ export declare const bridgeRequest: (urlPath: string, body?: Record<string, unknown>) => Promise<{
9
+ success: boolean;
10
+ username?: string;
11
+ warning?: string;
12
+ error?: string;
13
+ }>;
14
+ //# sourceMappingURL=bridge.d.ts.map
package/dist/bridge.js ADDED
@@ -0,0 +1,37 @@
1
+ import * as fs from 'node:fs';
2
+ import { REQUEST_TIMEOUT_MS } from './types.js';
3
+ /**
4
+ * Path to bridge state file, supporting both current and legacy env vars.
5
+ */
6
+ export const BRIDGE_STATE_PATH = process.env.MCP_HOST_BRIDGE_STATE || process.env.MINDSTONE_REBEL_BRIDGE_STATE || '';
7
+ const loadBridgeState = () => {
8
+ if (!BRIDGE_STATE_PATH)
9
+ return null;
10
+ try {
11
+ const raw = fs.readFileSync(BRIDGE_STATE_PATH, 'utf8');
12
+ return JSON.parse(raw);
13
+ }
14
+ catch {
15
+ return null;
16
+ }
17
+ };
18
+ /**
19
+ * Send a request to the host app bridge.
20
+ */
21
+ export const bridgeRequest = async (urlPath, body = {}) => {
22
+ const bridge = loadBridgeState();
23
+ if (!bridge) {
24
+ return { success: false, error: 'Bridge not available' };
25
+ }
26
+ const response = await fetch(`http://127.0.0.1:${bridge.port}${urlPath}`, {
27
+ method: 'POST',
28
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
29
+ headers: {
30
+ 'Content-Type': 'application/json',
31
+ Authorization: `Bearer ${bridge.token}`,
32
+ },
33
+ body: JSON.stringify(body),
34
+ });
35
+ return response.json();
36
+ };
37
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1,23 @@
1
+ import jsforce from 'jsforce';
2
+ import { type SalesforceAccount } from './types.js';
3
+ /**
4
+ * Ensure the connector is in a mode that can make API calls.
5
+ */
6
+ export declare function requireAuth(): void;
7
+ /**
8
+ * Get a jsforce connection for the current account.
9
+ */
10
+ export declare function getConnection(accountId?: string): Promise<jsforce.Connection>;
11
+ /**
12
+ * Execute an operation with a jsforce connection, handling session expiry.
13
+ */
14
+ export declare function withConnection<T>(accountId: string | undefined, operation: (conn: jsforce.Connection) => Promise<T>): Promise<T>;
15
+ /**
16
+ * List all connected accounts with their status.
17
+ */
18
+ export declare function listConnectedAccounts(): SalesforceAccount[];
19
+ /**
20
+ * Remove a connected account.
21
+ */
22
+ export declare function removeAccount(usernameOrId: string): void;
23
+ //# sourceMappingURL=client.d.ts.map