ask-user-question-plus 1.0.0 → 1.0.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 +313 -159
- package/dist/mcp-server.js +11 -11
- package/package.json +2 -1
- package/public/index.html +17 -17
package/README.md
CHANGED
|
@@ -3,212 +3,197 @@
|
|
|
3
3
|
[](https://opensource.org/licenses/MIT)
|
|
4
4
|
[](https://www.npmjs.com/package/ask-user-question-plus)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
A MCP server (Streamable HTTP) for asking user questions via a web interface, inspired by the Claude Code AskUserQuestion Tool.
|
|
7
7
|
|
|
8
|
-
!
|
|
8
|
+
> 🌟 Supports Claude Code, Codex, and Gemini CLI!
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
<div align="center">
|
|
13
|
+
|
|
14
|
+
[**English**](#english) | [**中文**](#chinese)
|
|
15
|
+
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
<a id="chinese"></a>
|
|
9
21
|
|
|
10
22
|
## ✨ 特性
|
|
11
23
|
|
|
12
|
-
- **🎨
|
|
13
|
-
- **⌨️ 全键盘操作**:支持方向键、Tab、Space、Enter
|
|
14
|
-
- **📊
|
|
15
|
-
- **🔄 实时通信**:基于 WebSocket
|
|
16
|
-
- **⏱️
|
|
17
|
-
- **📈
|
|
24
|
+
- **🎨 精美界面**:Claude Code AskUserQuestions 风格样式,支持暗/浅色主题适配
|
|
25
|
+
- **⌨️ 全键盘操作**:支持方向键、Tab、Space、Enter 快捷键,操作流畅
|
|
26
|
+
- **📊 丰富交互**:支持单选、多选、推荐选项标记以及自定义输入(Other)
|
|
27
|
+
- **🔄 实时通信**:基于 WebSocket 的实时消息传递,响应迅速
|
|
28
|
+
- **⏱️ 超时保护**:可配置会话超时时间(默认 10 分钟)
|
|
29
|
+
- **📈 高度可扩展**:支持 1-20 个问题,每个问题选项数量不限
|
|
18
30
|
|
|
19
|
-
|
|
31
|
+
## 🚀 部署
|
|
20
32
|
|
|
21
|
-
|
|
22
|
-
| ------------ | ---------------------- | ---------------------------- |
|
|
23
|
-
| 问题数量限制 | 1-4 个 | 1-20 个 |
|
|
24
|
-
| 选项数量限制 | 2-4 个 | 无限制 |
|
|
33
|
+
### 启动参数
|
|
25
34
|
|
|
26
|
-
|
|
35
|
+
| 参数 | 说明 | 默认值 | 示例 |
|
|
36
|
+
| :----------------- | :----------- | :--------------- | :----------------- |
|
|
37
|
+
| `--timeout=<毫秒>` | 会话超时时间 | 600000 (10 分钟) | `--timeout=300000` |
|
|
38
|
+
| `--port=<端口>` | 监听端口 | 3456 | `--port=8080` |
|
|
27
39
|
|
|
28
|
-
###
|
|
40
|
+
### 前台运行
|
|
29
41
|
|
|
30
42
|
```bash
|
|
31
|
-
|
|
43
|
+
npx ask-user-question-plus
|
|
44
|
+
|
|
45
|
+
# 自定义端口和超时
|
|
46
|
+
npx ask-user-question-plus -- --port=3456 --timeout=600000
|
|
32
47
|
```
|
|
33
48
|
|
|
34
|
-
###
|
|
49
|
+
### 后台运行(推荐)
|
|
50
|
+
|
|
51
|
+
#### 使用 pm2
|
|
52
|
+
|
|
53
|
+
> 需先安装 pm2: `npm install -g pm2`
|
|
35
54
|
|
|
36
55
|
```bash
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
56
|
+
pm2 start "npx ask-user-question-plus" --name ask-user-question-plus-service
|
|
57
|
+
|
|
58
|
+
# 带参数启动
|
|
59
|
+
pm2 start "npx ask-user-question-plus -- --port=3456 --timeout=600000" --name ask-user-question-plus-service
|
|
60
|
+
|
|
61
|
+
# 停止服务
|
|
62
|
+
pm2 stop ask-user-question-plus-service
|
|
41
63
|
```
|
|
42
64
|
|
|
43
|
-
|
|
65
|
+
#### 使用 Docker
|
|
44
66
|
|
|
45
|
-
|
|
67
|
+
```bash
|
|
68
|
+
docker compose up -d
|
|
69
|
+
```
|
|
46
70
|
|
|
47
|
-
|
|
71
|
+
## ⚙️ 配置
|
|
48
72
|
|
|
49
|
-
|
|
73
|
+
### Claude Code
|
|
50
74
|
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
"mcpServers": {
|
|
54
|
-
"ask-user-question-plus": {
|
|
55
|
-
"command": "npx",
|
|
56
|
-
"args": ["ask-user-question-plus"]
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
75
|
+
```bash
|
|
76
|
+
claude mcp add -s user -t http AskUserQuestionPlus http://localhost:3456/mcp
|
|
60
77
|
```
|
|
61
78
|
|
|
62
|
-
|
|
79
|
+
### Codex
|
|
63
80
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
}
|
|
81
|
+
在 `~/.codex/config.toml` 中添加配置:
|
|
82
|
+
|
|
83
|
+
```toml
|
|
84
|
+
experimental_use_rmcp_client = true
|
|
85
|
+
|
|
86
|
+
[mcp_servers.AskUserQuestionPlus]
|
|
87
|
+
url = "http://localhost:3456/mcp/"
|
|
73
88
|
```
|
|
74
89
|
|
|
75
|
-
|
|
90
|
+
或者使用命令行:
|
|
76
91
|
|
|
77
|
-
|
|
78
|
-
| ------------------ | -------------- | ---------------- | ------------------ |
|
|
79
|
-
| `--timeout=<毫秒>` | 会话超时时间 | 600000 (10 分钟) | `--timeout=300000` |
|
|
80
|
-
| `--port=<端口>` | WebSocket 端口 | 3456 | `--port=8080` |
|
|
92
|
+
在 `~/.codex/config.toml` 中添加配置:
|
|
81
93
|
|
|
82
|
-
|
|
94
|
+
```toml
|
|
95
|
+
experimental_use_rmcp_client = true
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
codex mcp add AskUserQuestionsPlus --url http://localhost:3456/mcp/
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Gemini CLI
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
gemini mcp add AskUserQuestionPlus http://localhost:3456/mcp -s user --transport http
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
> **⚠️ 注意**:如果遇到 `[Error: Unrecognized key(s) in object: 'type']` 错误 (参见 [issue #15449](https://github.com/google-gemini/gemini-cli/issues/15449)):
|
|
109
|
+
>
|
|
110
|
+
> - 请在 `~/.gemini/settings.json` 中删除 `type` 字段
|
|
111
|
+
> - 或等待 gemini cli `v0.23.0` 发布
|
|
112
|
+
|
|
113
|
+
## 🕹️ 使用方法
|
|
83
114
|
|
|
84
115
|
### 基本流程
|
|
85
116
|
|
|
86
|
-
1.
|
|
87
|
-
2.
|
|
88
|
-
3.
|
|
89
|
-
4.
|
|
90
|
-
5.
|
|
117
|
+
1. 启动与 Claude Code/Codex/Gemini 的对话。
|
|
118
|
+
2. 模型调用工具:例如 `使用 ask_user_question_plus 工具问我 3 个问题`。
|
|
119
|
+
3. 浏览器自动打开问卷界面。
|
|
120
|
+
4. 使用键盘(方向键、Space、Enter)或鼠标回答问题。
|
|
121
|
+
5. 提交后浏览器标签页自动关闭,结果返回给模型。
|
|
91
122
|
|
|
92
123
|
### 键盘快捷键
|
|
93
124
|
|
|
94
|
-
| 快捷键 | 功能
|
|
95
|
-
|
|
|
96
|
-
| `↑` `↓` | 在选项之间移动 /
|
|
97
|
-
| `←` `→` / `Tab` |
|
|
98
|
-
| `Space`
|
|
99
|
-
| `Cmd/Ctrl + Enter` |
|
|
125
|
+
| 快捷键 | 功能 |
|
|
126
|
+
| :----------------- | :------------------------ |
|
|
127
|
+
| `↑` `↓` | 在选项之间移动 / 滚动页面 |
|
|
128
|
+
| `←` `→` / `Tab` | 在不同问题标签页之间切换 |
|
|
129
|
+
| `Space` / `Enter` | 选中/取消选中当前选项 |
|
|
130
|
+
| `Cmd/Ctrl + Enter` | 进入提交 Tab / 提交答案 |
|
|
100
131
|
|
|
101
|
-
## 🔧
|
|
132
|
+
## 🔧 工具定义 (Tools)
|
|
102
133
|
|
|
103
|
-
###
|
|
134
|
+
### `ask_user_question_plus`
|
|
104
135
|
|
|
105
|
-
**输入 Schema
|
|
136
|
+
**输入 Schema (Input):**
|
|
106
137
|
|
|
107
138
|
```typescript
|
|
108
139
|
{
|
|
109
140
|
questions: [
|
|
110
141
|
{
|
|
111
142
|
id: string; // 问题唯一标识
|
|
112
|
-
header: string; //
|
|
113
|
-
text: string; //
|
|
114
|
-
type: "single" | "multiple"; //
|
|
143
|
+
header: string; // 标签标题(推荐 ≤12 字符)
|
|
144
|
+
text: string; // 问题正文
|
|
145
|
+
type: "single" | "multiple"; // 问题类型:单选或多选
|
|
115
146
|
options: [
|
|
116
147
|
{
|
|
117
148
|
value: string; // 选项值
|
|
118
|
-
label: string; //
|
|
149
|
+
label: string; // 选项显示文本
|
|
119
150
|
description?: string; // 选项描述(可选)
|
|
120
|
-
recommended?: boolean;//
|
|
151
|
+
recommended?: boolean;// 是否标记为推荐(可选)
|
|
121
152
|
}
|
|
122
153
|
]
|
|
123
154
|
}
|
|
124
|
-
] //
|
|
155
|
+
] // 限制:1-20 个问题
|
|
125
156
|
}
|
|
126
157
|
```
|
|
127
158
|
|
|
128
|
-
**输出 Schema
|
|
159
|
+
**输出 Schema (Output):**
|
|
129
160
|
|
|
130
161
|
```typescript
|
|
131
162
|
{
|
|
132
|
-
|
|
163
|
+
"answers": {
|
|
164
|
+
"questionId1": {"value" : "", "other":""},
|
|
165
|
+
"questionId2": {"value" : "", "other":""},
|
|
166
|
+
}
|
|
133
167
|
}
|
|
134
168
|
```
|
|
135
169
|
|
|
136
|
-
> **💡
|
|
170
|
+
> **💡 提示**:前端界面会自动为每个问题追加 "Other (自定义输入)" 选项。
|
|
137
171
|
|
|
138
|
-
|
|
172
|
+
## 🛠️ 开发指南
|
|
139
173
|
|
|
140
|
-
|
|
174
|
+
### 克隆项目
|
|
141
175
|
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
"questions": [
|
|
145
|
-
{
|
|
146
|
-
"id": "framework",
|
|
147
|
-
"header": "Framework",
|
|
148
|
-
"text": "选择你的前端框架:",
|
|
149
|
-
"type": "single",
|
|
150
|
-
"options": [
|
|
151
|
-
{
|
|
152
|
-
"value": "react",
|
|
153
|
-
"label": "React",
|
|
154
|
-
"description": "用于构建用户界面的 JavaScript 库",
|
|
155
|
-
"recommended": true
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
"value": "vue",
|
|
159
|
-
"label": "Vue",
|
|
160
|
-
"description": "渐进式 JavaScript 框架"
|
|
161
|
-
}
|
|
162
|
-
]
|
|
163
|
-
}
|
|
164
|
-
]
|
|
165
|
-
}
|
|
176
|
+
```bash
|
|
177
|
+
git clone https://github.com/JoJoJotarou/AskUserQuestionPlus.git && cd AskUserQuestionPlus
|
|
166
178
|
```
|
|
167
179
|
|
|
168
|
-
|
|
180
|
+
### 安装依赖
|
|
169
181
|
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
"questions": [
|
|
173
|
-
{
|
|
174
|
-
"id": "features",
|
|
175
|
-
"header": "Features",
|
|
176
|
-
"text": "你需要哪些功能?(可多选)",
|
|
177
|
-
"type": "multiple",
|
|
178
|
-
"options": [
|
|
179
|
-
{
|
|
180
|
-
"value": "auth",
|
|
181
|
-
"label": "用户认证",
|
|
182
|
-
"description": "登录、注册、密码重置"
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
"value": "api",
|
|
186
|
-
"label": "REST API",
|
|
187
|
-
"description": "RESTful API 端点"
|
|
188
|
-
},
|
|
189
|
-
{
|
|
190
|
-
"value": "db",
|
|
191
|
-
"label": "数据库",
|
|
192
|
-
"description": "PostgreSQL/MySQL 支持"
|
|
193
|
-
}
|
|
194
|
-
]
|
|
195
|
-
}
|
|
196
|
-
]
|
|
197
|
-
}
|
|
182
|
+
```bash
|
|
183
|
+
npm install
|
|
198
184
|
```
|
|
199
185
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
### 运行开发模式
|
|
186
|
+
### 开发模式
|
|
203
187
|
|
|
204
188
|
```bash
|
|
205
189
|
npm run dev
|
|
206
190
|
```
|
|
207
191
|
|
|
208
|
-
###
|
|
192
|
+
### 构建
|
|
209
193
|
|
|
210
194
|
```bash
|
|
211
195
|
npm run build
|
|
196
|
+
# npm start
|
|
212
197
|
```
|
|
213
198
|
|
|
214
199
|
### 目录结构
|
|
@@ -217,48 +202,217 @@ npm run build
|
|
|
217
202
|
ask-user-question-plus/
|
|
218
203
|
├── src/
|
|
219
204
|
│ ├── index.ts # 主入口文件
|
|
220
|
-
│ ├── ws-service.ts # WebSocket
|
|
221
|
-
│ └── mcp-server.ts # MCP
|
|
205
|
+
│ ├── ws-service.ts # WebSocket 服务逻辑
|
|
206
|
+
│ └── mcp-server.ts # MCP 服务器定义
|
|
222
207
|
├── public/
|
|
223
|
-
│ └── index.html #
|
|
224
|
-
├── dist/ #
|
|
225
|
-
└── package.json
|
|
208
|
+
│ └── index.html # 前端 Web 界面
|
|
209
|
+
├── dist/ # 编译输出
|
|
210
|
+
└── package.json
|
|
226
211
|
```
|
|
227
212
|
|
|
228
|
-
|
|
213
|
+
## 🤝 贡献
|
|
214
|
+
|
|
215
|
+
欢迎提交 [Issues](https://github.com/JoJoJotarou/AskUserQuestionPlus/issues) 或 Pull Requests 来改进这个项目。
|
|
229
216
|
|
|
230
|
-
|
|
231
|
-
|
|
217
|
+
## 📄 许可证
|
|
218
|
+
|
|
219
|
+
[MIT License](LICENSE)
|
|
232
220
|
|
|
233
|
-
##
|
|
221
|
+
## 🔗 相关链接
|
|
222
|
+
|
|
223
|
+
- [Model Context Protocol](https://modelcontextprotocol.io/)
|
|
224
|
+
- [Codex Support for streamable HTTP MCP](https://github.com/openai/codex/pull/4317)
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
<a id="english"></a>
|
|
229
|
+
|
|
230
|
+
## ✨ Features
|
|
231
|
+
|
|
232
|
+
- **🎨 Beautiful Interface**: Replicates the Claude Code AskUserQuestions style with support for Dark/Light themes.
|
|
233
|
+
- **⌨️ Full Keyboard Control**: Seamless navigation using Arrow keys, Tab, Space, and Enter.
|
|
234
|
+
- **📊 Rich Interactions**: Supports single choice, multiple choice, recommended options, and custom input ("Other").
|
|
235
|
+
- **🔄 Real-time Communication**: WebSocket-based messaging for instant feedback.
|
|
236
|
+
- **⏱️ Timeout Protection**: Configurable session timeout (Default: 10 minutes).
|
|
237
|
+
- **📈 Scalable**: Supports 1 to 20 questions with unlimited options per question.
|
|
238
|
+
|
|
239
|
+
## 🚀 Deployment
|
|
240
|
+
|
|
241
|
+
### Startup Parameters
|
|
242
|
+
|
|
243
|
+
| Argument | Description | Default | Example |
|
|
244
|
+
| :--------------- | :------------------------------ | :--------------- | :----------------- |
|
|
245
|
+
| `--timeout=<ms>` | Session timeout in milliseconds | 600000 (10 mins) | `--timeout=300000` |
|
|
246
|
+
| `--port=<port>` | Server port | 3456 | `--port=8080` |
|
|
247
|
+
|
|
248
|
+
### Foreground
|
|
234
249
|
|
|
235
250
|
```bash
|
|
236
|
-
|
|
237
|
-
docker-compose up -d
|
|
251
|
+
npx ask-user-question-plus
|
|
238
252
|
|
|
239
|
-
#
|
|
240
|
-
|
|
253
|
+
# Custom port and timeout
|
|
254
|
+
npx ask-user-question-plus -- --port=3456 --timeout=600000
|
|
255
|
+
```
|
|
241
256
|
|
|
242
|
-
|
|
243
|
-
|
|
257
|
+
### Background (Recommended)
|
|
258
|
+
|
|
259
|
+
#### Using pm2
|
|
260
|
+
|
|
261
|
+
> Install pm2 first: `npm install -g pm2`
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
pm2 start "npx ask-user-question-plus" --name ask-user-question-plus-service
|
|
265
|
+
|
|
266
|
+
# With arguments
|
|
267
|
+
pm2 start "npx ask-user-question-plus -- --port=3456 --timeout=600000" --name ask-user-question-plus-service
|
|
268
|
+
|
|
269
|
+
# Stop service
|
|
270
|
+
pm2 stop ask-user-question-plus-service
|
|
244
271
|
```
|
|
245
272
|
|
|
246
|
-
|
|
273
|
+
#### Using Docker
|
|
247
274
|
|
|
248
|
-
|
|
275
|
+
```bash
|
|
276
|
+
docker compose up -d
|
|
277
|
+
```
|
|
249
278
|
|
|
250
|
-
##
|
|
279
|
+
## ⚙️ Configuration
|
|
251
280
|
|
|
252
|
-
|
|
281
|
+
### Claude Code
|
|
253
282
|
|
|
254
|
-
|
|
283
|
+
```bash
|
|
284
|
+
claude mcp add -s user -t http AskUserQuestionPlus http://localhost:3456/mcp
|
|
285
|
+
```
|
|
255
286
|
|
|
256
|
-
|
|
257
|
-
- [npm 包](https://www.npmjs.com/package/ask-user-question-plus)
|
|
258
|
-
- [问题反馈](https://github.com/JoJoJotarou/AskUserQuestionPlus/issues)
|
|
259
|
-
- [Model Context Protocol](https://modelcontextprotocol.io/)
|
|
260
|
-
- [Claude Code](https://github.com/anthropics/claude-code)
|
|
287
|
+
### Codex
|
|
261
288
|
|
|
262
|
-
|
|
289
|
+
Add to `~/.codex/config.toml`:
|
|
290
|
+
|
|
291
|
+
```toml
|
|
292
|
+
experimental_use_rmcp_client = true
|
|
293
|
+
|
|
294
|
+
[mcp_servers.AskUserQuestionPlus]
|
|
295
|
+
url = "http://localhost:3456/mcp/"
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Or via CLI:
|
|
299
|
+
|
|
300
|
+
Add to `~/.codex/config.toml` first:
|
|
301
|
+
|
|
302
|
+
```toml
|
|
303
|
+
experimental_use_rmcp_client = true
|
|
304
|
+
```
|
|
263
305
|
|
|
264
|
-
|
|
306
|
+
```bash
|
|
307
|
+
codex mcp add AskUserQuestionsPlus --url http://localhost:3456/mcp/
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Gemini CLI
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
gemini mcp add AskUserQuestionPlus http://localhost:3456/mcp -s user --transport http
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
> **⚠️ Note**: If you encounter `[Error: Unrecognized key(s) in object: 'type']` ([Issue #15449](https://github.com/google-gemini/gemini-cli/issues/15449)):
|
|
317
|
+
>
|
|
318
|
+
> - Remove the `type` field in `~/.gemini/settings.json`.
|
|
319
|
+
> - Or wait for gemini cli `v0.23.0`.
|
|
320
|
+
|
|
321
|
+
## 🕹️ Usage
|
|
322
|
+
|
|
323
|
+
### Basic Workflow
|
|
324
|
+
|
|
325
|
+
1. Start a conversation with Claude, Codex, or Gemini.
|
|
326
|
+
2. Ask the model to use the tool: e.g., "Use ask_user_question_plus to ask me 3 questions."
|
|
327
|
+
3. A browser tab will automatically open with the questionnaire.
|
|
328
|
+
4. Answer using your keyboard (Arrows, Space, Enter) or mouse.
|
|
329
|
+
5. Upon submission, the tab closes, and answers are sent back to the model.
|
|
330
|
+
|
|
331
|
+
### Keyboard Shortcuts
|
|
332
|
+
|
|
333
|
+
| Shortcut | Function |
|
|
334
|
+
| :----------------- | :---------------------------- |
|
|
335
|
+
| `↑` `↓` | Move between options / Scroll |
|
|
336
|
+
| `←` `→` / `Tab` | Switch between question tabs |
|
|
337
|
+
| `Space` / `Enter` | Select/Deselect option |
|
|
338
|
+
| `Cmd/Ctrl + Enter` | Submit Tab / Submit answers |
|
|
339
|
+
|
|
340
|
+
## 🔧 Tools Definition
|
|
341
|
+
|
|
342
|
+
### `ask_user_question_plus`
|
|
343
|
+
|
|
344
|
+
**Input Schema:**
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
{
|
|
348
|
+
questions: [
|
|
349
|
+
{
|
|
350
|
+
id: string; // Unique identifier
|
|
351
|
+
header: string; // Tab header (Rec. ≤12 chars)
|
|
352
|
+
text: string; // Question text
|
|
353
|
+
type: "single" | "multiple"; // Question type
|
|
354
|
+
options: [
|
|
355
|
+
{
|
|
356
|
+
value: string; // Option value
|
|
357
|
+
label: string; // Option label
|
|
358
|
+
description?: string; // Option description (optional)
|
|
359
|
+
recommended?: boolean;// Recommended flag (optional)
|
|
360
|
+
}
|
|
361
|
+
]
|
|
362
|
+
}
|
|
363
|
+
] // Limit: 1-20 questions
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
**Output Schema:**
|
|
368
|
+
|
|
369
|
+
```json
|
|
370
|
+
{
|
|
371
|
+
"answers": {
|
|
372
|
+
"questionId1": { "value": "", "other": "" },
|
|
373
|
+
"questionId2": { "value": "", "other": "" }
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
> **💡 Tip**: The "Other" (custom input) option is automatically added by the frontend.
|
|
379
|
+
|
|
380
|
+
## 🛠️ Development
|
|
381
|
+
|
|
382
|
+
### Clone
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
git clone https://github.com/JoJoJotarou/AskUserQuestionPlus.git && cd AskUserQuestionPlus
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Install Dependencies
|
|
389
|
+
|
|
390
|
+
```bash
|
|
391
|
+
npm install
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Run Dev Mode
|
|
395
|
+
|
|
396
|
+
```bash
|
|
397
|
+
npm run dev
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Build
|
|
401
|
+
|
|
402
|
+
```bash
|
|
403
|
+
npm run build
|
|
404
|
+
# npm start
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## 🤝 Contribution
|
|
408
|
+
|
|
409
|
+
Contributions are welcome! Please submit [Issues](https://github.com/JoJoJotarou/AskUserQuestionPlus/issues) or Pull Requests.
|
|
410
|
+
|
|
411
|
+
## 📄 License
|
|
412
|
+
|
|
413
|
+
[MIT License](LICENSE)
|
|
414
|
+
|
|
415
|
+
## 🔗 Related Links
|
|
416
|
+
|
|
417
|
+
- [Model Context Protocol](https://modelcontextprotocol.io/)
|
|
418
|
+
- [Codex Support for streamable HTTP MCP](https://github.com/openai/codex/pull/4317)
|
package/dist/mcp-server.js
CHANGED
|
@@ -22,37 +22,37 @@ export class MCPServerService {
|
|
|
22
22
|
}
|
|
23
23
|
registerTools(server) {
|
|
24
24
|
server.registerTool("ask_user_question_plus", {
|
|
25
|
-
description: "
|
|
25
|
+
description: "An MCP-based user interaction tool for asking structured questions and collecting feedback. It supports single-choice and multiple-choice questions, marking recommended options, and flexible numbers of questions and options. An 'Other' (custom input) option is automatically added to each question, making it suitable for complex configuration and decision-making workflows.",
|
|
26
26
|
inputSchema: {
|
|
27
27
|
questions: z
|
|
28
28
|
.array(z.object({
|
|
29
|
-
id: z.string().describe("
|
|
29
|
+
id: z.string().describe("Unique identifier for the question"),
|
|
30
30
|
header: z
|
|
31
31
|
.string()
|
|
32
32
|
.max(12)
|
|
33
|
-
.describe("
|
|
34
|
-
text: z.string().describe("
|
|
33
|
+
.describe("Short header for the question tab (max 12 chars)"),
|
|
34
|
+
text: z.string().describe("Main text of the question"),
|
|
35
35
|
type: z
|
|
36
36
|
.enum(["single", "multiple"])
|
|
37
|
-
.describe("
|
|
37
|
+
.describe("Question type: 'single' or 'multiple'"),
|
|
38
38
|
options: z
|
|
39
39
|
.array(z.object({
|
|
40
|
-
value: z.string().describe("
|
|
41
|
-
label: z.string().describe("
|
|
40
|
+
value: z.string().describe("Technical value of the option"),
|
|
41
|
+
label: z.string().describe("Display label for the option"),
|
|
42
42
|
description: z
|
|
43
43
|
.string()
|
|
44
44
|
.optional()
|
|
45
|
-
.describe("
|
|
45
|
+
.describe("Additional description for the option"),
|
|
46
46
|
recommended: z
|
|
47
47
|
.boolean()
|
|
48
48
|
.optional()
|
|
49
|
-
.describe("
|
|
49
|
+
.describe("Whether this is a recommended option"),
|
|
50
50
|
}))
|
|
51
|
-
.describe("
|
|
51
|
+
.describe("List of options. Note: An 'Other' option is automatically added for custom user input."),
|
|
52
52
|
}))
|
|
53
53
|
.min(1)
|
|
54
54
|
.max(20)
|
|
55
|
-
.describe("
|
|
55
|
+
.describe("List of questions (up to 20 items)"),
|
|
56
56
|
},
|
|
57
57
|
}, async ({ questions }) => {
|
|
58
58
|
console.error("[MCP] Tool invoked: ask_user_question_plus");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ask-user-question-plus",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "A TUI-style MCP server for asking user questions via a web interface.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"build": "tsc",
|
|
12
12
|
"start": "node dist/index.js",
|
|
13
13
|
"dev": "tsx src/index.ts",
|
|
14
|
+
"test": "echo 'No tests yet' && exit 0",
|
|
14
15
|
"prepublishOnly": "npm run build"
|
|
15
16
|
},
|
|
16
17
|
"keywords": [
|
package/public/index.html
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html lang="
|
|
2
|
+
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
@@ -545,7 +545,7 @@
|
|
|
545
545
|
|
|
546
546
|
<!-- GitHub Star -->
|
|
547
547
|
<a
|
|
548
|
-
href="https://github.com/
|
|
548
|
+
href="https://github.com/JoJoJotarou/AskUserQuestionPlus"
|
|
549
549
|
target="_blank"
|
|
550
550
|
class="icon-btn"
|
|
551
551
|
title="Star on GitHub"
|
|
@@ -575,10 +575,10 @@
|
|
|
575
575
|
<div class="footer">
|
|
576
576
|
<div class="key-hints">
|
|
577
577
|
<div class="key-hint-item">
|
|
578
|
-
<span class="key-tag">↑↓</span>
|
|
578
|
+
<span class="key-tag">↑↓</span> Select/Scroll
|
|
579
579
|
</div>
|
|
580
580
|
<div class="key-hint-item">
|
|
581
|
-
<span class="key-tag">← →/Tab</span>
|
|
581
|
+
<span class="key-tag">← →/Tab</span> Switch
|
|
582
582
|
</div>
|
|
583
583
|
<div class="key-hint-item">
|
|
584
584
|
<span class="key-tag">Enter/Space</span>
|
|
@@ -586,7 +586,7 @@
|
|
|
586
586
|
</div>
|
|
587
587
|
</div>
|
|
588
588
|
<button class="submit-btn" id="submit-all" disabled>
|
|
589
|
-
|
|
589
|
+
Review & Submit
|
|
590
590
|
<span class="submit-shortcut" id="submit-shortcut-text">⌘+Enter</span>
|
|
591
591
|
</button>
|
|
592
592
|
</div>
|
|
@@ -799,7 +799,7 @@
|
|
|
799
799
|
${opt.label}
|
|
800
800
|
${
|
|
801
801
|
opt.recommended
|
|
802
|
-
? '<span class="recommended-tag"
|
|
802
|
+
? '<span class="recommended-tag">(Recommended)</span>'
|
|
803
803
|
: ""
|
|
804
804
|
}
|
|
805
805
|
</div>
|
|
@@ -833,7 +833,7 @@
|
|
|
833
833
|
<div class="question-header">
|
|
834
834
|
<span class="q-text">${q.text}${
|
|
835
835
|
q.type === "multiple"
|
|
836
|
-
? ' <span style="color:var(--dim-color); font-size:0.8em"
|
|
836
|
+
? ' <span style="color:var(--dim-color); font-size:0.8em">(Multi-select)</span>'
|
|
837
837
|
: ""
|
|
838
838
|
}</span>
|
|
839
839
|
</div>
|
|
@@ -875,7 +875,7 @@
|
|
|
875
875
|
|
|
876
876
|
if (q.type === "single") {
|
|
877
877
|
if (!ans.value) {
|
|
878
|
-
error = "
|
|
878
|
+
error = "No answer selected";
|
|
879
879
|
} else {
|
|
880
880
|
const opt = [
|
|
881
881
|
...q.options,
|
|
@@ -885,7 +885,7 @@
|
|
|
885
885
|
displayValue = opt.label;
|
|
886
886
|
if (opt.isOther) {
|
|
887
887
|
if (!ans.otherText.trim()) {
|
|
888
|
-
error = "
|
|
888
|
+
error = "Please provide custom input";
|
|
889
889
|
displayValue += ": [Empty]";
|
|
890
890
|
} else {
|
|
891
891
|
displayValue += `: ${ans.otherText}`;
|
|
@@ -895,7 +895,7 @@
|
|
|
895
895
|
}
|
|
896
896
|
} else {
|
|
897
897
|
if (!ans.values || ans.values.length === 0) {
|
|
898
|
-
error = "
|
|
898
|
+
error = "Please select at least one option";
|
|
899
899
|
} else {
|
|
900
900
|
displayValue = ans.values
|
|
901
901
|
.map((v) => {
|
|
@@ -907,7 +907,7 @@
|
|
|
907
907
|
let label = opt.label;
|
|
908
908
|
if (opt.isOther) {
|
|
909
909
|
if (!ans.otherText.trim()) {
|
|
910
|
-
error = "
|
|
910
|
+
error = "Please provide custom input";
|
|
911
911
|
label += ": [Empty]";
|
|
912
912
|
} else {
|
|
913
913
|
label += `: ${ans.otherText}`;
|
|
@@ -939,7 +939,7 @@
|
|
|
939
939
|
container.innerHTML = `
|
|
940
940
|
<div class="question-block">
|
|
941
941
|
<div class="question-header">
|
|
942
|
-
<span class="q-text"
|
|
942
|
+
<span class="q-text">Please review your answers before submitting!</span>
|
|
943
943
|
</div>
|
|
944
944
|
${summaryHtml}
|
|
945
945
|
</div>
|
|
@@ -961,13 +961,13 @@
|
|
|
961
961
|
const shortcutText = isMac ? "⌘+Enter" : "Ctrl+Enter";
|
|
962
962
|
|
|
963
963
|
if (isReview) {
|
|
964
|
-
submitBtn.innerHTML = `
|
|
964
|
+
submitBtn.innerHTML = `Submit Answers <span class="submit-shortcut" id="submit-shortcut-text">${shortcutText}</span>`;
|
|
965
965
|
submitBtn.disabled = !isValid;
|
|
966
|
-
if (spaceHint) spaceHint.textContent = "
|
|
966
|
+
if (spaceHint) spaceHint.textContent = "Jump";
|
|
967
967
|
} else {
|
|
968
|
-
submitBtn.innerHTML = `
|
|
968
|
+
submitBtn.innerHTML = `Review & Submit <span class="submit-shortcut" id="submit-shortcut-text">${shortcutText}</span>`;
|
|
969
969
|
submitBtn.disabled = QUESTIONS_DATA.length === 0;
|
|
970
|
-
if (spaceHint) spaceHint.textContent = "
|
|
970
|
+
if (spaceHint) spaceHint.textContent = "Select";
|
|
971
971
|
}
|
|
972
972
|
}
|
|
973
973
|
|
|
@@ -1091,7 +1091,7 @@
|
|
|
1091
1091
|
submitBtn.disabled = true;
|
|
1092
1092
|
|
|
1093
1093
|
setTimeout(() => {
|
|
1094
|
-
alert("
|
|
1094
|
+
alert("Submitted successfully! Closing...");
|
|
1095
1095
|
submitBtn.textContent = "DONE";
|
|
1096
1096
|
window.close();
|
|
1097
1097
|
document.body.innerHTML =
|