@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.
Files changed (3) hide show
  1. package/README.md +10 -1
  2. package/dist/server.js +136 -4
  3. 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.14
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";
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 === "claude"
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.21",
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.21",
30
- "@longtable/cli": "0.1.21",
31
- "@longtable/core": "0.1.21",
32
- "@longtable/provider-claude": "0.1.21",
33
- "@longtable/provider-codex": "0.1.21",
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
  },