@withone/mcp 2.1.1 → 2.2.1

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
@@ -20,7 +20,7 @@
20
20
  <a href="https://npmjs.com/package/@withone/mcp"><img src="https://img.shields.io/npm/v/%40withone%2Fmcp" alt="npm version"></a>
21
21
  </p>
22
22
 
23
- Connect your AI agents to 700+ apps through a single [MCP](https://modelcontextprotocol.io) server. Find the actions a task needs with their documentation, and execute API calls across platforms, without having to manage OAuth tokens or API keys.
23
+ Connect your AI agents to 1000+ apps through a single [MCP](https://modelcontextprotocol.io) server. Find the actions a task needs with their documentation, and execute API calls across platforms, without having to manage OAuth tokens or API keys.
24
24
 
25
25
  ```bash
26
26
  npm install -g @withone/cli
@@ -31,7 +31,7 @@ That's it. The [One CLI](https://www.npmjs.com/package/@withone/cli) will prompt
31
31
 
32
32
  ## Capabilities
33
33
 
34
- - **700+ platforms.** Gmail, Slack, Shopify, HubSpot, Stripe, Linear, QuickBooks, and [more](https://app.withone.ai/tools).
34
+ - **1000+ platforms.** Gmail, Slack, Shopify, HubSpot, Stripe, Linear, QuickBooks, and [more](https://app.withone.ai/tools).
35
35
  - **Natural language execution.** "read my last gmail email", "send a message to #general on Slack"
36
36
  - **Code generation.** "build a form to send emails using Gmail", "create a dashboard that lists my Linear projects"
37
37
  - **No tool bloat.** Only 3 tools exposed regardless of how many platforms or actions you connect. One call finds every action a task needs, across platforms, with its documentation, so your agent's context window stays clean.
@@ -66,7 +66,7 @@ The server exposes three MCP tools:
66
66
 
67
67
  ### Finding actions
68
68
 
69
- `find_one_actions` takes one `requests` entry per operation, each a kebab-case `platform` and a short `intent` naming the operation alone (`"send a message to a channel"`, not the message). A `task` describes the whole job in general terms, and an `ai_model` names the model asking; agents are asked to send both with every find, since the task helps tell similar actions apart. For each intent, One's decision model picks the action to use; the answer documents it, sets apart a substitute when the model was unsure, and lists a few alternatives. Large documents come back as a digest; call `find_one_actions` again with `load: [{ action_id, section }]` for a section it left out, `full: true` for the whole document, or `toc: true` for its table of contents. `ONE_ACTION_IDS`, `ONE_PERMISSIONS` and `ONE_CONNECTION_KEYS` apply to every answer: an action they refuse is never offered, and when they refuse the model's pick, the next allowed candidate takes its place.
69
+ `find_one_actions` takes one `requests` entry per operation, each a kebab-case `platform` and a short `intent` naming the operation alone (`"send a message to a channel"`, not the message). A `task` describes the whole job in general terms, and an `ai_model` names the model asking; agents are asked to send both with every find, since the task helps tell similar actions apart. For each intent, One's decision model picks the action to use; the answer documents it, sets apart a substitute when the model was unsure, and lists a few alternatives. A `platform` no active platform has (`clickup` for `click-up`) is not searched: the answer names the platforms it may have meant, closest first, so the agent can ask again with the right one. Large documents come back as a digest; call `find_one_actions` again with `load: [{ action_id, section }]` for a section it left out, `full: true` for the whole document, or `toc: true` for its table of contents. `ONE_ACTION_IDS`, `ONE_PERMISSIONS` and `ONE_CONNECTION_KEYS` apply to every answer: an action they refuse is never offered, and when they refuse the model's pick, the next allowed candidate takes its place.
70
70
 
71
71
  Upgrading from 1.x: `search_one_platform_actions` and `get_one_action_knowledge` are removed. `find_one_actions` replaces both.
72
72
 
package/build/find.js CHANGED
@@ -93,6 +93,13 @@ function status(answer, narrowed) {
93
93
  if (narrowed.replaced) {
94
94
  return 'The chosen action is not allowed on this server, so this is the next allowed candidate: check it fits before using it.';
95
95
  }
96
+ if (answer.selector === 'unknown_platform') {
97
+ const opening = `No active platform is named \`${answer.platform}\`.`;
98
+ const suggestions = answer.suggestions ?? [];
99
+ return suggestions.length === 0
100
+ ? `${opening} Check the platform name: \`list_one_integrations\` gives the exact name of each connected integration.`
101
+ : `${opening} Did you mean ${suggestions.map((s) => `\`${s}\``).join(', ')}? Ask again with the platform you meant.`;
102
+ }
96
103
  if (answer.selector === 'none_fit' || answer.selected.length === 0) {
97
104
  return answer.alternatives.length === 0
98
105
  ? 'No action fits this intent, and nothing close was found. Rephrase it, or check the platform name.'
@@ -131,6 +131,18 @@ describe('find_one_actions', () => {
131
131
  assert.ok(text.includes('No action fits this intent, and nothing close was found.'));
132
132
  assert.ok(!text.includes(FIND_EXECUTE_HINT));
133
133
  });
134
+ it('names the platforms core suggests for a name no active platform has', async () => {
135
+ const unknown = (suggestions) => answer({ platform: 'clickup', intent: 'create a task', selected: [], alternatives: [], selector: 'unknown_platform', confidence: undefined, suggestions });
136
+ const asked = [
137
+ { platform: 'clickup', intent: 'create a task' },
138
+ { platform: 'clickup', intent: 'create a task' },
139
+ ];
140
+ const text = await findOneActions({ requests: asked }, deps([unknown(['click-up', 'click-house']), unknown()]), settings());
141
+ assert.ok(text.includes('No active platform is named `clickup`. Did you mean `click-up`, `click-house`? Ask again with the platform you meant.'), text);
142
+ assert.ok(text.includes('Check the platform name: `list_one_integrations` gives the exact name'), text);
143
+ assert.ok(!text.includes('No action fits'), 'an unknown platform is not read as a platform with no fitting action');
144
+ assert.ok(!text.includes(FIND_EXECUTE_HINT), 'nothing was documented');
145
+ });
134
146
  it('loads what each entry asked for, refusing one this server may not use in the words for a missing one', async () => {
135
147
  const text = await findOneActions({ load: [{ action_id: 'a', section: 'Response Fields' }, { action_id: 'missing' }, { action_id: 'b' }] }, deps([], { a: LARGE }), settings({ actionIds: ['a', 'missing'] }));
136
148
  assert.ok(text.includes('### Action a'));
package/build/index.js CHANGED
@@ -93,7 +93,7 @@ async function handleGetIntegrations(args) {
93
93
  const resolvedAllowed = (await oneClient.resolveAllowedActions(ONE_ACTION_IDS))
94
94
  .filter(action => isMethodAllowed(action.method, ONE_PERMISSIONS));
95
95
  // Execute mode lists only connections: every connection carries its
96
- // access, and the full catalog (800+ platforms) would sit in the agent's
96
+ // access, and the full catalog (1000+ platforms) would sit in the agent's
97
97
  // context for the rest of the session. Knowledge/code-gen mode also lists
98
98
  // available platforms so code can target one that is not connected yet,
99
99
  // unless connection keys are scoped.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withone/mcp",
3
- "version": "2.1.1",
3
+ "version": "2.2.1",
4
4
  "description": "A Model Context Protocol Server for One",
5
5
  "type": "module",
6
6
  "bin": {