@longtable/mcp 0.1.21 → 0.1.23
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 +10 -1
- package/dist/server.js +136 -4
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ longtable-state
|
|
|
14
14
|
Run:
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
npx -y @longtable/mcp@0.1.
|
|
17
|
+
npx -y @longtable/mcp@0.1.22
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
Self-test:
|
|
@@ -22,3 +22,12 @@ Self-test:
|
|
|
22
22
|
```bash
|
|
23
23
|
longtable-state --self-test
|
|
24
24
|
```
|
|
25
|
+
|
|
26
|
+
Codex UI Researcher Checkpoints are opt-in from the CLI:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
longtable mcp install --provider codex --checkpoint-ui strong --write
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
If MCP elicitation is unavailable or not approved, the server returns the same
|
|
33
|
+
pending `QuestionRecord` as a numbered fallback.
|
package/dist/server.js
CHANGED
|
@@ -11,7 +11,7 @@ import { renderQuestionRecordInput } from "@longtable/provider-claude";
|
|
|
11
11
|
import { renderQuestionRecordPrompt } from "@longtable/provider-codex";
|
|
12
12
|
import { answerWorkspaceQuestion, createWorkspaceQuestion, inspectProjectWorkspace, loadProjectContextFromDirectory, loadWorkspaceState, syncCurrentWorkspaceView } from "@longtable/cli";
|
|
13
13
|
const SERVER_NAME = "longtable-state";
|
|
14
|
-
const SERVER_VERSION = "0.1.
|
|
14
|
+
const SERVER_VERSION = "0.1.22";
|
|
15
15
|
const TOOL_NAMES = [
|
|
16
16
|
"read_project",
|
|
17
17
|
"read_session",
|
|
@@ -19,6 +19,7 @@ const TOOL_NAMES = [
|
|
|
19
19
|
"pending_questions",
|
|
20
20
|
"evaluate_checkpoint",
|
|
21
21
|
"create_question",
|
|
22
|
+
"elicit_question",
|
|
22
23
|
"render_question",
|
|
23
24
|
"append_decision",
|
|
24
25
|
"regenerate_current"
|
|
@@ -64,6 +65,67 @@ function findQuestion(records, questionId) {
|
|
|
64
65
|
}
|
|
65
66
|
return records.filter((record) => record.status === "pending").at(-1) ?? null;
|
|
66
67
|
}
|
|
68
|
+
function renderQuestionFallback(record, provider = "codex") {
|
|
69
|
+
return provider === "claude"
|
|
70
|
+
? renderQuestionRecordInput(record)
|
|
71
|
+
: renderQuestionRecordPrompt(record);
|
|
72
|
+
}
|
|
73
|
+
function buildElicitationParams(record) {
|
|
74
|
+
const choices = [
|
|
75
|
+
...record.prompt.options.map((option) => ({
|
|
76
|
+
const: option.value,
|
|
77
|
+
title: [
|
|
78
|
+
option.label,
|
|
79
|
+
option.recommended ? "(Recommended)" : ""
|
|
80
|
+
].filter(Boolean).join(" ")
|
|
81
|
+
})),
|
|
82
|
+
...(record.prompt.allowOther
|
|
83
|
+
? [{
|
|
84
|
+
const: "other",
|
|
85
|
+
title: record.prompt.otherLabel ?? "Other"
|
|
86
|
+
}]
|
|
87
|
+
: [])
|
|
88
|
+
];
|
|
89
|
+
return {
|
|
90
|
+
mode: "form",
|
|
91
|
+
message: [
|
|
92
|
+
record.prompt.title,
|
|
93
|
+
record.prompt.question,
|
|
94
|
+
...record.prompt.rationale.slice(0, 2).map((entry) => `Why now: ${entry}`)
|
|
95
|
+
].join("\n"),
|
|
96
|
+
requestedSchema: {
|
|
97
|
+
type: "object",
|
|
98
|
+
properties: {
|
|
99
|
+
answer: {
|
|
100
|
+
type: "string",
|
|
101
|
+
title: "Decision",
|
|
102
|
+
oneOf: choices,
|
|
103
|
+
default: choices[0]?.const
|
|
104
|
+
},
|
|
105
|
+
rationale: {
|
|
106
|
+
type: "string",
|
|
107
|
+
title: "Rationale",
|
|
108
|
+
description: "Optional short note for the LongTable decision log."
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
required: ["answer"]
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function acceptedAnswer(result) {
|
|
116
|
+
if (result.action !== "accept") {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
const answer = result.content?.answer;
|
|
120
|
+
if (typeof answer !== "string" || answer.length === 0) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const rationale = result.content?.rationale;
|
|
124
|
+
return {
|
|
125
|
+
answer,
|
|
126
|
+
...(typeof rationale === "string" && rationale.length > 0 ? { rationale } : {})
|
|
127
|
+
};
|
|
128
|
+
}
|
|
67
129
|
async function readAllowedProjectFiles(context) {
|
|
68
130
|
const current = existsSync(context.currentFilePath)
|
|
69
131
|
? await readFile(context.currentFilePath, "utf8")
|
|
@@ -216,6 +278,78 @@ export function createLongTableMcpServer() {
|
|
|
216
278
|
return errorResult(error instanceof Error ? error.message : String(error));
|
|
217
279
|
}
|
|
218
280
|
});
|
|
281
|
+
server.registerTool("elicit_question", {
|
|
282
|
+
title: "Elicit Researcher Checkpoint",
|
|
283
|
+
description: "Create a QuestionRecord, then try MCP form elicitation for a provider-native UI checkpoint. Falls back to rendered LongTable transport when unsupported.",
|
|
284
|
+
inputSchema: cwdSchema.extend({
|
|
285
|
+
prompt: z.string().min(1),
|
|
286
|
+
title: z.string().optional(),
|
|
287
|
+
question: z.string().optional(),
|
|
288
|
+
provider: z.enum(["codex", "claude"]).default("codex"),
|
|
289
|
+
required: z.boolean().optional(),
|
|
290
|
+
fallbackOnly: z.boolean().default(false).describe("Create and render the checkpoint without calling MCP elicitation.")
|
|
291
|
+
})
|
|
292
|
+
}, async ({ cwd: inputCwd, prompt, title, question, provider, required, fallbackOnly }) => {
|
|
293
|
+
try {
|
|
294
|
+
const context = await requireContext(inputCwd);
|
|
295
|
+
const created = await createWorkspaceQuestion({
|
|
296
|
+
context,
|
|
297
|
+
prompt,
|
|
298
|
+
title,
|
|
299
|
+
question,
|
|
300
|
+
provider,
|
|
301
|
+
required
|
|
302
|
+
});
|
|
303
|
+
const fallback = renderQuestionFallback(created.question, provider);
|
|
304
|
+
if (fallbackOnly) {
|
|
305
|
+
return textResult({
|
|
306
|
+
question: created.question,
|
|
307
|
+
elicitation: { attempted: false, reason: "fallbackOnly" },
|
|
308
|
+
fallback,
|
|
309
|
+
nextAction: `longtable decide --question ${created.question.id} --answer <value>`
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
try {
|
|
313
|
+
const elicited = await server.server.elicitInput(buildElicitationParams(created.question));
|
|
314
|
+
const accepted = acceptedAnswer(elicited);
|
|
315
|
+
if (!accepted) {
|
|
316
|
+
return textResult({
|
|
317
|
+
question: created.question,
|
|
318
|
+
elicitation: { attempted: true, action: elicited.action },
|
|
319
|
+
fallback,
|
|
320
|
+
nextAction: `longtable decide --question ${created.question.id} --answer <value>`
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
const decided = await answerWorkspaceQuestion({
|
|
324
|
+
context,
|
|
325
|
+
questionId: created.question.id,
|
|
326
|
+
answer: accepted.answer,
|
|
327
|
+
rationale: accepted.rationale,
|
|
328
|
+
provider: provider
|
|
329
|
+
});
|
|
330
|
+
return textResult({
|
|
331
|
+
question: decided.question,
|
|
332
|
+
decision: decided.decision,
|
|
333
|
+
elicitation: { attempted: true, action: elicited.action }
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
catch (elicitationError) {
|
|
337
|
+
return textResult({
|
|
338
|
+
question: created.question,
|
|
339
|
+
elicitation: {
|
|
340
|
+
attempted: true,
|
|
341
|
+
supported: false,
|
|
342
|
+
error: elicitationError instanceof Error ? elicitationError.message : String(elicitationError)
|
|
343
|
+
},
|
|
344
|
+
fallback,
|
|
345
|
+
nextAction: `longtable decide --question ${created.question.id} --answer <value>`
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
catch (error) {
|
|
350
|
+
return errorResult(error instanceof Error ? error.message : String(error));
|
|
351
|
+
}
|
|
352
|
+
});
|
|
219
353
|
server.registerTool("render_question", {
|
|
220
354
|
title: "Render Researcher Checkpoint",
|
|
221
355
|
description: "Render a pending QuestionRecord for Codex numbered prompt or Claude structured question transport.",
|
|
@@ -232,9 +366,7 @@ export function createLongTableMcpServer() {
|
|
|
232
366
|
if (!question) {
|
|
233
367
|
return errorResult("No matching pending LongTable question was found.");
|
|
234
368
|
}
|
|
235
|
-
const transport = provider
|
|
236
|
-
? renderQuestionRecordInput(question)
|
|
237
|
-
: renderQuestionRecordPrompt(question);
|
|
369
|
+
const transport = renderQuestionFallback(question, provider);
|
|
238
370
|
return textResult({ provider, question, transport });
|
|
239
371
|
}
|
|
240
372
|
catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@longtable/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.23",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "LongTable MCP transport for workspace state and Researcher Checkpoints",
|
|
6
6
|
"type": "module",
|
|
@@ -26,11 +26,11 @@
|
|
|
26
26
|
"self-test": "node ./dist/server.js --self-test"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@longtable/checkpoints": "0.1.
|
|
30
|
-
"@longtable/cli": "0.1.
|
|
31
|
-
"@longtable/core": "0.1.
|
|
32
|
-
"@longtable/provider-claude": "0.1.
|
|
33
|
-
"@longtable/provider-codex": "0.1.
|
|
29
|
+
"@longtable/checkpoints": "0.1.23",
|
|
30
|
+
"@longtable/cli": "0.1.23",
|
|
31
|
+
"@longtable/core": "0.1.23",
|
|
32
|
+
"@longtable/provider-claude": "0.1.23",
|
|
33
|
+
"@longtable/provider-codex": "0.1.23",
|
|
34
34
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
35
35
|
"zod": "^4.0.0"
|
|
36
36
|
},
|