@mindstone/mcp-server-salesforce 0.1.2 → 0.1.3

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/README.md CHANGED
@@ -1,13 +1,117 @@
1
1
  # @mindstone/mcp-server-salesforce
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/@mindstone/mcp-server-salesforce.svg)](https://www.npmjs.com/package/@mindstone/mcp-server-salesforce)
4
+ [![License: FSL-1.1-MIT](https://img.shields.io/badge/License-FSL--1.1--MIT-blue.svg)](./LICENSE)
5
+
3
6
  Salesforce CRM MCP server — accounts, contacts, opportunities, leads, tasks, users, and custom objects via the Salesforce API.
4
7
 
5
- ## Installation
8
+ *Best when an MCP host needs a local, install-and-run CRM connector for everyday sales work rather than a Salesforce-hosted endpoint.*
9
+
10
+ ## Status
11
+
12
+ - **Version:** [0.1.2](./CHANGELOG.md) · [npm](https://www.npmjs.com/package/@mindstone/mcp-server-salesforce)
13
+ - **Auth:** OAuth (local 127.0.0.1 callback) or static access token ([`SALESFORCE_CLIENT_SECRET`](./server.json), [`SALESFORCE_ACCESS_TOKEN`](./server.json))
14
+ - **Tools:** [26](./src/tools/) (accounts, contacts, opportunities, leads, tasks, query)
15
+ - **Surface:** cloud-api
16
+ - **Machine-readable:** [`STATUS.json`](./STATUS.json)
17
+
18
+ ## Why this exists
19
+
20
+ Salesforce's own MCP options are the right starting point for many teams. This package is for teams that want a normal npm MCP server they can run locally in any stdio host.
21
+
22
+ It gives an assistant focused access to the CRM work people actually ask for: finding accounts and contacts, updating leads, creating opportunities and tasks, running CRM searches, and working with custom objects. The benefit is a short path from a natural-language sales request to the right Salesforce records, with write actions kept visible to the host.
23
+
24
+ ## Example interaction
25
+
26
+ > "Find Acme Corp in Salesforce, create a Q3 expansion opportunity for $75,000, and add a follow-up task for next Friday."
27
+
28
+ Tools the host calls:
29
+ 1. `salesforce_get_accounts` — searches accounts by name and returns the matching account ID.
30
+ 2. `salesforce_create_opportunity` — creates the opportunity against that account.
31
+ 3. `salesforce_create_task` — adds a follow-up task related to the new opportunity.
32
+
33
+ Response (trimmed):
34
+
35
+ ```json
36
+ {
37
+ "account": { "id": "001xx000003DGbYAAW", "name": "Acme Corp" },
38
+ "opportunity": {
39
+ "id": "006xx000004TmiYAAS",
40
+ "name": "Q3 expansion",
41
+ "amount": 75000,
42
+ "stage": "Prospecting"
43
+ },
44
+ "task": {
45
+ "id": "00Txx000006rYxDEAU",
46
+ "subject": "Follow up on Q3 expansion"
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## Requirements
52
+
53
+ - Node.js 20+
54
+ - npm
55
+ - A Salesforce Connected App for the OAuth path, or a valid access token plus instance URL for manual-token mode.
56
+
57
+ <!-- BEGIN INSTALL_LINKS: do not edit by hand; regenerated by scripts/gen-install-links.mjs -->
58
+ ## One-click install
59
+
60
+ [![Add to Cursor](https://img.shields.io/badge/Add_to_Cursor-black?style=for-the-badge&logo=cursor&logoColor=white)](cursor://anysphere.cursor-deeplink/mcp/install?name=Salesforce&config=eyJ0eXBlIjoic3RkaW8iLCJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBtaW5kc3RvbmUvbWNwLXNlcnZlci1zYWxlc2ZvcmNlIl0sImVudiI6eyJTQUxFU0ZPUkNFX0NMSUVOVF9JRCI6IiIsIlNBTEVTRk9SQ0VfQ0xJRU5UX1NFQ1JFVCI6IiIsIlNBTEVTRk9SQ0VfQUNDRVNTX1RPS0VOIjoiIiwiU0FMRVNGT1JDRV9DT05GSUdfRElSIjoifi8ubWNwL3NhbGVzZm9yY2UiLCJTQUxFU0ZPUkNFX09BVVRIX1BPUlQiOiIwIn19)
61
+ [![Add to VS Code](https://img.shields.io/badge/Add_to_VS_Code-007ACC?style=for-the-badge&logo=visual-studio-code&logoColor=white)](vscode:mcp/install?%7B%22name%22%3A%22Salesforce%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40mindstone%2Fmcp-server-salesforce%22%5D%2C%22env%22%3A%7B%22SALESFORCE_CLIENT_ID%22%3A%22%22%2C%22SALESFORCE_CLIENT_SECRET%22%3A%22%22%2C%22SALESFORCE_ACCESS_TOKEN%22%3A%22%22%2C%22SALESFORCE_CONFIG_DIR%22%3A%22%7E%2F.mcp%2Fsalesforce%22%2C%22SALESFORCE_OAUTH_PORT%22%3A%220%22%7D%7D)
62
+ [![Add to VS Code Insiders](https://img.shields.io/badge/Add_to_VS_Code_Insiders-24bfa5?style=for-the-badge&logo=visual-studio-code&logoColor=white)](vscode-insiders:mcp/install?%7B%22name%22%3A%22Salesforce%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40mindstone%2Fmcp-server-salesforce%22%5D%2C%22env%22%3A%7B%22SALESFORCE_CLIENT_ID%22%3A%22%22%2C%22SALESFORCE_CLIENT_SECRET%22%3A%22%22%2C%22SALESFORCE_ACCESS_TOKEN%22%3A%22%22%2C%22SALESFORCE_CONFIG_DIR%22%3A%22%7E%2F.mcp%2Fsalesforce%22%2C%22SALESFORCE_OAUTH_PORT%22%3A%220%22%7D%7D)
63
+
64
+ After clicking the button, your host will prompt you to fill: `SALESFORCE_CLIENT_ID`, `SALESFORCE_CLIENT_SECRET`, `SALESFORCE_ACCESS_TOKEN`, `SALESFORCE_CONFIG_DIR`, `SALESFORCE_OAUTH_PORT`.
65
+
66
+ <details>
67
+ <summary>Manual config for Claude Desktop / Claude Code / Goose / Continue.dev (Salesforce)</summary>
68
+
69
+ ```json
70
+ {
71
+ "mcpServers": {
72
+ "Salesforce": {
73
+ "command": "npx",
74
+ "args": [
75
+ "-y",
76
+ "@mindstone/mcp-server-salesforce"
77
+ ],
78
+ "env": {
79
+ "SALESFORCE_CLIENT_ID": "",
80
+ "SALESFORCE_CLIENT_SECRET": "",
81
+ "SALESFORCE_ACCESS_TOKEN": "",
82
+ "SALESFORCE_CONFIG_DIR": "~/.mcp/salesforce",
83
+ "SALESFORCE_OAUTH_PORT": "0"
84
+ }
85
+ }
86
+ }
87
+ }
88
+ ```
89
+
90
+ </details>
91
+ <!-- END INSTALL_LINKS -->
92
+
93
+ ## Quick Start
94
+
95
+ ### Install & build
96
+
97
+ ```bash
98
+ cd <path-to-repo>/connectors/salesforce
99
+ npm install
100
+ npm run build
101
+ ```
102
+
103
+ ### npx
6
104
 
7
105
  ```bash
8
106
  npx -y @mindstone/mcp-server-salesforce
9
107
  ```
10
108
 
109
+ ### Local
110
+
111
+ ```bash
112
+ node dist/index.js
113
+ ```
114
+
11
115
  ## Configuration
12
116
 
13
117
  ### OAuth (Recommended)
@@ -28,6 +132,8 @@ Then call `salesforce_connect_account` to start the OAuth flow.
28
132
  ### Additional Options
29
133
 
30
134
  - `SALESFORCE_CONFIG_DIR` — Custom config directory (default: `~/.mcp/salesforce`)
135
+ - `SALESFORCE_OAUTH_PORT` — OAuth callback port (`0` = OS-assigned; default: `0`)
136
+ - `SALESFORCE_OAUTH_SCOPES` — Space-separated OAuth scopes. Leave unset to use the connector default.
31
137
 
32
138
  ## Available Tools (26)
33
139
 
@@ -75,6 +181,13 @@ Then call `salesforce_connect_account` to start the OAuth flow.
75
181
  - `salesforce_update_record` — Update any Salesforce record
76
182
  - `salesforce_get_records` — Query any Salesforce object
77
183
 
78
- ## License
184
+ ## Security notes
185
+
186
+ - The standalone OAuth callback server binds to `127.0.0.1`; it does not honour environment overrides that would expose the callback beyond loopback.
187
+ - OAuth credentials are stored under `SALESFORCE_CONFIG_DIR` (default `~/.mcp/salesforce`) with restrictive directory and file permissions.
188
+ - Write and disconnect tools are marked so capable hosts can ask for confirmation before changing Salesforce data.
189
+ - SOQL helper paths escape string and `LIKE` values, strip comments quote-safely before applying the query limit cap, and enforce a maximum of 200 records for raw SOQL queries.
190
+
191
+ ## Licence
79
192
 
80
- FSL-1.1-MIT
193
+ [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/client.js CHANGED
@@ -44,10 +44,18 @@ export async function getConnection(accountId) {
44
44
  const connectionConfig = {
45
45
  instanceUrl: tokenData.instance_url,
46
46
  accessToken: tokenData.access_token,
47
- refreshToken: tokenData.refresh_token,
48
47
  };
48
+ // Only hand jsforce a refresh token when we can also give it a way to USE
49
+ // that token — i.e. the OAuth2 client info to build a refresh delegate.
50
+ // jsforce throws synchronously at construction otherwise:
51
+ // "Refresh token is specified without oauth2 client information or refresh function".
52
+ // This is the bridge-mode case: the host app owns OAuth and does not pass
53
+ // SALESFORCE_CLIENT_ID/SECRET into the connector, so we operate on the access
54
+ // token alone and surface SESSION_EXPIRED (-> reconnect) on expiry rather than
55
+ // crashing every tool call. (See docs/plans/260612_fix-salesforce-bridge-refresh-token/.)
49
56
  if (clientId && clientSecret && tokenData.refresh_token) {
50
57
  connectionConfig.oauth2 = { clientId, clientSecret, loginUrl };
58
+ connectionConfig.refreshToken = tokenData.refresh_token;
51
59
  }
52
60
  const conn = new jsforce.Connection(connectionConfig);
53
61
  conn.on('refresh', async (accessToken) => {
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@mindstone/mcp-server-salesforce",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "mcpName": "io.github.mindstone/mcp-server-salesforce",
5
- "description": "Salesforce CRM MCP server \u2014 accounts, contacts, opportunities, leads, tasks, and custom objects via Salesforce API",
5
+ "description": "Salesforce CRM MCP server — accounts, contacts, opportunities, leads, tasks, and custom objects via Salesforce API",
6
6
  "license": "FSL-1.1-MIT",
7
7
  "type": "module",
8
8
  "bin": {