dsh-oauth-mcp 0.0.3 → 0.0.4
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 +1 -1
- package/lib/build-info.js +2 -2
- package/lib/tools/reveal.js +58 -43
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -215,7 +215,7 @@ GitHub、Zendesk、Slack、PagerDuty、MongoDB Atlas、Render、Shopify、Atlass
|
|
|
215
215
|
pnpm test # 等价于 node --test "test/**/*.test.js"
|
|
216
216
|
```
|
|
217
217
|
|
|
218
|
-
仓库记录的最近一次全量运行是 **
|
|
218
|
+
仓库记录的最近一次全量运行是 **667 例**,全绿。用例分单元、协议契约、端到端、宿主集成、冒烟五类,外加发布清单与仓库卫生两条守卫。端到端有两种:`test/e2e/full-flow.test.js` 走协议层,`test/e2e/host-flow.test.js` 走完整链路。
|
|
219
219
|
|
|
220
220
|
`node --test test/` 在 Node v24 上不可用:`--test` 的位置参数按 glob 解析,`test/` 会被当成模块去加载。
|
|
221
221
|
|
package/lib/build-info.js
CHANGED
|
@@ -12,13 +12,13 @@ import { createTranslator } from './i18n/index.js'
|
|
|
12
12
|
export const PLUGIN_ID = 'dsh-oauth-mcp'
|
|
13
13
|
|
|
14
14
|
/** The version of the plugin. It is reported to every server it talks to. */
|
|
15
|
-
export const PLUGIN_VERSION = '0.0.
|
|
15
|
+
export const PLUGIN_VERSION = '0.0.4'
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Short marker of the current source revision. Bump it whenever the behaviour
|
|
19
19
|
* of the user facing surfaces (commands, tools, panel, callback pages) changes.
|
|
20
20
|
*/
|
|
21
|
-
export const BUILD_STAMP = '2026-11-08-lazy-tools'
|
|
21
|
+
export const BUILD_STAMP = '2026-11-08-lazy-tools-reveal-fix'
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* One line that names the version and the build of the running code.
|
package/lib/tools/reveal.js
CHANGED
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
* description has to carry that job on its own: the model sees this tool and
|
|
12
12
|
* nothing else.
|
|
13
13
|
*
|
|
14
|
+
* The shape follows the host's contract: `execute` resolves with the data (one
|
|
15
|
+
* row per server), and `output.render` turns that data into the content
|
|
16
|
+
* blocks the model reads. The schema describes the data.
|
|
17
|
+
*
|
|
14
18
|
* @module dsh-oauth-mcp/tools/reveal
|
|
15
19
|
*/
|
|
16
20
|
|
|
@@ -21,7 +25,7 @@ export { REVEAL_TOOL_NAME }
|
|
|
21
25
|
/** JSON Schema of the value the tool resolves with. */
|
|
22
26
|
const REVEAL_OUTPUT_SCHEMA = Object.freeze({
|
|
23
27
|
type: 'array',
|
|
24
|
-
description: 'The servers
|
|
28
|
+
description: 'The servers that were revealed, and the tools they expose.',
|
|
25
29
|
items: {
|
|
26
30
|
type: 'object',
|
|
27
31
|
properties: {
|
|
@@ -29,6 +33,7 @@ const REVEAL_OUTPUT_SCHEMA = Object.freeze({
|
|
|
29
33
|
label: { type: 'string', description: 'The human readable label of the server.' },
|
|
30
34
|
authorized: { type: 'boolean', description: 'Whether the server has a usable grant.' },
|
|
31
35
|
connected: { type: 'boolean', description: 'Whether the MCP session is established.' },
|
|
36
|
+
revealed: { type: 'boolean', description: 'Whether the tools of this server are callable now.' },
|
|
32
37
|
tools: {
|
|
33
38
|
type: 'array',
|
|
34
39
|
items: { type: 'string' },
|
|
@@ -36,7 +41,7 @@ const REVEAL_OUTPUT_SCHEMA = Object.freeze({
|
|
|
36
41
|
'The public names of the tools of this server, for example "mcp_oauth__notion__search". They are callable from the next step on.',
|
|
37
42
|
},
|
|
38
43
|
},
|
|
39
|
-
required: ['serverId', 'label', 'authorized', 'connected', 'tools'],
|
|
44
|
+
required: ['serverId', 'label', 'authorized', 'connected', 'revealed', 'tools'],
|
|
40
45
|
},
|
|
41
46
|
})
|
|
42
47
|
|
|
@@ -55,7 +60,7 @@ function buildDescription() {
|
|
|
55
60
|
'so that every step does not carry their schemas. ' +
|
|
56
61
|
'Call it with {"server":"<serverId>"} to reveal one server, ' +
|
|
57
62
|
'or without arguments to list the authorized servers. ' +
|
|
58
|
-
'The answer lists the
|
|
63
|
+
'The answer lists the servers and the names of their tools; those names are callable from the next step on.'
|
|
59
64
|
)
|
|
60
65
|
}
|
|
61
66
|
|
|
@@ -65,10 +70,44 @@ function buildDescription() {
|
|
|
65
70
|
* @param {object} options The options.
|
|
66
71
|
* @param {import('../mcp/reveal.js').RevealState} options.reveal The reveal state.
|
|
67
72
|
* @param {{ status: (serverId?: string) => Promise<object[]>, listToolNames: (serverId: string) => string[] }} options.service The plugin service.
|
|
68
|
-
* @param {() => string} [options.locale] The current locale.
|
|
69
73
|
* @returns {object} The tool definition.
|
|
70
74
|
*/
|
|
71
|
-
export function createRevealTool({ reveal, service
|
|
75
|
+
export function createRevealTool({ reveal, service }) {
|
|
76
|
+
/**
|
|
77
|
+
* Render the rows into the text the model reads.
|
|
78
|
+
*
|
|
79
|
+
* @param {object} args The arguments the tool was called with.
|
|
80
|
+
* @param {object[]} value The rows.
|
|
81
|
+
* @returns {{ type: 'text', text: string }[]} The content blocks.
|
|
82
|
+
*/
|
|
83
|
+
function render(args, value) {
|
|
84
|
+
void args
|
|
85
|
+
const rows = Array.isArray(value) ? value : []
|
|
86
|
+
if (rows.length === 0) {
|
|
87
|
+
return [
|
|
88
|
+
{
|
|
89
|
+
type: 'text',
|
|
90
|
+
text: 'No MCP server is configured in this profile. Add one in the settings, then authorize it.',
|
|
91
|
+
},
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
const lines = []
|
|
95
|
+
for (const row of rows) {
|
|
96
|
+
const state = row.authorized ? 'authorized' : 'not authorized yet'
|
|
97
|
+
const connection = row.connected ? 'connected' : 'not connected'
|
|
98
|
+
const callable = row.revealed ? 'tools callable now' : 'tools not revealed'
|
|
99
|
+
const tools = row.tools.length > 0 ? row.tools.join(', ') : 'no tools yet'
|
|
100
|
+
lines.push(`${row.serverId} (${row.label}) — ${state} — ${connection} — ${callable}`)
|
|
101
|
+
if (row.tools.length > 0) lines.push(` ${tools}`)
|
|
102
|
+
}
|
|
103
|
+
const revealed = rows.filter((row) => row.revealed).length
|
|
104
|
+
if (revealed > 0) {
|
|
105
|
+
lines.push('')
|
|
106
|
+
lines.push(`The tools of ${revealed} server(s) are callable from the next step on.`)
|
|
107
|
+
}
|
|
108
|
+
return [{ type: 'text', text: lines.join('\n') }]
|
|
109
|
+
}
|
|
110
|
+
|
|
72
111
|
return {
|
|
73
112
|
name: REVEAL_TOOL_NAME,
|
|
74
113
|
description: buildDescription(),
|
|
@@ -81,57 +120,33 @@ export function createRevealTool({ reveal, service, locale }) {
|
|
|
81
120
|
'The id of the MCP server to reveal, for example "notion". Leave it out to list the authorized servers.',
|
|
82
121
|
},
|
|
83
122
|
},
|
|
123
|
+
required: [],
|
|
124
|
+
additionalProperties: false,
|
|
84
125
|
},
|
|
85
|
-
output: { schema: REVEAL_OUTPUT_SCHEMA, render
|
|
126
|
+
output: { schema: REVEAL_OUTPUT_SCHEMA, render },
|
|
86
127
|
execute: async (args, exec) => {
|
|
87
128
|
const agent = exec?.agent
|
|
88
129
|
const requested = typeof args?.server === 'string' ? args.server.trim() : ''
|
|
89
130
|
|
|
90
131
|
const rows = await service.status(requested || undefined)
|
|
91
|
-
|
|
92
|
-
return [
|
|
93
|
-
{
|
|
94
|
-
type: 'text',
|
|
95
|
-
text: requested
|
|
96
|
-
? `No MCP server with the id "${requested}" is configured in this profile.`
|
|
97
|
-
: 'No MCP server is configured in this profile. Add one in the settings, then authorize it.',
|
|
98
|
-
},
|
|
99
|
-
]
|
|
100
|
-
}
|
|
132
|
+
const target = Array.isArray(rows) ? rows : []
|
|
101
133
|
|
|
102
134
|
// Reveal what the model asked for. Without a server id every authorized
|
|
103
135
|
// server is revealed: the model asked what is there, and the answer is
|
|
104
136
|
// more useful than another round trip.
|
|
105
|
-
const wanted = rows.filter((row) => row.authorized).map((row) => row.serverId)
|
|
106
|
-
const target = requested ? rows.filter((row) => row.serverId === requested) : rows
|
|
107
137
|
const revealIds = target.filter((row) => row.authorized).map((row) => row.serverId)
|
|
108
138
|
reveal.reveal(agent, revealIds)
|
|
109
139
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
tools.length > 0 ? `tools: ${tools.join(', ')}` : 'no tools yet',
|
|
119
|
-
].join(' — '),
|
|
120
|
-
)
|
|
121
|
-
}
|
|
122
|
-
if (requested && revealIds.length === 0) {
|
|
123
|
-
lines.push(`The server "${requested}" is not authorized yet, so its tools were not revealed.`)
|
|
124
|
-
}
|
|
125
|
-
if (wanted.length === 0 && !requested) {
|
|
126
|
-
lines.push('No server is authorized yet. Use the oauth-mcp command to authorize one.')
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return [
|
|
130
|
-
{
|
|
131
|
-
type: 'text',
|
|
132
|
-
text: lines.join('\n'),
|
|
133
|
-
},
|
|
134
|
-
]
|
|
140
|
+
return target.map((row) => ({
|
|
141
|
+
serverId: String(row.serverId ?? ''),
|
|
142
|
+
label: String(row.label ?? row.serverId ?? ''),
|
|
143
|
+
authorized: row.authorized === true,
|
|
144
|
+
connected: row.connected === true,
|
|
145
|
+
revealed: revealIds.includes(String(row.serverId ?? '')),
|
|
146
|
+
tools: Array.isArray(row.tools) ? row.tools.map((name) => String(name)) : [],
|
|
147
|
+
}))
|
|
135
148
|
},
|
|
149
|
+
timeoutMs: 30_000,
|
|
150
|
+
isConcurrencySafe: true,
|
|
136
151
|
}
|
|
137
152
|
}
|
package/package.json
CHANGED