@withone/mcp 2.1.1 → 2.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/README.md CHANGED
@@ -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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withone/mcp",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
4
4
  "description": "A Model Context Protocol Server for One",
5
5
  "type": "module",
6
6
  "bin": {